Skip to content

Commit caf0187

Browse files
committed
Auto merge of #65750 - nnethercote:cheaper-doc-comments, r=petrochenkov
Cheaper doc comments This PR implements the idea from #60935: represent doc comments more cheaply, rather than converting them into `#[doc="..."]` attribute form. Unlike #60936 (which is about coalescing doc comments to reduce their number), this approach does not have any backwards compatibility concerns, and it eliminates about 80-90% of the current cost of doc comments (as estimated using the numbers in #60930, which eliminated the cost of doc comments entirely by treating them as normal comments). r? @petrochenkov
2 parents 3804876 + eea6f23 commit caf0187

File tree

25 files changed

+234
-151
lines changed

25 files changed

+234
-151
lines changed

src/librustc/hir/lowering.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -997,14 +997,20 @@ impl<'a> LoweringContext<'a> {
997997
// Note that we explicitly do not walk the path. Since we don't really
998998
// lower attributes (we use the AST version) there is nowhere to keep
999999
// the `HirId`s. We don't actually need HIR version of attributes anyway.
1000+
let kind = match attr.kind {
1001+
AttrKind::Normal(ref item) => {
1002+
AttrKind::Normal(AttrItem {
1003+
path: item.path.clone(),
1004+
tokens: self.lower_token_stream(item.tokens.clone()),
1005+
})
1006+
}
1007+
AttrKind::DocComment(comment) => AttrKind::DocComment(comment)
1008+
};
1009+
10001010
Attribute {
1001-
item: AttrItem {
1002-
path: attr.path.clone(),
1003-
tokens: self.lower_token_stream(attr.tokens.clone()),
1004-
},
1011+
kind,
10051012
id: attr.id,
10061013
style: attr.style,
1007-
is_sugared_doc: attr.is_sugared_doc,
10081014
span: attr.span,
10091015
}
10101016
}

src/librustc/ich/impls_syntax.rs

+11-14
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
177177
let filtered: SmallVec<[&ast::Attribute; 8]> = self
178178
.iter()
179179
.filter(|attr| {
180-
!attr.is_sugared_doc &&
180+
!attr.is_doc_comment() &&
181181
!attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name))
182182
})
183183
.collect();
@@ -207,19 +207,16 @@ impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute {
207207
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
208208
// Make sure that these have been filtered out.
209209
debug_assert!(!self.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name)));
210-
debug_assert!(!self.is_sugared_doc);
211-
212-
let ast::Attribute {
213-
ref item,
214-
id: _,
215-
style,
216-
is_sugared_doc: _,
217-
span,
218-
} = *self;
219-
220-
item.hash_stable(hcx, hasher);
221-
style.hash_stable(hcx, hasher);
222-
span.hash_stable(hcx, hasher);
210+
debug_assert!(!self.is_doc_comment());
211+
212+
let ast::Attribute { kind, id: _, style, span } = self;
213+
if let ast::AttrKind::Normal(item) = kind {
214+
item.hash_stable(hcx, hasher);
215+
style.hash_stable(hcx, hasher);
216+
span.hash_stable(hcx, hasher);
217+
} else {
218+
unreachable!();
219+
}
223220
}
224221
}
225222

