Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit bf63acf

Browse files
authoredJun 22, 2025
Rollup merge of #142776 - dtolnay:hirattrstyle2, r=jdonszelmann
All HIR attributes are outer Fixes #142649. Closes #142759. All HIR attributes, including parsed and not yet parsed, will now be rendered as outer attributes by `rustc_hir_pretty`. The original style of the corresponding AST attribute(s) is not relevant for pretty printing, only for diagnostics. r? ````@jdonszelmann````
2 parents b5b106a + 6729b66 commit bf63acf

File tree

15 files changed

+197
-167
lines changed

15 files changed

+197
-167
lines changed
 

‎compiler/rustc_ast/src/attr/mod.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,24 @@ impl AttributeExt for Attribute {
206206
}
207207
}
208208

209-
fn style(&self) -> AttrStyle {
210-
self.style
209+
fn doc_resolution_scope(&self) -> Option<AttrStyle> {
210+
match &self.kind {
211+
AttrKind::DocComment(..) => Some(self.style),
212+
AttrKind::Normal(normal)
213+
if normal.item.path == sym::doc && normal.item.value_str().is_some() =>
214+
{
215+
Some(self.style)
216+
}
217+
_ => None,
218+
}
211219
}
212220
}
213221

214222
impl Attribute {
223+
pub fn style(&self) -> AttrStyle {
224+
self.style
225+
}
226+
215227
pub fn may_have_doc_links(&self) -> bool {
216228
self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
217229
}
@@ -806,7 +818,14 @@ pub trait AttributeExt: Debug {
806818
/// * `#[doc(...)]` returns `None`.
807819
fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)>;
808820

809-
fn style(&self) -> AttrStyle;
821+
/// Returns outer or inner if this is a doc attribute or a sugared doc
822+
/// comment, otherwise None.
823+
///
824+
/// This is used in the case of doc comments on modules, to decide whether
825+
/// to resolve intra-doc links against the symbols in scope within the
826+
/// commented module (for inner doc) vs within its parent module (for outer
827+
/// doc).
828+
fn doc_resolution_scope(&self) -> Option<AttrStyle>;
810829
}
811830

812831
// FIXME(fn_delegation): use function delegation instead of manually forwarding
@@ -881,8 +900,4 @@ impl Attribute {
881900
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
882901
AttributeExt::doc_str_and_comment_kind(self)
883902
}
884-
885-
pub fn style(&self) -> AttrStyle {
886-
AttributeExt::style(self)
887-
}
888903
}

‎compiler/rustc_hir/src/hir.rs

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,12 +1346,13 @@ impl AttributeExt for Attribute {
13461346
}
13471347
}
13481348

1349-
#[inline]
1350-
fn style(&self) -> AttrStyle {
1351-
match &self {
1352-
Attribute::Unparsed(u) => u.style,
1353-
Attribute::Parsed(AttributeKind::DocComment { style, .. }) => *style,
1354-
_ => panic!(),
1349+
fn doc_resolution_scope(&self) -> Option<AttrStyle> {
1350+
match self {
1351+
Attribute::Parsed(AttributeKind::DocComment { style, .. }) => Some(*style),
1352+
Attribute::Unparsed(attr) if self.has_name(sym::doc) && self.value_str().is_some() => {
1353+
Some(attr.style)
1354+
}
1355+
_ => None,
13551356
}
13561357
}
13571358
}
@@ -1442,11 +1443,6 @@ impl Attribute {
14421443
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
14431444
AttributeExt::doc_str_and_comment_kind(self)
14441445
}
1445-
1446-
#[inline]
1447-
pub fn style(&self) -> AttrStyle {
1448-
AttributeExt::style(self)
1449-
}
14501446
}
14511447

14521448
/// Attributes owned by a HIR owner.
@@ -2286,16 +2282,9 @@ pub struct Expr<'hir> {
22862282
}
22872283

