Skip to content

Commit 393f4ae

Browse files
committed
Allow Clippy to define duplicate extra symbols
1 parent 25cf7d1 commit 393f4ae

File tree

19 files changed

+575
-441
lines changed

19 files changed

+575
-441
lines changed

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
264264
hash_untracked_state: None,
265265
register_lints: None,
266266
override_queries: None,
267-
extra_symbols: Vec::new(),
267+
preinterned_symbols: None,
268268
make_codegen_backend: None,
269269
registry: diagnostics_registry(),
270270
using_internal_features: &USING_INTERNAL_FEATURES,

compiler/rustc_hir/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ fn def_path_hash_depends_on_crate_id() {
1717
// the crate by changing the crate disambiguator (e.g. via bumping the
1818
// crate's version number).
1919

20-
create_session_globals_then(Edition::Edition2024, &[], None, || {
20+
create_session_globals_then(Edition::Edition2024, None, None, || {
2121
let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()], "");
2222
let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()], "");
2323

compiler/rustc_interface/src/interface.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,9 @@ pub struct Config {
350350
/// the list of queries.
351351
pub override_queries: Option<fn(&Session, &mut Providers)>,
352352

353-
/// An extra set of symbols to add to the symbol interner, the symbol indices
354-
/// will start at [`PREDEFINED_SYMBOLS_COUNT`](rustc_span::symbol::PREDEFINED_SYMBOLS_COUNT)
355-
pub extra_symbols: Vec<&'static str>,
353+
/// Replaces the default list of preinterned symbols, should be set to the `PREINTERNED_SYMBOLS`
354+
/// expanded from [`rustc_span::extra_symbols`]
355+
pub preinterned_symbols: Option<&'static [&'static str]>,
356356

357357
/// This is a callback from the driver that is called to create a codegen backend.
358358
///
@@ -418,7 +418,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
418418
&early_dcx,
419419
config.opts.edition,
420420
config.opts.unstable_opts.threads,
421-
&config.extra_symbols,
421+
config.preinterned_symbols,
422422
SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind },
423423
|current_gcx, jobserver_proxy| {
424424
// The previous `early_dcx` can't be reused here because it doesn't

compiler/rustc_interface/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ where
5555
checksum_hash_kind,
5656
});
5757

