Skip to content

Commit f518ce8

Browse files
committed
Do not apply #[do_not_recommend] if the feature flag is not set
This commit adds additional checks for the feature flag as apparently it is possible to use this on a beta compiler without feature flags. To track whether a diagnostic attribute is allowed based of the feature in certain possibly upstream crate we introduce a new boolean flag stored in each attribute. This hopefully enables future diagnostic attributes to prevent this situation, as there is now a single place that can be checked whether the attribute should be honored or not. This0PR might be a candidate for backporting to the latest beta release. Reported in the bevy issue tracker: bevyengine/bevy#14591 (comment)
1 parent 97e7252 commit f518ce8

File tree

12 files changed

+102
-16
lines changed

12 files changed

+102
-16
lines changed

compiler/rustc_ast/src/ast.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2855,6 +2855,7 @@ pub struct Attribute {
28552855
/// or the construct this attribute is contained within (inner).
28562856
pub style: AttrStyle,
28572857
pub span: Span,
2858+
pub allowed_diagnostic_attribute: bool,
28582859
}
28592860

28602861
#[derive(Clone, Encodable, Decodable, Debug)]

compiler/rustc_ast/src/attr/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,13 @@ pub fn mk_doc_comment(
566566
data: Symbol,
567567
span: Span,
568568
) -> Attribute {
569-
Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
569+
Attribute {
570+
kind: AttrKind::DocComment(comment_kind, data),
571+
id: g.mk_attr_id(),
572+
style,
573+
span,
574+
allowed_diagnostic_attribute: false,
575+
}
570576
}
571577

572578
pub fn mk_attr(
@@ -592,6 +598,7 @@ pub fn mk_attr_from_item(
592598
id: g.mk_attr_id(),
593599
style,
594600
span,
601+
allowed_diagnostic_attribute: false,
595602
}
596603
}
597604

compiler/rustc_ast/src/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ fn walk_local<T: MutVisitor>(vis: &mut T, local: &mut P<Local>) {
631631
}
632632

633633
fn walk_attribute<T: MutVisitor>(vis: &mut T, attr: &mut Attribute) {
634-
let Attribute { kind, id: _, style: _, span } = attr;
634+
let Attribute { kind, id: _, style: _, span, allowed_diagnostic_attribute: _ } = attr;
635635
match kind {
636636
AttrKind::Normal(normal) => {
637637
let NormalAttr {

compiler/rustc_ast/src/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1214,7 +1214,7 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) -> V::
12141214
}
12151215

12161216
pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) -> V::Result {
1217-
let Attribute { kind, id: _, style: _, span: _ } = attr;
1217+
let Attribute { kind, id: _, style: _, span: _, allowed_diagnostic_attribute: _ } = attr;
12181218
match kind {
12191219
AttrKind::Normal(normal) => {
12201220
let NormalAttr { item, tokens: _ } = &**normal;

compiler/rustc_ast_lowering/src/expr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
733733
id: self.tcx.sess.psess.attr_id_generator.mk_attr_id(),
734734
style: AttrStyle::Outer,
735735
span: unstable_span,
736+
allowed_diagnostic_attribute: false,
736737
}],
737738
);
738739
}

compiler/rustc_ast_lowering/src/lib.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -945,7 +945,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
945945
AttrKind::DocComment(comment_kind, data) => AttrKind::DocComment(comment_kind, data),
946946
};
947947

948-
Attribute { kind, id: attr.id, style: attr.style, span: self.lower_span(attr.span) }
948+
Attribute {
949+
kind,
950+
id: attr.id,
951+
style: attr.style,
952+
span: self.lower_span(attr.span),
953+
allowed_diagnostic_attribute: attr.allowed_diagnostic_attribute,
954+
}
949955
}
950956

951957
fn alias_attrs(&mut self, id: HirId, target_id: HirId) {

compiler/rustc_ast_passes/src/ast_validation.rs

+30
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use std::mem;
2020
use std::ops::{Deref, DerefMut};
2121

2222
use itertools::{Either, Itertools};
23+
use mut_visit::MutVisitor;
2324
use rustc_ast::ptr::P;
2425
use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
2526
use rustc_ast::*;
@@ -1781,3 +1782,32 @@ pub fn check_crate(
17811782

17821783
validator.has_proc_macro_decls
17831784
}
1785+
1786+
struct MarkDiagnosticAttributesAsUnstable<'a> {
1787+
features: &'a Features,
1788+
}
1789+
1790+
impl<'a> MutVisitor for MarkDiagnosticAttributesAsUnstable<'a> {
1791+
fn visit_attribute(&mut self, at: &mut Attribute) {
1792+
if at.is_doc_comment() {
1793+
return;
1794+
}
1795+
let diagnostic_item = match at.path().as_slice() {
1796+
[sym::diagnostic, item] => *item,
1797+
_ => return,
1798+
};
1799+
match diagnostic_item {
1800+
sym::on_unimplemented => at.allowed_diagnostic_attribute = true,
1801+
sym::do_not_recommend => {
1802+
at.allowed_diagnostic_attribute = self.features.do_not_recommend
1803+
}
1804+
_ => {}
1805+
}
1806+
}
1807+
}
1808+
1809+
pub fn apply_diagnostic_attribute_stablilty(features: &Features, krate: &mut Crate) {
1810+
let mut visitor = MarkDiagnosticAttributesAsUnstable { features };
1811+
1812+
mut_visit::walk_crate(&mut visitor, krate);
1813+
}