22882284
impl Expr<'_> {
2289-
pub fn precedence(
2290-
&self,
2291-
for_each_attr: &dyn Fn(HirId, &mut dyn FnMut(&Attribute)),
2292-
) -> ExprPrecedence {
2285+
pub fn precedence(&self, has_attr: &dyn Fn(HirId) -> bool) -> ExprPrecedence {
22932286
let prefix_attrs_precedence = || -> ExprPrecedence {
2294-
let mut has_outer_attr = false;
2295-
for_each_attr(self.hir_id, &mut |attr: &Attribute| {
2296-
has_outer_attr |= matches!(attr.style(), AttrStyle::Outer)
2297-
});
2298-
if has_outer_attr { ExprPrecedence::Prefix } else { ExprPrecedence::Unambiguous }
2287+
if has_attr(self.hir_id) { ExprPrecedence::Prefix } else { ExprPrecedence::Unambiguous }
22992288
};
23002289

23012290
match &self.kind {
@@ -2351,7 +2340,7 @@ impl Expr<'_> {
23512340
| ExprKind::Use(..)
23522341
| ExprKind::Err(_) => prefix_attrs_precedence(),
23532342

2354-
ExprKind::DropTemps(expr, ..) => expr.precedence(for_each_attr),
2343+
ExprKind::DropTemps(expr, ..) => expr.precedence(has_attr),
23552344
}
23562345
}
23572346

‎compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 40 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::vec;
1010

1111
use rustc_abi::ExternAbi;
1212
use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
13-
use rustc_ast::{AttrStyle, DUMMY_NODE_ID, DelimArgs};
13+
use rustc_ast::{DUMMY_NODE_ID, DelimArgs};
1414
use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
1515
use rustc_ast_pretty::pp::{self, BoxMarker, Breaks};
1616
use rustc_ast_pretty::pprust::state::MacHeader;
@@ -81,32 +81,24 @@ impl<'a> State<'a> {
8181
}
8282

8383
fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
84-
let for_each_attr = |id: HirId, callback: &mut dyn FnMut(&hir::Attribute)| {
85-
self.attrs(id).iter().for_each(callback);
86-
};
87-
expr.precedence(&for_each_attr)
88-
}
89-
90-
fn print_attrs_as_inner(&mut self, attrs: &[hir::Attribute]) {
91-
self.print_either_attributes(attrs, ast::AttrStyle::Inner)
92-
}
93-
94-
fn print_attrs_as_outer(&mut self, attrs: &[hir::Attribute]) {
95-
self.print_either_attributes(attrs, ast::AttrStyle::Outer)
84+
let has_attr = |id: HirId| !self.attrs(id).is_empty();
85+
expr.precedence(&has_attr)
9686
}
9787

