Skip to content

Commit e4a4ccb

Browse files
Move doc = "" parsing out of DocParser to keep doc attributes order
1 parent 86f1d6a commit e4a4ccb

File tree

2 files changed

+41
-25
lines changed

2 files changed

+41
-25
lines changed

compiler/rustc_attr_parsing/src/attributes/doc.rs

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#![allow(unused_imports)]
33

44
use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit};
5-
use rustc_ast::token::CommentKind;
65
use rustc_errors::MultiSpan;
76
use rustc_feature::template;
87
use rustc_hir::attrs::{
@@ -81,19 +80,10 @@ fn parse_keyword_and_attribute<'c, S, F>(
8180
*attr_value = Some((value, path.span()));
8281
}
8382

84-
#[derive(Debug)]
85-
struct DocComment {
86-
style: AttrStyle,
87-
kind: CommentKind,
88-
span: Span,
89-
comment: Symbol,
90-
}
91-
9283
#[derive(Default, Debug)]
9384
pub(crate) struct DocParser {
9485
attribute: DocAttribute,
9586
nb_doc_attrs: usize,
96-
doc_comment: Option<DocComment>,
9787
}
9888

9989
impl DocParser {
@@ -481,17 +471,11 @@ impl DocParser {
481471
}
482472
}
483473
ArgParser::NameValue(nv) => {
484-
let Some(comment) = nv.value_as_str() else {
474+
if nv.value_as_str().is_none() {
485475
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
486-
return;
487-
};
488-
489-
self.doc_comment = Some(DocComment {
490-
style: cx.attr_style,
491-
kind: CommentKind::Block,
492-
span: nv.value_span,
493-
comment,
494-
});
476+
} else {
477+
unreachable!("Should have been handled at the same time as sugar-syntaxed doc comments");
478+
}
495479
}
496480
}
497481
}
@@ -537,9 +521,7 @@ impl<S: Stage> AttributeParser<S> for DocParser {
537521
]);
538522

539523
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
540-
if let Some(DocComment { style, kind, span, comment }) = self.doc_comment {
541-
Some(AttributeKind::DocComment { style, kind, span, comment })
542-
} else if self.nb_doc_attrs != 0 {
524+
if self.nb_doc_attrs != 0 {
543525
Some(AttributeKind::Doc(Box::new(self.attribute)))
544526
} else {
545527
None

compiler/rustc_attr_parsing/src/interface.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::borrow::Cow;
22

33
use rustc_ast as ast;
44
use rustc_ast::{AttrStyle, NodeId};
5+
use rustc_ast::token::CommentKind;
56
use rustc_errors::DiagCtxtHandle;
67
use rustc_feature::{AttributeTemplate, Features};
78
use rustc_hir::attrs::AttributeKind;
@@ -258,7 +259,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
258259
// that's expanded right? But no, sometimes, when parsing attributes on macros,
259260
// we already use the lowering logic and these are still there. So, when `omit_doc`
260261
// is set we *also* want to ignore these.
261-
if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) {
262+
let is_doc_attribute = attr.has_name(sym::doc);
263+
if omit_doc == OmitDoc::Skip && is_doc_attribute {
262264
continue;
263265
}
264266

@@ -290,8 +292,40 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
290292
) else {
291293
continue;
292294
};
293-
let path = parser.path();
294295
let args = parser.args();
296+
297+
// Special-case handling for `#[doc = "..."]`: if we go through with
298+
// `DocParser`, the order of doc comments will be messed up because `///`
299+
// doc comments are added into `attributes` whereas attributes parsed with
300+
// `DocParser` are added into `parsed_attributes` which are then appended
301+
// to `attributes`. So if you have:
302+
//
303+
// /// bla
304+
// #[doc = "a"]
305+
// /// blob
306+
//
307+
// You would get:
308+
//
309+
// bla
310+
// blob
311+
// a
312+
if is_doc_attribute
313+
&& let ArgParser::NameValue(nv) = args
314+
// If not a string key/value, it should emit an error, but to make
315+
// things simpler, it's handled in `DocParser` because it's simpler to
316+
// emit an error with `AcceptContext`.
317+
&& let Some(comment) = nv.value_as_str()
318+
{
319+
attributes.push(Attribute::Parsed(AttributeKind::DocComment {
320+
style: attr.style,
321+
kind: CommentKind::Block,
322+
span: nv.value_span,
323+
comment,
324+
}));
325+
continue;
326+
}
327+
328+
let path = parser.path();
295329
for accept in accepts {
296330
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
297331
shared: SharedContext {

0 commit comments

Comments
 (0)