compiler/rustc_interface/src/passes.rs

+2
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ fn configure_and_expand(
237237
rustc_builtin_macros::test_harness::inject(&mut krate, sess, features, resolver)
238238
});
239239

240+
rustc_ast_passes::ast_validation::apply_diagnostic_attribute_stablilty(features, &mut krate);
241+
240242
let has_proc_macro_decls = sess.time("AST_validation", || {
241243
rustc_ast_passes::ast_validation::check_crate(
242244
sess,

compiler/rustc_query_system/src/ich/impls_syntax.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> {
4141
debug_assert!(!attr.ident().is_some_and(|ident| self.is_ignored_attr(ident.name)));
4242
debug_assert!(!attr.is_doc_comment());
4343

44-
let ast::Attribute { kind, id: _, style, span } = attr;
44+
let ast::Attribute { kind, id: _, style, span, allowed_diagnostic_attribute: _ } = attr;
4545
if let ast::AttrKind::Normal(normal) = kind {
4646
normal.item.hash_stable(self, hasher);
4747
style.hash_stable(self, hasher);

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -1630,11 +1630,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
16301630
.tcx
16311631
.all_impls(def_id)
16321632
// ignore `do_not_recommend` items
1633-
.filter(|def_id| {
1634-
!self
1635-
.tcx
1636-
.has_attrs_with_path(*def_id, &[sym::diagnostic, sym::do_not_recommend])
1637-
})
1633+
.filter(|def_id| self.do_not_recommend_filter(*def_id))
16381634
// Ignore automatically derived impls and `!Trait` impls.
16391635
.filter_map(|def_id| self.tcx.impl_trait_header(def_id))
16401636
.filter_map(|header| {
@@ -1904,12 +1900,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19041900
let impl_candidates = impl_candidates
19051901
.into_iter()
19061902
.cloned()
1907-
.filter(|cand| {
1908-
!self.tcx.has_attrs_with_path(
1909-
cand.impl_def_id,
1910-
&[sym::diagnostic, sym::do_not_recommend],
1911-
)
1912-
})
1903+
.filter(|cand| self.do_not_recommend_filter(cand.impl_def_id))
19131904
.collect::<Vec<_>>();
19141905

19151906
let def_id = trait_ref.def_id();
@@ -1953,6 +1944,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19531944
report(impl_candidates, err)
19541945
}
19551946

1947+
fn do_not_recommend_filter(&self, def_id: DefId) -> bool {
1948+
let do_not_recommend =
1949+
self.tcx.get_attrs_by_path(def_id, &[sym::diagnostic, sym::do_not_recommend]).next();
1950+
!matches!(do_not_recommend, Some(a) if a.allowed_diagnostic_attribute)
1951+
}
1952+
19561953
fn report_similar_impl_candidates_for_root_obligation(
19571954
&self,
19581955
obligation: &PredicateObligation<'tcx>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![allow(unknown_or_malformed_diagnostic_attributes)]
2+
3+
trait Foo {}
4+
5+
#[diagnostic::do_not_recommend]
6+
impl<A> Foo for (A,) {}
7+
8+
#[diagnostic::do_not_recommend]
9+
impl<A, B> Foo for (A, B) {}
10+
11+
#[diagnostic::do_not_recommend]
12+
impl<A, B, C> Foo for (A, B, C) {}
13+
14+
impl Foo for i32 {}
15+
16+
fn check(a: impl Foo) {}
17+
18+
fn main() {
19+
check(());
20+
//~^ ERROR the trait bound `(): Foo` is not satisfied
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0277]: the trait bound `(): Foo` is not satisfied
2+
--> $DIR/do_not_apply_attribute_without_feature_flag.rs:19:11
3+
|
4+
LL | check(());
5+
| ----- ^^ the trait `Foo` is not implemented for `()`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
= help: the following other types implement trait `Foo`:
10+
(A, B)
11+
(A, B, C)
12+
(A,)
13+
note: required by a bound in `check`
14+
--> $DIR/do_not_apply_attribute_without_feature_flag.rs:16:18
15+
|
16+
LL | fn check(a: impl Foo) {}
17+
| ^^^ required by this bound in `check`
18+
19+
error: aborting due to 1 previous error
20+
21+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)