98-
fn print_either_attributes(&mut self, attrs: &[hir::Attribute], style: ast::AttrStyle) {
88+
fn print_attrs(&mut self, attrs: &[hir::Attribute]) {
9989
if attrs.is_empty() {
10090
return;
10191
}
10292

10393
for attr in attrs {
104-
self.print_attribute_inline(attr, style);
94+
self.print_attribute_as_style(attr, ast::AttrStyle::Outer);
10595
}
10696
self.hardbreak_if_not_bol();
10797
}
10898

109-
fn print_attribute_inline(&mut self, attr: &hir::Attribute, style: AttrStyle) {
99+
/// Print a single attribute as if it has style `style`, disregarding the
100+
/// actual style of the attribute.
101+
fn print_attribute_as_style(&mut self, attr: &hir::Attribute, style: ast::AttrStyle) {
110102
match &attr {
111103
hir::Attribute::Unparsed(unparsed) => {
112104
self.maybe_print_comment(unparsed.span.lo());
@@ -118,14 +110,17 @@ impl<'a> State<'a> {
118110
self.word("]");
119111
self.hardbreak()
120112
}
121-
hir::Attribute::Parsed(AttributeKind::DocComment { style, kind, comment, .. }) => {
113+
hir::Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => {
122114
self.word(rustc_ast_pretty::pprust::state::doc_comment_to_string(
123-
*kind, *style, *comment,
115+
*kind, style, *comment,
124116
));
125117
self.hardbreak()
126118
}
127119
hir::Attribute::Parsed(pa) => {
128-
self.word("#[attr = ");
120+
match style {
121+
ast::AttrStyle::Inner => self.word("#![attr = "),
122+
ast::AttrStyle::Outer => self.word("#[attr = "),
123+
}
129124
pa.print_attribute(self);
130125
self.word("]");
131126
self.hardbreak()
@@ -281,10 +276,17 @@ pub fn print_crate<'a>(
281276
ann,
282277
};
283278

279+
// Print all attributes, regardless of actual style, as inner attributes
280+
// since this is the crate root with nothing above it to print outer
281+
// attributes.
282+
for attr in s.attrs(hir::CRATE_HIR_ID) {
283+
s.print_attribute_as_style(attr, ast::AttrStyle::Inner);
284+
}
285+
284286
// When printing the AST, we sometimes need to inject `#[no_std]` here.
285287
// Since you can't compile the HIR, it's not necessary.
286288

287-
s.print_mod(krate, (*attrs)(hir::CRATE_HIR_ID));
289+
s.print_mod(krate);
288290
s.print_remaining_comments();
289291
s.s.eof()
290292
}
@@ -299,7 +301,7 @@ where
299301
}
300302

301303
pub fn attribute_to_string(ann: &dyn PpAnn, attr: &hir::Attribute) -> String {
302-
to_string(ann, |s| s.print_attribute_inline(attr, AttrStyle::Outer))
304+
to_string(ann, |s| s.print_attribute_as_style(attr, ast::AttrStyle::Outer))
303305
}
304306

305307
pub fn ty_to_string(ann: &dyn PpAnn, ty: &hir::Ty<'_>) -> String {
@@ -361,8 +363,7 @@ impl<'a> State<'a> {
361363
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span);
362364
}
363365

364-
fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[hir::Attribute]) {
365-
self.print_attrs_as_inner(attrs);
366+
fn print_mod(&mut self, _mod: &hir::Mod<'_>) {
366367
for &item_id in _mod.item_ids {
367368
self.ann.nested(self, Nested::Item(item_id));
368369
}
@@ -479,7 +480,7 @@ impl<'a> State<'a> {
479480
fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
480481
self.hardbreak_if_not_bol();
481482
self.maybe_print_comment(item.span.lo());
482-
self.print_attrs_as_outer(self.attrs(item.hir_id()));
483+
self.print_attrs(self.attrs(item.hir_id()));
483484
match item.kind {
484485
hir::ForeignItemKind::Fn(sig, arg_idents, generics) => {
485486
let (cb, ib) = self.head("");
@@ -565,7 +566,7 @@ impl<'a> State<'a> {
565566
self.hardbreak_if_not_bol();
566567
self.maybe_print_comment(item.span.lo());
567568
let attrs = self.attrs(item.hir_id());
568-
self.print_attrs_as_outer(attrs);
569+
self.print_attrs(attrs);
569570
self.ann.pre(self, AnnNode::Item(item));
570571
match item.kind {
571572
hir::ItemKind::ExternCrate(orig_name, ident) => {
@@ -647,14 +648,13 @@ impl<'a> State<'a> {
647648
self.print_ident(ident);
648649
self.nbsp();
649650
self.bopen(ib);
650-
self.print_mod(mod_, attrs);
651+
self.print_mod(mod_);
651652
self.bclose(item.span, cb);
652653
}
653654
hir::ItemKind::ForeignMod { abi, items } => {
654655
let (cb, ib) = self.head("extern");
655656
self.word_nbsp(abi.to_string());
656657
self.bopen(ib);
657-
self.print_attrs_as_inner(self.attrs(item.hir_id()));
658658
for item in items {
659659
self.ann.nested(self, Nested::ForeignItem(item.id));
660660
}
@@ -731,7 +731,6 @@ impl<'a> State<'a> {
731731

732732
self.space();
733733
self.bopen(ib);
734-
self.print_attrs_as_inner(attrs);
735734
for impl_item in items {
736735
self.ann.nested(self, Nested::ImplItem(impl_item.id));
737736
}
@@ -822,7 +821,7 @@ impl<'a> State<'a> {
822821
for v in variants {
823822
self.space_if_not_bol();
824823
self.maybe_print_comment(v.span.lo());
825-
self.print_attrs_as_outer(self.attrs(v.hir_id));
824+
self.print_attrs(self.attrs(v.hir_id));
826825
let ib = self.ibox(INDENT_UNIT);
827826
self.print_variant(v);
828827
self.word(",");
@@ -857,7 +856,7 @@ impl<'a> State<'a> {
857856
self.popen();
858857
self.commasep(Inconsistent, struct_def.fields(), |s, field| {
859858
s.maybe_print_comment(field.span.lo());
860-
s.print_attrs_as_outer(s.attrs(field.hir_id));
859+
s.print_attrs(s.attrs(field.hir_id));
861860
s.print_type(field.ty);
862861
});
863862
self.pclose();
@@ -878,7 +877,7 @@ impl<'a> State<'a> {
878877
for field in struct_def.fields() {
879878
self.hardbreak_if_not_bol();
880879
self.maybe_print_comment(field.span.lo());
881-
self.print_attrs_as_outer(self.attrs(field.hir_id));
880+
self.print_attrs(self.attrs(field.hir_id));
882881
self.print_ident(field.ident);
883882
self.word_nbsp(":");
884883
self.print_type(field.ty);
@@ -916,7 +915,7 @@ impl<'a> State<'a> {
916915
self.ann.pre(self, AnnNode::SubItem(ti.hir_id()));
917916
self.hardbreak_if_not_bol();
918917
self.maybe_print_comment(ti.span.lo());
919-
self.print_attrs_as_outer(self.attrs(ti.hir_id()));
918+
self.print_attrs(self.attrs(ti.hir_id()));
920919
match ti.kind {
921920
hir::TraitItemKind::Const(ty, default) => {
922921
self.print_associated_const(ti.ident, ti.generics, ty, default);
@@ -944,7 +943,7 @@ impl<'a> State<'a> {
944943
self.ann.pre(self, AnnNode::SubItem(ii.hir_id()));
945944
self.hardbreak_if_not_bol();
946945
self.maybe_print_comment(ii.span.lo());
947-
self.print_attrs_as_outer(self.attrs(ii.hir_id()));
946+
self.print_attrs(self.attrs(ii.hir_id()));
948947

949948
match ii.kind {
950949
hir::ImplItemKind::Const(ty, expr) => {
@@ -1028,27 +1027,16 @@ impl<'a> State<'a> {
10281027
}
10291028

10301029
fn print_block(&mut self, blk: &hir::Block<'_>, cb: BoxMarker, ib: BoxMarker) {
1031-
self.print_block_with_attrs(blk, &[], cb, ib)
1030+
self.print_block_maybe_unclosed(blk, Some(cb), ib)
10321031
}
10331032

10341033
fn print_block_unclosed(&mut self, blk: &hir::Block<'_>, ib: BoxMarker) {
1035-
self.print_block_maybe_unclosed(blk, &[], None, ib)
1036-
}
1037-
1038-
fn print_block_with_attrs(
1039-
&mut self,
1040-
blk: &hir::Block<'_>,
1041-
attrs: &[hir::Attribute],
1042-
cb: BoxMarker,
1043-
ib: BoxMarker,
1044-
) {
1045-
self.print_block_maybe_unclosed(blk, attrs, Some(cb), ib)
1034+
self.print_block_maybe_unclosed(blk, None, ib)
10461035
}
10471036

10481037
fn print_block_maybe_unclosed(
10491038
&mut self,
10501039
blk: &hir::Block<'_>,
1051-
attrs: &[hir::Attribute],
10521040
cb: Option<BoxMarker>,
10531041
ib: BoxMarker,
10541042
) {
@@ -1060,8 +1048,6 @@ impl<'a> State<'a> {
10601048
self.ann.pre(self, AnnNode::Block(blk));
10611049
self.bopen(ib);
10621050

1063-
self.print_attrs_as_inner(attrs);
1064-
10651051
for st in blk.stmts {
10661052
self.print_stmt(st);
10671053
}
@@ -1251,7 +1237,7 @@ impl<'a> State<'a> {
12511237

12521238
fn print_expr_field(&mut self, field: &hir::ExprField<'_>) {
12531239
let cb = self.cbox(INDENT_UNIT);
1254-
self.print_attrs_as_outer(self.attrs(field.hir_id));
1240+
self.print_attrs(self.attrs(field.hir_id));
12551241
if !field.is_shorthand {
12561242
self.print_ident(field.ident);
12571243
self.word_space(":");
@@ -1451,7 +1437,7 @@ impl<'a> State<'a> {
14511437

14521438
fn print_expr(&mut self, expr: &hir::Expr<'_>) {
14531439
self.maybe_print_comment(expr.span.lo());
1454-
self.print_attrs_as_outer(self.attrs(expr.hir_id));
1440+
self.print_attrs(self.attrs(expr.hir_id));
14551441
let ib = self.ibox(INDENT_UNIT);
14561442
self.ann.pre(self, AnnNode::Expr(expr));
14571443
match expr.kind {
@@ -2076,7 +2062,7 @@ impl<'a> State<'a> {
20762062
self.space();
20772063
}
20782064
let cb = self.cbox(INDENT_UNIT);
2079-
self.print_attrs_as_outer(self.attrs(field.hir_id));
2065+
self.print_attrs(self.attrs(field.hir_id));
20802066
if !field.is_shorthand {
20812067
self.print_ident(field.ident);
20822068
self.word_nbsp(":");
@@ -2086,7 +2072,7 @@ impl<'a> State<'a> {
20862072
}
20872073

20882074
fn print_param(&mut self, arg: &hir::Param<'_>) {
2089-
self.print_attrs_as_outer(self.attrs(arg.hir_id));
2075+
self.print_attrs(self.attrs(arg.hir_id));
20902076
self.print_pat(arg.pat);
20912077
}
20922078

@@ -2121,7 +2107,7 @@ impl<'a> State<'a> {
21212107
let cb = self.cbox(INDENT_UNIT);
21222108
self.ann.pre(self, AnnNode::Arm(arm));
21232109
let ib = self.ibox(0);
2124-
self.print_attrs_as_outer(self.attrs(arm.hir_id));
2110+
self.print_attrs(self.attrs(arm.hir_id));
21252111
self.print_pat(arm.pat);
21262112
self.space();
21272113
if let Some(ref g) = arm.guard {
@@ -2409,7 +2395,7 @@ impl<'a> State<'a> {
24092395
}
24102396

24112397
fn print_where_predicate(&mut self, predicate: &hir::WherePredicate<'_>) {
2412-
self.print_attrs_as_outer(self.attrs(predicate.hir_id));
2398+
self.print_attrs(self.attrs(predicate.hir_id));
24132399
match *predicate.kind {
24142400
hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
24152401
bound_generic_params,

‎compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_errors::{
1818
use rustc_hir::def::{CtorKind, DefKind, Res};
1919
use rustc_hir::def_id::DefId;
2020
use rustc_hir::lang_items::LangItem;
21-
use rustc_hir::{Attribute, ExprKind, HirId, QPath};
21+
use rustc_hir::{ExprKind, HirId, QPath};
2222
use rustc_hir_analysis::NoVariantNamed;
2323
use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _};
2424
use rustc_infer::infer;
@@ -55,7 +55,7 @@ use crate::{
5555

5656
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5757
pub(crate) fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
58-
let for_each_attr = |id: HirId, callback: &mut dyn FnMut(&Attribute)| {
58+
let has_attr = |id: HirId| -> bool {
5959
for attr in self.tcx.hir_attrs(id) {
6060
// For the purpose of rendering suggestions, disregard attributes
6161
// that originate from desugaring of any kind. For example, `x?`
@@ -71,11 +71,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7171
// let y: u32 = (x?).try_into().unwrap();
7272
// + +++++++++++++++++++++
7373
if attr.span().desugaring_kind().is_none() {
74-
callback(attr);
74+
return true;
7575
}
7676
}
77+
false
7778
};
78-
expr.precedence(&for_each_attr)
79+
expr.precedence(&has_attr)
7980
}
8081

8182
/// Check an expr with an expectation type, and also demand that the expr's

‎compiler/rustc_lint/src/context.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -855,14 +855,15 @@ impl<'tcx> LateContext<'tcx> {
855855
/// rendering diagnostic. This is not the same as the precedence that would
856856
/// be used for pretty-printing HIR by rustc_hir_pretty.
857857
pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
858-
let for_each_attr = |id: hir::HirId, callback: &mut dyn FnMut(&hir::Attribute)| {
858+
let has_attr = |id: hir::HirId| -> bool {
859859
for attr in self.tcx.hir_attrs(id) {
860860
if attr.span().desugaring_kind().is_none() {
861-
callback(attr);
861+
return true;
862862
}
863863
}
864+
false
864865
};
865-
expr.precedence(&for_each_attr)
866+
expr.precedence(&has_attr)
866867
}
867868

868869
/// If the given expression is a local binding, find the initializer expression.

‎compiler/rustc_passes/src/check_attr.rs

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
116116
let mut seen = FxHashMap::default();
117117
let attrs = self.tcx.hir_attrs(hir_id);
118118
for attr in attrs {
119+
let mut style = None;
119120
match attr {
120121
Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => {
121122
self.check_confusables(*first_span, target);
@@ -167,10 +168,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
167168
Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => {
168169
self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target)
169170
}
170-
&Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => {
171-
self.check_may_dangle(hir_id, attr_span)
171+
Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => {
172+
self.check_may_dangle(hir_id, *attr_span)
172173
}
173-
Attribute::Unparsed(_) => {
174+
Attribute::Unparsed(attr_item) => {
175+
style = Some(attr_item.style);
174176
match attr.path().as_slice() {
175177
[sym::diagnostic, sym::do_not_recommend, ..] => {
176178
self.check_do_not_recommend(attr.span(), hir_id, target, attr, item)
@@ -193,6 +195,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
193195
}
194196
[sym::doc, ..] => self.check_doc_attrs(
195197
attr,
198+
attr_item.style,
196199
hir_id,
197200
target,
198201
&mut specified_inline,
@@ -353,14 +356,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
353356
if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
354357
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
355358
{
356-
match attr.style() {
357-
ast::AttrStyle::Outer => self.tcx.emit_node_span_lint(
359+
match style {
360+
Some(ast::AttrStyle::Outer) => self.tcx.emit_node_span_lint(
358361
UNUSED_ATTRIBUTES,
359362
hir_id,
360363
attr.span(),
361364
errors::OuterCrateLevelAttr,
362365
),
363-
ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
366+
Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint(
364367
UNUSED_ATTRIBUTES,
365368
hir_id,
366369
attr.span(),
@@ -374,7 +377,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
374377
check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
375378
}
376379

377-
self.check_unused_attribute(hir_id, attr)
380+
self.check_unused_attribute(hir_id, attr, style)
378381
}
379382

380383
self.check_repr(attrs, span, target, item, hir_id);
@@ -1197,7 +1200,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
11971200
/// the first `inline`/`no_inline` attribute.
11981201
fn check_doc_inline(
11991202
&self,
1200-
attr: &Attribute,
1203+
style: AttrStyle,
12011204
meta: &MetaItemInner,
12021205
hir_id: HirId,
12031206
target: Target,
@@ -1227,8 +1230,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
12271230
meta.span(),
12281231
errors::DocInlineOnlyUse {
12291232
attr_span: meta.span(),
1230-
item_span: (attr.style() == AttrStyle::Outer)
1231-
.then(|| self.tcx.hir_span(hir_id)),
1233+
item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)),
12321234
},
12331235
);
12341236
}
@@ -1237,7 +1239,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
12371239

12381240
fn check_doc_masked(
12391241
&self,
1240-
attr: &Attribute,
1242+
style: AttrStyle,
12411243
meta: &MetaItemInner,
12421244
hir_id: HirId,
12431245
target: Target,
@@ -1249,8 +1251,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
12491251
meta.span(),
12501252
errors::DocMaskedOnlyExternCrate {
12511253
attr_span: meta.span(),
1252-
item_span: (attr.style() == AttrStyle::Outer)
1253-
.then(|| self.tcx.hir_span(hir_id)),
1254+
item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)),
12541255
},
12551256
);
12561257
return;
@@ -1263,8 +1264,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
12631264
meta.span(),
12641265
errors::DocMaskedNotExternCrateSelf {
12651266
attr_span: meta.span(),
1266-
item_span: (attr.style() == AttrStyle::Outer)
1267-
.then(|| self.tcx.hir_span(hir_id)),
1267+
item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)),
12681268
},
12691269
);
12701270
}
@@ -1288,13 +1288,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
12881288
fn check_attr_crate_level(
12891289
&self,
12901290
attr: &Attribute,
1291+
style: AttrStyle,
12911292
meta: &MetaItemInner,
12921293
hir_id: HirId,
12931294
) -> bool {
12941295
if hir_id != CRATE_HIR_ID {
12951296
// insert a bang between `#` and `[...`
12961297
let bang_span = attr.span().lo() + BytePos(1);
1297-
let sugg = (attr.style() == AttrStyle::Outer
1298+
let sugg = (style == AttrStyle::Outer
12981299
&& self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID)
12991300
.then_some(errors::AttrCrateLevelOnlySugg {
13001301
attr: attr.span().with_lo(bang_span).with_hi(bang_span),
@@ -1311,15 +1312,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
13111312
}
13121313

13131314
/// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place.
1314-
fn check_test_attr(&self, attr: &Attribute, meta: &MetaItemInner, hir_id: HirId) {
1315+
fn check_test_attr(
1316+
&self,
1317+
attr: &Attribute,
1318+
style: AttrStyle,
1319+
meta: &MetaItemInner,
1320+
hir_id: HirId,
1321+
) {
13151322
if let Some(metas) = meta.meta_item_list() {
13161323
for i_meta in metas {
13171324
match (i_meta.name(), i_meta.meta_item()) {
13181325
(Some(sym::attr), _) => {
13191326
// Allowed everywhere like `#[doc]`
13201327
}
13211328
(Some(sym::no_crate_inject), _) => {
1322-
self.check_attr_crate_level(attr, meta, hir_id);
1329+
self.check_attr_crate_level(attr, style, meta, hir_id);
13231330
}
13241331
(_, Some(m)) => {
13251332
self.tcx.emit_node_span_lint(
@@ -1373,6 +1380,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
13731380
fn check_doc_attrs(
13741381
&self,
13751382
attr: &Attribute,
1383+
style: AttrStyle,
13761384
hir_id: HirId,
13771385
target: Target,
13781386
specified_inline: &mut Option<(bool, Span)>,
@@ -1407,7 +1415,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
14071415
}
14081416

14091417
Some(sym::test) => {
1410-
self.check_test_attr(attr, meta, hir_id);
1418+
self.check_test_attr(attr, style, meta, hir_id);
14111419
}
14121420

14131421
Some(
@@ -1418,25 +1426,25 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
14181426
| sym::html_root_url
14191427
| sym::html_no_source,
14201428
) => {
1421-
self.check_attr_crate_level(attr, meta, hir_id);
1429+
self.check_attr_crate_level(attr, style, meta, hir_id);
14221430
}
14231431

14241432
Some(sym::cfg_hide) => {
1425-
if self.check_attr_crate_level(attr, meta, hir_id) {
1433+
if self.check_attr_crate_level(attr, style, meta, hir_id) {
14261434
self.check_doc_cfg_hide(meta, hir_id);
14271435
}
14281436
}
14291437

14301438
Some(sym::inline | sym::no_inline) => {
1431-
self.check_doc_inline(attr, meta, hir_id, target, specified_inline)
1439+
self.check_doc_inline(style, meta, hir_id, target, specified_inline)
14321440
}
14331441

1434-
Some(sym::masked) => self.check_doc_masked(attr, meta, hir_id, target),
1442+
Some(sym::masked) => self.check_doc_masked(style, meta, hir_id, target),
14351443

14361444
Some(sym::cfg | sym::hidden | sym::notable_trait) => {}
14371445

14381446
Some(sym::rust_logo) => {
1439-
if self.check_attr_crate_level(attr, meta, hir_id)
1447+
if self.check_attr_crate_level(attr, style, meta, hir_id)
14401448
&& !self.tcx.features().rustdoc_internals()
14411449
{
14421450
feature_err(
@@ -1475,7 +1483,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
14751483
errors::DocTestUnknownInclude {
14761484
path,
14771485
value: value.to_string(),
1478-
inner: match attr.style() {
1486+
inner: match style {
14791487
AttrStyle::Inner => "!",
14801488
AttrStyle::Outer => "",
14811489
},
@@ -2429,7 +2437,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
24292437
}
24302438
}
24312439

2432-
fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
2440+
fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option<AttrStyle>) {
24332441
// FIXME(jdonszelmann): deduplicate these checks after more attrs are parsed. This is very
24342442
// ugly now but can 100% be removed later.
24352443
if let Attribute::Parsed(p) = attr {
@@ -2482,14 +2490,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
24822490
})
24832491
{
24842492
if hir_id != CRATE_HIR_ID {
2485-
match attr.style() {
2486-
ast::AttrStyle::Outer => self.tcx.emit_node_span_lint(
2493+
match style {
2494+
Some(ast::AttrStyle::Outer) => self.tcx.emit_node_span_lint(
24872495
UNUSED_ATTRIBUTES,
24882496
hir_id,
24892497
attr.span(),
24902498
errors::OuterCrateLevelAttr,
24912499
),
2492-
ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
2500+
Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint(
24932501
UNUSED_ATTRIBUTES,
24942502
hir_id,
24952503
attr.span(),

‎compiler/rustc_resolve/src/rustdoc.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,12 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGen
356356
/// If there are no doc-comments, return true.
357357
/// FIXME(#78591): Support both inner and outer attributes on the same item.
358358
pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool {
359-
attrs.iter().find(|a| a.doc_str().is_some()).is_none_or(|a| a.style() == ast::AttrStyle::Inner)
359+
for attr in attrs {
360+
if let Some(attr_style) = attr.doc_resolution_scope() {
361+
return attr_style == ast::AttrStyle::Inner;
362+
}
363+
}
364+
true
360365
}
361366

362367
/// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`.

‎src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
2+
use rustc_ast::attr::AttributeExt as _;
23
use rustc_ast::token::CommentKind;
34
use rustc_errors::Applicability;
45
use rustc_hir::{AttrStyle, Attribute};
@@ -43,13 +44,19 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
4344
"looks like a footnote ref, but has no matching footnote",
4445
|diag| {
4546
if this_fragment.kind == DocFragmentKind::SugaredDoc {
46-
let (doc_attr, (_, doc_attr_comment_kind)) = attrs
47+
let (doc_attr, (_, doc_attr_comment_kind), attr_style) = attrs
4748
.iter()
4849
.filter(|attr| attr.span().overlaps(this_fragment.span))
4950
.rev()
50-
.find_map(|attr| Some((attr, attr.doc_str_and_comment_kind()?)))
51+
.find_map(|attr| {
52+
Some((
53+
attr,
54+
attr.doc_str_and_comment_kind()?,
55+
attr.doc_resolution_scope()?,
56+
))
57+
})
5158
.unwrap();
52-
let (to_add, terminator) = match (doc_attr_comment_kind, doc_attr.style()) {
59+
let (to_add, terminator) = match (doc_attr_comment_kind, attr_style) {
5360
(CommentKind::Line, AttrStyle::Outer) => ("\n///\n/// ", ""),
5461
(CommentKind::Line, AttrStyle::Inner) => ("\n//!\n//! ", ""),
5562
(CommentKind::Block, AttrStyle::Outer) => ("\n/** ", " */"),
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//@ check-fail
2+
//@ compile-flags: --crate-type=lib
3+
4+
// Regression test for issue 142649
5+
pub fn public() {
6+
#[deprecated] 0
7+
//~^ ERROR mismatched types
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/deprecated-expr-precedence.rs:6:19
3+
|
4+
LL | pub fn public() {
5+
| - help: try adding a return type: `-> i32`
6+
LL | #[deprecated] 0
7+
| ^ expected `()`, found integer
8+
9+
error: aborting due to 1 previous error
10+
11+
For more information about this error, try `rustc --explain E0308`.

‎tests/ui/unpretty/deprecated-attr.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,8 @@ pub struct SinceAndNote;
1616

1717
#[deprecated(note = "here's why this is deprecated", since = "1.2.3")]
1818
pub struct FlippedOrder;
19+
20+
pub fn f() {
21+
// Attribute is ignored here (with a warning), but still preserved in HIR
22+
#[deprecated] 0
23+
}

‎tests/ui/unpretty/deprecated-attr.stdout

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,12 @@ struct SinceAndNote;
2424
#[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"),
2525
note: "here's why this is deprecated"}}]
2626
struct FlippedOrder;
27+
28+
fn f() {
29+
30+
// Attribute is ignored here (with a warning), but still preserved in HIR
31+
#[attr = Deprecation {deprecation:
32+
Deprecation {since:
33+
Unspecified}}]
34+
0
35+
}

‎tests/ui/unpretty/diagnostic-attr.stdout

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,4 @@ extern crate std;
1212
trait ImportantTrait<A> { }
1313

1414
#[diagnostic::do_not_recommend]
15-
impl <T> ImportantTrait<T> for T where T: Clone
16-
{#![diagnostic::do_not_recommend]
17-
}
15+
impl <T> ImportantTrait<T> for T where T: Clone { }

‎tests/ui/unpretty/exhaustive-asm.hir.stdout

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ mod expressions {
2626

2727
mod items {
2828
/// ItemKind::GlobalAsm
29-
mod item_global_asm {/// ItemKind::GlobalAsm
29+
mod item_global_asm {
3030
global_asm! (".globl my_asm_func");
3131
}
3232
}

‎tests/ui/unpretty/exhaustive.hir.stdout

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,14 @@ mod prelude {
5050
}
5151
}
5252

53-
//! inner single-line doc comment
54-
/*!
53+
/// inner single-line doc comment
54+
/**
5555
* inner multi-line doc comment
5656
*/
5757
#[doc = "inner doc attribute"]
5858
#[allow(dead_code, unused_variables)]
5959
#[no_std]
60-
mod attributes {//! inner single-line doc comment
61-
/*!
62-
* inner multi-line doc comment
63-
*/
64-
#![doc = "inner doc attribute"]
65-
#![allow(dead_code, unused_variables)]
66-
#![no_std]
60+
mod attributes {
6761

6862
/// outer single-line doc comment
6963
/**
@@ -413,25 +407,25 @@ mod expressions {
413407
}
414408
mod items {
415409
/// ItemKind::ExternCrate
416-
mod item_extern_crate {/// ItemKind::ExternCrate
410+
mod item_extern_crate {
417411
extern crate core;
418412
extern crate self as unpretty;
419413
extern crate core as _;
420414
}
421415
/// ItemKind::Use
422-
mod item_use {/// ItemKind::Use
416+
mod item_use {
423417
use ::{};
424418
use crate::expressions;
425419
use crate::items::item_use;
426420
use core::*;
427421
}
428422
/// ItemKind::Static
429-
mod item_static {/// ItemKind::Static
423+
mod item_static {
430424
static A: () = { };
431425
static mut B: () = { };
432426
}
433427
/// ItemKind::Const
434-
mod item_const {/// ItemKind::Const
428+
mod item_const {
435429
const A: () = { };
436430
trait TraitItems {
437431
const
@@ -445,7 +439,7 @@ mod items {
445439
}
446440
}
447441
/// ItemKind::Fn
448-
mod item_fn {/// ItemKind::Fn
442+
mod item_fn {
449443
const unsafe extern "C" fn f() { }
450444
async unsafe extern "C" fn g()
451445
->
@@ -460,21 +454,19 @@ mod items {
460454
}
461455
}
462456
/// ItemKind::Mod
463-
mod item_mod {/// ItemKind::Mod
464-
}
457+
mod item_mod { }
465458
/// ItemKind::ForeignMod
466-
mod item_foreign_mod {/// ItemKind::ForeignMod
459+
mod item_foreign_mod {
467460
extern "Rust" { }
468461
extern "C" { }
469462
}
470463
/// ItemKind::GlobalAsm: see exhaustive-asm.rs
471464
/// ItemKind::TyAlias
472-
mod item_ty_alias {/// ItemKind::GlobalAsm: see exhaustive-asm.rs
473-
/// ItemKind::TyAlias
465+
mod item_ty_alias {
474466
type Type<'a> where T: 'a = T;
475467
}
476468
/// ItemKind::Enum
477-
mod item_enum {/// ItemKind::Enum
469+
mod item_enum {
478470
enum Void { }
479471
enum Empty {
480472
Unit,
@@ -490,7 +482,7 @@ mod items {
490482
}
491483
}
492484
/// ItemKind::Struct
493-
mod item_struct {/// ItemKind::Struct
485+
mod item_struct {
494486
struct Unit;
495487
struct Tuple();
496488
struct Newtype(Unit);
@@ -501,45 +493,40 @@ mod items {
501493
}
502494
}
503495
/// ItemKind::Union
504-
mod item_union {/// ItemKind::Union
496+
mod item_union {
505497
union Generic<'a, T> where T: 'a {
506498
t: T,
507499
}
508500
}
509501
/// ItemKind::Trait
510-
mod item_trait {/// ItemKind::Trait
502+
mod item_trait {
511503
auto unsafe trait Send { }
512504
trait Trait<'a>: Sized where Self: 'a { }
513505
}
514506
/// ItemKind::TraitAlias
515-
mod item_trait_alias {/// ItemKind::TraitAlias
507+
mod item_trait_alias {
516508
trait Trait<T> = Sized where for<'a> T: 'a;
517509
}
518510
/// ItemKind::Impl
519-
mod item_impl {/// ItemKind::Impl
511+
mod item_impl {
520512
impl () { }
521513
impl <T> () { }
522514
impl Default for () { }
523515
impl const <T> Default for () { }
524516
}
525517
/// ItemKind::MacCall
526-
mod item_mac_call {/// ItemKind::MacCall
527-
}
518+
mod item_mac_call { }
528519
/// ItemKind::MacroDef
529-
mod item_macro_def {/// ItemKind::MacroDef
520+
mod item_macro_def {
530521
macro_rules! mac { () => {...}; }
531522
macro stringify { () => {} }
532523
}
533524
/// ItemKind::Delegation
534-
/*! FIXME: todo */
535-
mod item_delegation {/// ItemKind::Delegation
536-
/*! FIXME: todo */
537-
}
525+
/** FIXME: todo */
526+
mod item_delegation { }
538527
/// ItemKind::DelegationMac
539-
/*! FIXME: todo */
540-
mod item_delegation_mac {/// ItemKind::DelegationMac
541-
/*! FIXME: todo */
542-
}
528+
/** FIXME: todo */
529+
mod item_delegation_mac { }
543530
}
544531
mod patterns {
545532
/// PatKind::Missing
@@ -690,29 +677,29 @@ mod types {
690677
/// TyKind::Paren
691678
fn ty_paren() { let _: T; }
692679
/// TyKind::Typeof
693-
/*! unused for now */
680+
/** unused for now */
694681
fn ty_typeof() { }
695682
/// TyKind::Infer
696683
fn ty_infer() { let _: _; }
697684
/// TyKind::ImplicitSelf
698-
/*! there is no syntax for this */
685+
/** there is no syntax for this */
699686
fn ty_implicit_self() { }
700687
/// TyKind::MacCall
701688
#[expect(deprecated)]
702689
fn ty_mac_call() { let _: T; let _: T; let _: T; }
703690
/// TyKind::CVarArgs
704-
/*! FIXME: todo */
691+
/** FIXME: todo */
705692
fn ty_c_var_args() { }
706693
/// TyKind::Pat
707694
fn ty_pat() { let _: u32 is 1..=RangeMax; }
708695
}
709696
mod visibilities {
710697
/// VisibilityKind::Public
711-
mod visibility_public {/// VisibilityKind::Public
698+
mod visibility_public {
712699
struct Pub;
713700
}
714701
/// VisibilityKind::Restricted
715-
mod visibility_restricted {/// VisibilityKind::Restricted
702+
mod visibility_restricted {
716703
struct PubCrate;
717704
struct PubSelf;
718705
struct PubSuper;

0 commit comments

Comments
 (0)
Please sign in to comment.