58-
rustc_span::create_session_globals_then(DEFAULT_EDITION, &[], sm_inputs, || {
58+
rustc_span::create_session_globals_then(DEFAULT_EDITION, None, sm_inputs, || {
5959
let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
6060
let io = CompilerIO {
6161
input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },

compiler/rustc_interface/src/util.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx, Arc<Proxy>) -> R + Send, R:
128128
thread_stack_size: usize,
129129
edition: Edition,
130130
sm_inputs: SourceMapInputs,
131-
extra_symbols: &[&'static str],
131+
driver_symbols: Option<&[&'static str]>,
132132
f: F,
133133
) -> R {
134134
// The "thread pool" is a single spawned thread in the non-parallel
@@ -148,7 +148,7 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx, Arc<Proxy>) -> R + Send, R:
148148
.spawn_scoped(s, move || {
149149
rustc_span::create_session_globals_then(
150150
edition,
151-
extra_symbols,
151+
driver_symbols,
152152
Some(sm_inputs),
153153
|| f(CurrentGcx::new(), Proxy::new()),
154154
)
@@ -170,7 +170,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
170170
thread_builder_diag: &EarlyDiagCtxt,
171171
edition: Edition,
172172
threads: usize,
173-
extra_symbols: &[&'static str],
173+
driver_symbols: Option<&[&'static str]>,
174174
sm_inputs: SourceMapInputs,
175175
f: F,
176176
) -> R {
@@ -191,7 +191,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
191191
thread_stack_size,
192192
edition,
193193
sm_inputs,
194-
extra_symbols,
194+
driver_symbols,
195195
|current_gcx, jobserver_proxy| {
196196
// Register the thread for use with the `WorkerLocal` type.
197197
registry.register();
@@ -259,7 +259,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
259259
// pool. Upon creation, each worker thread created gets a copy of the
260260
// session globals in TLS. This is possible because `SessionGlobals` impls
261261
// `Send` in the parallel compiler.
262-
rustc_span::create_session_globals_then(edition, extra_symbols, Some(sm_inputs), || {
262+
rustc_span::create_session_globals_then(edition, driver_symbols, Some(sm_inputs), || {
263263
rustc_span::with_session_globals(|session_globals| {
264264
let session_globals = FromDyn::from(session_globals);
265265
builder

compiler/rustc_macros/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ pub fn symbols(input: TokenStream) -> TokenStream {
4040
symbols::symbols(input.into()).into()
4141
}
4242

43+
#[proc_macro]
44+
pub fn extra_symbols_impl(input: TokenStream) -> TokenStream {
45+
symbols::extra_symbols(input.into()).into()
46+
}
47+
4348
/// Derive an extension trait for a given impl block. The trait name
4449
/// goes into the parenthesized args of the macro, for greppability.
4550
/// For example:

compiler/rustc_macros/src/symbols.rs

Lines changed: 150 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@
2525
//! ```
2626
2727
use std::collections::HashMap;
28+
use std::collections::hash_map::Entry;
2829

2930
use proc_macro2::{Span, TokenStream};
3031
use quote::quote;
3132
use syn::parse::{Parse, ParseStream, Result};
3233
use syn::punctuated::Punctuated;
33-
use syn::{Expr, Ident, Lit, LitStr, Macro, Token, braced};
34+
use syn::{Expr, Ident, Lit, LitStr, Macro, Token, braced, bracketed};
3435

3536
#[cfg(test)]
3637
mod tests;
@@ -147,25 +148,44 @@ struct Predefined {
147148
span_of_name: Span,
148149
}
149150

151+
struct Duplicate {
152+
name: String,
153+
span_of_name: Span,
154+
}
155+
150156
struct Entries {
151157
map: HashMap<String, Predefined>,
158+
prefill_stream: TokenStream,
152159
}
153160

154161
impl Entries {
155162
fn with_capacity(capacity: usize) -> Self {
156-
Entries { map: HashMap::with_capacity(capacity) }
163+
Entries { map: HashMap::with_capacity(capacity), prefill_stream: TokenStream::new() }
164+
}
165+
166+
fn try_insert(&mut self, span: Span, s: String) -> (u32, Option<Duplicate>) {
167+
let len = self.len();
168+
match self.map.entry(s) {
169+
Entry::Occupied(entry) => {
170+
let Predefined { idx, span_of_name } = *entry.get();
171+
(idx, Some(Duplicate { name: entry.key().clone(), span_of_name }))
172+
}
173+
Entry::Vacant(entry) => {
174+
let s = entry.key().as_str();
175+
self.prefill_stream.extend(quote! { #s, });
176+
entry.insert(Predefined { idx: len, span_of_name: span });
177+
(len, None)
178+
}
179+
}
157180
}
158181

159-
fn insert(&mut self, span: Span, s: &str, errors: &mut Errors) -> u32 {
160-
if let Some(prev) = self.map.get(s) {
161-
errors.error(span, format!("Symbol `{s}` is duplicated"));
162-
errors.error(prev.span_of_name, "location of previous definition".to_string());
163-
prev.idx
164-
} else {
165-
let idx = self.len();
166-
self.map.insert(s.to_string(), Predefined { idx, span_of_name: span });
167-
idx
182+
fn insert(&mut self, span: Span, s: String, errors: &mut Errors) -> u32 {
183+
let (idx, duplicate) = self.try_insert(span, s);
184+
if let Some(Duplicate { name, span_of_name }) = duplicate {
185+
errors.error(span, format!("Symbol `{name}` is duplicated"));
186+
errors.error(span_of_name, "location of previous definition".to_string());
168187
}
188+
idx
169189
}
170190

171191
fn len(&self) -> u32 {
@@ -188,18 +208,13 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
188208

189209
let mut keyword_stream = quote! {};
190210
let mut symbols_stream = quote! {};
191-
let mut prefill_stream = quote! {};
192211
let mut entries = Entries::with_capacity(input.keywords.len() + input.symbols.len() + 10);
193212

194213
// Generate the listed keywords.
195214
for keyword in input.keywords.iter() {
196215
let name = &keyword.name;
197-
let value = &keyword.value;
198-
let value_string = value.value();
199-
let idx = entries.insert(keyword.name.span(), &value_string, &mut errors);
200-
prefill_stream.extend(quote! {
201-
#value,
202-
});
216+
let value_string = keyword.value.value();
217+
let idx = entries.insert(keyword.name.span(), value_string, &mut errors);
203218
keyword_stream.extend(quote! {
204219
pub const #name: Symbol = Symbol::new(#idx);
205220
});
@@ -224,23 +239,15 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
224239
continue;
225240
}
226241
};
227-
let idx = entries.insert(symbol.name.span(), &value, &mut errors);
228-
229-
prefill_stream.extend(quote! {
230-
#value,
231-
});
242+
let idx = entries.insert(symbol.name.span(), value, &mut errors);
232243
symbols_stream.extend(quote! {
233244
pub const #name: Symbol = Symbol::new(#idx);
234245
});
235246
}
236247

237248
// Generate symbols for the strings "0", "1", ..., "9".
238249
for n in 0..10 {
239-
let n = n.to_string();
240-
entries.insert(Span::call_site(), &n, &mut errors);
241-
prefill_stream.extend(quote! {
242-
#n,
243-
});
250+
entries.insert(Span::call_site(), n.to_string(), &mut errors);
244251
}
245252

246253
// Symbols whose value comes from an environment variable. It's allowed for
@@ -267,23 +274,16 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
267274
}
268275
};
269276

270-
let idx = if let Some(prev) = entries.map.get(&value) {
271-
prev.idx
272-
} else {
273-
prefill_stream.extend(quote! {
274-
#value,
275-
});
276-
entries.insert(symbol.name.span(), &value, &mut errors)
277-
};
278-
279277
let name = &symbol.name;
278+
let (idx, _) = entries.try_insert(name.span(), value);
280279
symbols_stream.extend(quote! {
281280
pub const #name: Symbol = Symbol::new(#idx);
282281
});
283282
}
284283

285284
let symbol_digits_base = entries.map["0"].idx;
286285
let predefined_symbols_count = entries.len();
286+
let prefill_stream = entries.prefill_stream;
287287
let output = quote! {
288288
const SYMBOL_DIGITS_BASE: u32 = #symbol_digits_base;
289289

@@ -309,14 +309,124 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
309309
impl Interner {
310310
/// Creates an `Interner` with the predefined symbols from the `symbols!` macro and
311311
/// any extra symbols provided by external drivers such as Clippy
312-
pub(crate) fn with_extra_symbols(extra_symbols: &[&'static str]) -> Self {
312+
pub(crate) fn new(driver_symbols: Option<&[&'static str]>) -> Self {
313313
Interner::prefill(
314-
&[#prefill_stream],
315-
extra_symbols,
314+
driver_symbols.unwrap_or(&[#prefill_stream])
316315
)
317316
}
318317
}
318+
319+
/// Allows drivers to define extra preinterned symbols, the expanded `PREINTERNED_SYMBOLS`
320+
/// is to be provided to `rustc_interface::Config`
321+
#[macro_export]
322+
macro_rules! extra_symbols {
323+
($(#[macro_export] $further_symbols:ident;)? Symbols { $($tt:tt)* }) => {
324+
rustc_macros::extra_symbols_impl! {
325+
$($further_symbols)? [#prefill_stream] $($tt)*
326+
}
327+
};
328+
}
319329
};
320330

321331
(output, errors.list)
322332
}
333+
334+
#[derive(Default)]
335+
struct ExtraSymbols {
336+
macro_ident: Option<Ident>,
337+
predefined: Punctuated<LitStr, Token![,]>,
338+
extra_symbols: Punctuated<Symbol, Token![,]>,
339+
}
340+
341+
impl Parse for ExtraSymbols {
342+
fn parse(input: ParseStream<'_>) -> Result<Self> {
343+
let macro_ident: Option<Ident> = input.parse()?;
344+
345+
let content;
346+
bracketed!(content in input);
347+
let predefined = Punctuated::parse_terminated(&content)?;
348+
349+
let extra_symbols = Punctuated::parse_terminated(&input)?;
350+
351+
Ok(ExtraSymbols { macro_ident, predefined, extra_symbols })
352+
}
353+
}
354+
355+
pub(super) fn extra_symbols(input: TokenStream) -> TokenStream {
356+
let mut errors = Errors::default();
357+
358+
let input: ExtraSymbols = match syn::parse2(input) {
359+
Ok(input) => input,
360+
Err(e) => {
361+
errors.list.push(e);
362+
Default::default()
363+
}
364+
};
365+
366+
let mut symbol_stream = TokenStream::new();
367+
let mut duplicate_symbols = TokenStream::new();
368+
369+
let mut entries = Entries::with_capacity(input.predefined.len() + input.extra_symbols.len());
370+
for lit in &input.predefined {
371+
entries.insert(lit.span(), lit.value(), &mut errors);
372+
}
373+
374+
for symbol in input.extra_symbols {
375+
let value = match symbol.value {
376+
Value::SameAsName => symbol.name.to_string(),
377+
Value::String(lit) => lit.value(),
378+
_ => {
379+
errors.error(
380+
symbol.name.span(),
381+
"unsupported expression for extra symbol value".to_string(),
382+
);
383+
continue;
384+
}
385+
};
386+
387+
let name = &symbol.name;
388+
let (idx, duplicate) = entries.try_insert(name.span(), value);
389+
if duplicate.is_some() {
390+
duplicate_symbols.extend(quote! { #name, });
391+
}
392+
symbol_stream.extend(quote! {
393+
pub const #name: Symbol = Symbol::new(#idx);
394+
});
395+
}
396+
397+
let prefill_stream = entries.prefill_stream;
398+
399+
let further_symbols = if let Some(macro_ident) = input.macro_ident {
400+
quote! {
401+
#[macro_export]
402+
macro_rules! #macro_ident {
403+
($(#[macro_export] $further_symbols:ident;)? Symbols { $($tt:tt)* }) => {
404+
rustc_macros::extra_symbols_impl! {
405+
$($further_symbols)? [#prefill_stream] $($tt)*
406+
}
407+
};
408+
}
409+
}
410+
} else {
411+
TokenStream::new()
412+
};
413+
414+
let mut output = quote! {
415+
/// To be supplied to `rustc_interface::Config`
416+
pub const PREINTERNED_SYMBOLS: &[&str] = &[
417+
#prefill_stream
418+
];
419+
420+
pub const DUPLICATE_SYMBOLS: &[Symbol] = &[
421+
#duplicate_symbols
422+
];
423+
424+
#symbol_stream
425+
426+
#further_symbols
427+
};
428+
429+
output.extend(errors.list.into_iter().map(|e| e.into_compile_error()));
430+
431+
output
432+
}

0 commit comments

Comments
 (0)