src/librustc_lint/builtin.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,7 @@ impl EarlyLintPass for DeprecatedAttr {
706706
}
707707
}
708708
if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) {
709-
let path_str = pprust::path_to_string(&attr.path);
709+
let path_str = pprust::path_to_string(&attr.get_normal_item().path);
710710
let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str);
711711
lint_deprecated_attr(cx, attr, &msg, None);
712712
}
@@ -736,7 +736,7 @@ impl UnusedDocComment {
736736
let mut sugared_span: Option<Span> = None;
737737

738738
while let Some(attr) = attrs.next() {
739-
if attr.is_sugared_doc {
739+
if attr.is_doc_comment() {
740740
sugared_span = Some(
741741
sugared_span.map_or_else(
742742
|| attr.span,
@@ -745,7 +745,7 @@ impl UnusedDocComment {
745745
);
746746
}
747747

748-
if attrs.peek().map(|next_attr| next_attr.is_sugared_doc).unwrap_or_default() {
748+
if attrs.peek().map(|next_attr| next_attr.is_doc_comment()).unwrap_or_default() {
749749
continue;
750750
}
751751

src/librustc_metadata/link_args.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ crate fn collect(tcx: TyCtxt<'_>) -> Vec<String> {
1111
tcx.hir().krate().visit_all_item_likes(&mut collector);
1212

1313
for attr in tcx.hir().krate().attrs.iter() {
14-
if attr.path == sym::link_args {
14+
if attr.has_name(sym::link_args) {
1515
if let Some(linkarg) = attr.value_str() {
1616
collector.add_link_args(&linkarg.as_str());
1717
}

src/librustc_passes/ast_validation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ impl<'a> AstValidator<'a> {
328328
let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
329329
!arr.contains(&attr.name_or_empty()) && is_builtin_attr(attr)
330330
})
331-
.for_each(|attr| if attr.is_sugared_doc {
331+
.for_each(|attr| if attr.is_doc_comment() {
332332
let mut err = self.err_handler().struct_span_err(
333333
attr.span,
334334
"documentation comments cannot be applied to function parameters"

src/librustc_resolve/build_reduced_graph.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1229,8 +1229,10 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
12291229
}
12301230

12311231
fn visit_attribute(&mut self, attr: &'b ast::Attribute) {
1232-
if !attr.is_sugared_doc && is_builtin_attr(attr) {
1233-
self.r.builtin_attrs.push((attr.path.segments[0].ident, self.parent_scope));
1232+
if !attr.is_doc_comment() && is_builtin_attr(attr) {
1233+
self.r.builtin_attrs.push(
1234+
(attr.get_normal_item().path.segments[0].ident, self.parent_scope)
1235+
);
12341236
}
12351237
visit::walk_attribute(self, attr);
12361238
}

src/librustc_resolve/macros.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,10 @@ impl<'a> base::Resolver for Resolver<'a> {
179179

180180
let (path, kind, derives, after_derive) = match invoc.kind {
181181
InvocationKind::Attr { ref attr, ref derives, after_derive, .. } =>
182-
(&attr.path, MacroKind::Attr, self.arenas.alloc_ast_paths(derives), after_derive),
182+
(&attr.get_normal_item().path,
183+
MacroKind::Attr,
184+
self.arenas.alloc_ast_paths(derives),
185+
after_derive),
183186
InvocationKind::Bang { ref mac, .. } =>
184187
(&mac.path, MacroKind::Bang, &[][..], false),
185188
InvocationKind::Derive { ref path, .. } =>

src/librustc_save_analysis/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -885,7 +885,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
885885
for attr in attrs {
886886
if attr.check_name(sym::doc) {
887887
if let Some(val) = attr.value_str() {
888-
if attr.is_sugared_doc {
888+
if attr.is_doc_comment() {
889889
result.push_str(&strip_doc_comment_decoration(&val.as_str()));
890890
} else {
891891
result.push_str(&val.as_str());
@@ -1195,7 +1195,7 @@ fn null_id() -> rls_data::Id {
11951195
fn lower_attributes(attrs: Vec<Attribute>, scx: &SaveContext<'_, '_>) -> Vec<rls_data::Attribute> {
11961196
attrs.into_iter()
11971197
// Only retain real attributes. Doc comments are lowered separately.
1198-
.filter(|attr| attr.path != sym::doc)
1198+
.filter(|attr| !attr.has_name(sym::doc))
11991199
.map(|mut attr| {
12001200
// Remove the surrounding '#[..]' or '#![..]' of the pretty printed
12011201
// attribute. First normalize all inner attribute (#![..]) to outer

src/librustc_typeck/collect.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2706,7 +2706,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
27062706
}
27072707

27082708
codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
2709-
if attr.path != sym::inline {
2709+
if !attr.has_name(sym::inline) {
27102710
return ia;
27112711
}
27122712
match attr.meta().map(|i| i.kind) {
@@ -2746,7 +2746,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
27462746
});
27472747

27482748
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
2749-
if attr.path != sym::optimize {
2749+
if !attr.has_name(sym::optimize) {
27502750
return ia;
27512751
}
27522752
let err = |sp, s| span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s);

src/librustdoc/clean/mod.rs

+24-23
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind};
2626
use rustc::ty::fold::TypeFolder;
2727
use rustc::ty::layout::VariantIdx;
2828
use rustc::util::nodemap::{FxHashMap, FxHashSet};
29-
use syntax::ast::{self, Attribute, AttrStyle, AttrItem, Ident};
29+
use syntax::ast::{self, Attribute, AttrStyle, AttrKind, Ident};
3030
use syntax::attr;
3131
use syntax::parse::lexer::comments;
3232
use syntax::source_map::DUMMY_SP;
@@ -859,31 +859,32 @@ impl Attributes {
859859
let mut cfg = Cfg::True;
860860
let mut doc_line = 0;
861861

862-
/// Converts `attr` to a normal `#[doc="foo"]` comment, if it is a
863-
/// comment like `///` or `/** */`. (Returns `attr` unchanged for
864-
/// non-sugared doc attributes.)
865-
pub fn with_desugared_doc<T>(attr: &Attribute, f: impl FnOnce(&Attribute) -> T) -> T {
866-
if attr.is_sugared_doc {
867-
let comment = attr.value_str().unwrap();
868-
let meta = attr::mk_name_value_item_str(
869-
Ident::with_dummy_span(sym::doc),
870-
Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str())),
871-
DUMMY_SP,
872-
);
873-
f(&Attribute {
874-
item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
875-
id: attr.id,
876-
style: attr.style,
877-
is_sugared_doc: true,
878-
span: attr.span,
879-
})
880-
} else {
881-
f(attr)
862+
/// If `attr` is a doc comment, strips the leading and (if present)
863+
/// trailing comments symbols, e.g. `///`, `/**`, and `*/`. Otherwise,
864+
/// returns `attr` unchanged.
865+
pub fn with_doc_comment_markers_stripped<T>(
866+
attr: &Attribute,
867+
f: impl FnOnce(&Attribute) -> T
868+
) -> T {
869+
match attr.kind {
870+
AttrKind::Normal(_) => {
871+
f(attr)
872+
}
873+
AttrKind::DocComment(comment) => {
874+
let comment =
875+
Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str()));
876+
f(&Attribute {
877+
kind: AttrKind::DocComment(comment),
878+
id: attr.id,
879+
style: attr.style,
880+
span: attr.span,
881+
})
882+
}
882883
}
883884
}
884885

885886
let other_attrs = attrs.iter().filter_map(|attr| {
886-
with_desugared_doc(attr, |attr| {
887+
with_doc_comment_markers_stripped(attr, |attr| {
887888
if attr.check_name(sym::doc) {
888889
if let Some(mi) = attr.meta() {
889890
if let Some(value) = mi.value_str() {
@@ -892,7 +893,7 @@ impl Attributes {
892893
let line = doc_line;
893894
doc_line += value.lines().count();
894895

895-
if attr.is_sugared_doc {
896+
if attr.is_doc_comment() {
896897
doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value));
897898
} else {
898899
doc_strings.push(DocFragment::RawDoc(line, attr.span, value));

src/libsyntax/ast.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -2190,22 +2190,29 @@ pub struct AttrItem {
21902190
}
21912191

21922192
/// Metadata associated with an item.
2193-
/// Doc-comments are promoted to attributes that have `is_sugared_doc = true`.
21942193
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
21952194
pub struct Attribute {
2196-
pub item: AttrItem,
2195+
pub kind: AttrKind,
21972196
pub id: AttrId,
21982197
/// Denotes if the attribute decorates the following construct (outer)
21992198
/// or the construct this attribute is contained within (inner).
22002199
pub style: AttrStyle,
2201-
pub is_sugared_doc: bool,
22022200
pub span: Span,
22032201
}
22042202

2205-
// Compatibility impl to avoid churn, consider removing.
2206-
impl std::ops::Deref for Attribute {
2207-
type Target = AttrItem;
2208-
fn deref(&self) -> &Self::Target { &self.item }
2203+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2204+
pub enum AttrKind {
2205+
/// A normal attribute.
2206+
Normal(AttrItem),
2207+
2208+
/// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`).
2209+
/// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal`
2210+
/// variant (which is much less compact and thus more expensive).
2211+
///
2212+
/// Note: `self.has_name(sym::doc)` and `self.check_name(sym::doc)` succeed
2213+
/// for this variant, but this may change in the future.
2214+
/// ```
2215+
DocComment(Symbol),
22092216
}
22102217

22112218
/// `TraitRef`s appear in impls.

src/libsyntax/attr/builtin.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -228,18 +228,18 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
228228
sym::stable,
229229
sym::rustc_promotable,
230230
sym::rustc_allow_const_fn_ptr,
231-
].iter().any(|&s| attr.path == s) {
231+
].iter().any(|&s| attr.has_name(s)) {
232232
continue // not a stability level
233233
}
234234

235235
mark_used(attr);
236236

237237
let meta = attr.meta();
238238

239-
if attr.path == sym::rustc_promotable {
239+
if attr.has_name(sym::rustc_promotable) {
240240
promotable = true;
241241
}
242-
if attr.path == sym::rustc_allow_const_fn_ptr {
242+
if attr.has_name(sym::rustc_allow_const_fn_ptr) {
243243
allow_const_fn_ptr = true;
244244
}
245245
// attributes with data
@@ -778,7 +778,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
778778

779779
let mut acc = Vec::new();
780780
let diagnostic = &sess.span_diagnostic;
781-
if attr.path == sym::repr {
781+
if attr.has_name(sym::repr) {
782782
if let Some(items) = attr.meta_item_list() {
783783
mark_used(attr);
784784
for item in items {

0 commit comments

Comments
 (0)