diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b4bb89af03871..09f376a480050 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2524,8 +2524,8 @@ impl Encodable for AttrId { } impl Decodable for AttrId { - fn decode(_: &mut D) -> AttrId { - crate::attr::mk_attr_id() + default fn decode(_: &mut D) -> AttrId { + panic!("cannot decode `AttrId` with `{}`", std::any::type_name::()); } } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 28198e69bff8f..990f4f8f1329f 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -11,12 +11,18 @@ use crate::tokenstream::{DelimSpan, Spacing, TokenTree}; use crate::tokenstream::{LazyAttrTokenStream, TokenStream}; use crate::util::comments; +use rustc_data_structures::sync::WorkerLocal; use rustc_index::bit_set::GrowableBitSet; use rustc_span::source_map::BytePos; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; +use std::cell::Cell; use std::iter; +#[cfg(debug_assertions)] +use std::ops::BitXor; +#[cfg(debug_assertions)] +use std::sync::atomic::{AtomicU32, Ordering}; pub struct MarkedAttrs(GrowableBitSet); @@ -346,22 +352,55 @@ pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem { NestedMetaItem::MetaItem(mk_word_item(ident)) } -pub(crate) fn mk_attr_id() -> AttrId { - use std::sync::atomic::AtomicU32; - use std::sync::atomic::Ordering; +pub struct AttrIdGenerator(WorkerLocal>); - static NEXT_ATTR_ID: AtomicU32 = AtomicU32::new(0); +#[cfg(debug_assertions)] +static MAX_ATTR_ID: AtomicU32 = AtomicU32::new(u32::MAX); - let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst); - assert!(id != u32::MAX); - AttrId::from_u32(id) +impl AttrIdGenerator { + pub fn new() -> Self { + // We use `(index as u32).reverse_bits()` to initialize the + // starting value of AttrId in each worker thread. + // The `index` is the index of the worker thread. + // This ensures that the AttrId generated in each thread is unique. + AttrIdGenerator(WorkerLocal::new(|index| { + let index: u32 = index.try_into().unwrap(); + + #[cfg(debug_assertions)] + { + let max_id = ((index + 1).next_power_of_two() - 1).bitxor(u32::MAX).reverse_bits(); + MAX_ATTR_ID.fetch_min(max_id, Ordering::Release); + } + + Cell::new(index.reverse_bits()) + })) + } + + pub fn mk_attr_id(&self) -> AttrId { + let id = self.0.get(); + + // Ensure the assigned attr_id does not overlap the bits + // representing the number of threads. + #[cfg(debug_assertions)] + assert!(id <= MAX_ATTR_ID.load(Ordering::Acquire)); + + self.0.set(id + 1); + AttrId::from_u32(id) + } } -pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute { - mk_attr_from_item(AttrItem { path, args, tokens: None }, None, style, span) +pub fn mk_attr( + g: &AttrIdGenerator, + style: AttrStyle, + path: Path, + args: MacArgs, + span: Span, +) -> Attribute { + mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span) } pub fn mk_attr_from_item( + g: &AttrIdGenerator, item: AttrItem, tokens: Option, style: AttrStyle, @@ -369,29 +408,30 @@ pub fn mk_attr_from_item( ) -> Attribute { Attribute { kind: AttrKind::Normal(P(ast::NormalAttr { item, tokens })), - id: mk_attr_id(), + id: g.mk_attr_id(), style, span, } } /// Returns an inner attribute with the given value and span. -pub fn mk_attr_inner(item: MetaItem) -> Attribute { - mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span) +pub fn mk_attr_inner(g: &AttrIdGenerator, item: MetaItem) -> Attribute { + mk_attr(g, AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span) } /// Returns an outer attribute with the given value and span. -pub fn mk_attr_outer(item: MetaItem) -> Attribute { - mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span) +pub fn mk_attr_outer(g: &AttrIdGenerator, item: MetaItem) -> Attribute { + mk_attr(g, AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span) } pub fn mk_doc_comment( + g: &AttrIdGenerator, comment_kind: CommentKind, style: AttrStyle, data: Symbol, span: Span, ) -> Attribute { - Attribute { kind: AttrKind::DocComment(comment_kind, data), id: mk_attr_id(), style, span } + Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span } } pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index cd03e3fb4572d..7f5e09938cbc9 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1552,7 +1552,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let uc_nested = attr::mk_nested_word_item(uc_ident); attr::mk_list_item(allow_ident, vec![uc_nested]) }; - attr::mk_attr_outer(allow) + attr::mk_attr_outer(&self.tcx.sess.parse_sess.attr_id_generator, allow) }; let attrs: AttrVec = thin_vec![attr]; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index ed5e7dace4bc4..b87c6f78d7285 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -22,6 +22,7 @@ use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol}; use rustc_span::{BytePos, FileName, Span}; +use rustc_ast::attr::AttrIdGenerator; use std::borrow::Cow; pub use self::delimited::IterDelimited; @@ -107,6 +108,7 @@ pub fn print_crate<'a>( ann: &'a dyn PpAnn, is_expanded: bool, edition: Edition, + g: &AttrIdGenerator, ) -> String { let mut s = State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann }; @@ -120,7 +122,7 @@ pub fn print_crate<'a>( // `#![feature(prelude_import)]` let pi_nested = attr::mk_nested_word_item(Ident::with_dummy_span(sym::prelude_import)); let list = attr::mk_list_item(Ident::with_dummy_span(sym::feature), vec![pi_nested]); - let fake_attr = attr::mk_attr_inner(list); + let fake_attr = attr::mk_attr_inner(g, list); s.print_attribute(&fake_attr); // Currently, in Rust 2018 we don't have `extern crate std;` at the crate @@ -128,7 +130,7 @@ pub fn print_crate<'a>( if edition == Edition::Edition2015 { // `#![no_std]` let no_std_meta = attr::mk_word_item(Ident::with_dummy_span(sym::no_std)); - let fake_attr = attr::mk_attr_inner(no_std_meta); + let fake_attr = attr::mk_attr_inner(g, no_std_meta); s.print_attribute(&fake_attr); } } diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 747e48ece704c..db05c00d2118a 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -28,7 +28,13 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - continue; } - krate.attrs.push(mk_attr(AttrStyle::Inner, path, args, start_span.to(end_span))); + krate.attrs.push(mk_attr( + &parse_sess.attr_id_generator, + AttrStyle::Inner, + path, + args, + start_span.to(end_span), + )); } krate diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 467ac34ded942..e0fb7affb3498 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -32,7 +32,8 @@ impl MultiItemModifier for Expander { ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| { let template = AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() }; - let attr = attr::mk_attr_outer(meta_item.clone()); + let attr = + attr::mk_attr_outer(&sess.parse_sess.attr_id_generator, meta_item.clone()); validate_attr::check_builtin_attribute( &sess.parse_sess, &attr, diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 079c6ff37cfb5..561ca00c71975 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -187,7 +187,10 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { let dc_nested = attr::mk_nested_word_item(Ident::new(sym::dead_code, self.def_site)); let allow_dead_code_item = attr::mk_list_item(allow_ident, vec![dc_nested]); - let allow_dead_code = attr::mk_attr_outer(allow_dead_code_item); + let allow_dead_code = attr::mk_attr_outer( + &self.sess.parse_sess.attr_id_generator, + allow_dead_code_item, + ); let attrs = attrs .into_iter() .filter(|attr| { diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index faeacd3e41040..2874fa0caff6f 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -396,6 +396,7 @@ pub fn print_after_parsing( annotation.pp_ann(), false, parse.edition, + &sess.parse_sess.attr_id_generator, ) }) } @@ -438,6 +439,7 @@ pub fn print_after_hir_lowering<'tcx>( annotation.pp_ann(), true, parse.edition, + &sess.parse_sess.attr_id_generator, ) }) } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index cf2c023c2f89f..50d2be3cee5e0 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -616,7 +616,7 @@ impl<'a> ExtCtxt<'a> { } pub fn attribute(&self, mi: ast::MetaItem) -> ast::Attribute { - attr::mk_attr_outer(mi) + attr::mk_attr_outer(&self.sess.parse_sess.attr_id_generator, mi) } pub fn meta_word(&self, sp: Span, w: Symbol) -> ast::MetaItem { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 7d30596a936f9..8d4e364074863 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -424,7 +424,13 @@ impl<'a> StripUnconfigured<'a> { ); trees.push(bracket_group); let tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::new(trees))); - let attr = attr::mk_attr_from_item(item, tokens, attr.style, item_span); + let attr = attr::mk_attr_from_item( + &self.sess.parse_sess.attr_id_generator, + item, + tokens, + attr.style, + item_span, + ); if attr.has_name(sym::crate_type) { self.sess.parse_sess.buffer_lint( rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 562246f4e8a1b..830417eea1a0a 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -450,6 +450,13 @@ impl<'a, 'tcx> Decodable> for ExpnIndex { } } +impl<'a, 'tcx> Decodable> for ast::AttrId { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ast::AttrId { + let sess = d.sess.expect("can't decode AttrId without Session"); + sess.parse_sess.attr_id_generator.mk_attr_id() + } +} + impl<'a, 'tcx> Decodable> for SyntaxContext { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SyntaxContext { let cdata = decoder.cdata(); diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index a37f828eafb9b..5fd69b15ecc04 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -87,6 +87,7 @@ impl<'a> Parser<'a> { // Always make an outer attribute - this allows us to recover from a misplaced // inner attribute. Some(attr::mk_doc_comment( + &self.sess.attr_id_generator, comment_kind, ast::AttrStyle::Outer, data, @@ -138,7 +139,13 @@ impl<'a> Parser<'a> { this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy); } - Ok(attr::mk_attr_from_item(item, None, style, attr_sp)) + Ok(attr::mk_attr_from_item( + &self.sess.attr_id_generator, + item, + None, + style, + attr_sp, + )) } else { let token_str = pprust::token_to_string(&this.token); let msg = &format!("expected `#`, found `{token_str}`"); @@ -291,7 +298,13 @@ impl<'a> Parser<'a> { } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind { if attr_style == ast::AttrStyle::Inner { self.bump(); - Some(attr::mk_doc_comment(comment_kind, attr_style, data, self.prev_token.span)) + Some(attr::mk_doc_comment( + &self.sess.attr_id_generator, + comment_kind, + attr_style, + data, + self.prev_token.span, + )) } else { None } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 9bc7fbfbe1491..0389b2a06a340 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -21,6 +21,7 @@ use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{Span, Symbol}; +use rustc_ast::attr::AttrIdGenerator; use std::str; /// The set of keys (and, optionally, values) that define the compilation @@ -219,6 +220,8 @@ pub struct ParseSess { /// Spans passed to `proc_macro::quote_span`. Each span has a numerical /// identifier represented by its position in the vector. pub proc_macro_quoted_spans: Lock>, + /// Used to generate new `AttrId`s. Every `AttrId` is unique. + pub attr_id_generator: AttrIdGenerator, } impl ParseSess { @@ -257,6 +260,7 @@ impl ParseSess { type_ascription_path_suggestions: Default::default(), assume_incomplete_release: false, proc_macro_quoted_spans: Default::default(), + attr_id_generator: AttrIdGenerator::new(), } }