Skip to content

Commit d527bc9

Browse files
committed
Auto merge of #159344 - Urgau:canonical-symbols, r=mejrs
Replace weak only lang items with a custom attribute When I added the `invalid_runtime_symbol_definitions` and `suspicious_runtime_symbol_definitions` lints in #155521 I added the concept of "weak only" lang item. It's a `LangItem` that has no implementation, this is useful because the `core` symbols where not directly called, they were inserted by the compiler. This mechanism work well, but T-lang [approved](#158522 (comment)) the extension to "all extern functions referenced by the standard library", which makes the lang item approach impractical as we needs to update 5 files just to declare them. I'm not sure we can ask library contributor to do the dance for each `extern "C"` functions. But the most problematic thing is that many extern functions in `std` come from `libc` not `std`, and adding lang items there is just no feasible I think. Instead this PR proposed that we introduce a proper mechanism for them by adding a attribute `#[rustc_canonical_symbol = "..."]`, which is encoded and decoded in `rmeta` like lang items and diagnostics items. This simplifies the declaration as we only need to put the attribute to be effective `#[rustc_canonical_symbol = "open"]`. It also opens up many possibilities (none implemented here) like putting them on `use` statements (so we don't need to modify `libc`) or having the attribute be placed on a module. The table may also be useful on it's own if we want someday to do it for all crates, not just the standard library. Follow up to #155521 and #158522
2 parents 9e71b3b + deac9ea commit d527bc9

29 files changed

Lines changed: 293 additions & 113 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ impl SingleAttributeParser for LangParser {
582582
// Only weak lang items may be applied to foreign items
583583
if [Target::ForeignFn, Target::ForeignStatic, Target::ForeignTy, Target::ForeignMod]
584584
.contains(&cx.target)
585-
&& !(lang_item.is_weak() || lang_item.is_weak_only())
585+
&& !lang_item.is_weak()
586586
{
587587
cx.emit_err(UnknownExternLangItem { span: cx.attr_span, lang_item: lang_item.name() });
588588
return None;
@@ -1145,3 +1145,18 @@ impl NoArgsAttributeParser for RustcExhaustiveParser {
11451145
const STABILITY: AttributeStability = unstable!(rustc_attrs);
11461146
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcMustMatchExhaustively;
11471147
}
1148+
1149+
pub(crate) struct RustcCanonicalSymbolParser;
1150+
1151+
impl NoArgsAttributeParser for RustcCanonicalSymbolParser {
1152+
const PATH: &[Symbol] = &[sym::rustc_canonical_symbol];
1153+
const ALLOWED_TARGETS: AllowedTargets<'_> =
1154+
AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
1155+
const STABILITY: AttributeStability = unstable!(
1156+
rustc_attrs,
1157+
"the `#[rustc_canonical_symbol]` attribute registers a function's symbol to be linted against \
1158+
by the `invalid_runtime_symbol_definitions` and `suspicious_runtime_symbol_definitions` \
1159+
lints"
1160+
);
1161+
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCanonicalSymbol;
1162+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ attribute_parsers!(
275275
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
276276
Single<WithoutArgs<RustcAllowIncoherentImplParser>>,
277277
Single<WithoutArgs<RustcAsPtrParser>>,
278+
Single<WithoutArgs<RustcCanonicalSymbolParser>>,
278279
Single<WithoutArgs<RustcCaptureAnalysisParser>>,
279280
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
280281
Single<WithoutArgs<RustcCoinductiveParser>>,

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[
354354
sym::rustc_has_incoherent_inherent_impls,
355355
sym::rustc_non_const_trait_method,
356356

357+
sym::rustc_canonical_symbol,
357358
sym::rustc_diagnostic_item,
358359
sym::prelude_import,
359360
sym::rustc_paren_sugar,

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,10 @@ pub enum AttributeKind {
13721372
builtin_name: Option<Symbol>,
13731373
helper_attrs: ThinVec<Symbol>,
13741374
},
1375+
1376+
/// Represents `#[rustc_canonical_symbol]`
1377+
RustcCanonicalSymbol,
1378+
13751379
/// Represents `#[rustc_capture_analysis]`
13761380
RustcCaptureAnalysis,
13771381

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ impl AttributeKind {
110110
RustcAutodiff(..) => Yes,
111111
RustcBodyStability { .. } => No,
112112
RustcBuiltinMacro { .. } => Yes,
113+
RustcCanonicalSymbol => No,
113114
RustcCaptureAnalysis => No,
114115
RustcCguTestAttr { .. } => No,
115116
RustcClean { .. } => No,
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use rustc_data_structures::fx::FxIndexMap;
2+
use rustc_macros::{Encodable, StableHash};
3+
use rustc_span::Symbol;
4+
use rustc_span::def_id::DefId;
5+
6+
/// A representation of a canonical symbol
7+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, StableHash)]
8+
pub struct CanonicalSymbol {
9+
pub def_id: DefId,
10+
pub symbol: Symbol,
11+
}
12+
13+
#[derive(StableHash, Debug)]
14+
pub struct CanonicalSymbols {
15+
symbols: FxIndexMap<Symbol, CanonicalSymbol>,
16+
}
17+
18+
impl CanonicalSymbols {
19+
/// Construct an empty collection of canonical symbols
20+
pub fn new() -> Self {
21+
Self { symbols: FxIndexMap::default() }
22+
}
23+
24+
pub fn get(&self, symbol: Symbol) -> Option<CanonicalSymbol> {
25+
self.symbols.get(&symbol).copied()
26+
}
27+
28+
pub fn set(&mut self, symbol: Symbol, def_id: DefId) -> Option<DefId> {
29+
let preexisting = self.symbols.insert(symbol, CanonicalSymbol { def_id, symbol });
30+
31+
if let Some(preexisting) = preexisting {
32+
(preexisting.def_id != def_id).then_some(preexisting.def_id)
33+
} else {
34+
None
35+
}
36+
}
37+
38+
pub fn iter(&self) -> impl Iterator<Item = CanonicalSymbol> {
39+
self.symbols.values().copied()
40+
}
41+
}

compiler/rustc_hir/src/lang_items.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -453,22 +453,6 @@ language_item_table! {
453453

454454
// Used to fallback `{float}` to `f32` when `f32: From<{float}>`
455455
From, sym::From, from_trait, Target::Trait, GenericRequirement::Exact(1);
456-
457-
// Runtime symbols
458-
MemCpy, sym::memcpy_fn, memcpy_fn, Target::ForeignFn, GenericRequirement::None;
459-
MemMove, sym::memmove_fn, memmove_fn, Target::ForeignFn, GenericRequirement::None;
460-
MemSet, sym::memset_fn, memset_fn, Target::ForeignFn, GenericRequirement::None;
461-
MemCmp, sym::memcmp_fn, memcmp_fn, Target::ForeignFn, GenericRequirement::None;
462-
Bcmp, sym::bcmp_fn, bcmp_fn, Target::ForeignFn, GenericRequirement::None;
463-
StrLen, sym::strlen_fn, strlen_fn, Target::ForeignFn, GenericRequirement::None;
464-
Open, sym::open_fn, open_fn, Target::ForeignFn, GenericRequirement::None;
465-
Read, sym::read_fn, read_fn, Target::ForeignFn, GenericRequirement::None;
466-
Write, sym::write_fn, write_fn, Target::ForeignFn, GenericRequirement::None;
467-
Close, sym::close_fn, close_fn, Target::ForeignFn, GenericRequirement::None;
468-
Malloc, sym::malloc_fn, malloc_fn, Target::ForeignFn, GenericRequirement::None;
469-
Realloc, sym::realloc_fn, realloc_fn, Target::ForeignFn, GenericRequirement::None;
470-
Free, sym::free_fn, free_fn, Target::ForeignFn, GenericRequirement::None;
471-
Exit, sym::exit_fn, exit_fn, Target::ForeignFn, GenericRequirement::None;
472456
}
473457

474458
/// The requirement imposed on the generics of a lang item

compiler/rustc_hir/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ extern crate self as rustc_hir;
1919

2020
mod arena;
2121
pub mod attrs;
22+
pub mod canonical_symbols;
2223
pub mod def;
2324
pub mod def_path_hash_map;
2425
pub mod definitions;
@@ -39,6 +40,7 @@ pub mod weak_lang_items;
3940
#[cfg(test)]
4041
mod tests;
4142

43+
pub use canonical_symbols::{CanonicalSymbol, CanonicalSymbols};
4244
#[doc(no_inline)]
4345
pub use hir::*;
4446
pub use lang_items::{LangItem, LanguageItems};

compiler/rustc_hir/src/weak_lang_items.rs

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,34 +23,7 @@ macro_rules! weak_lang_items {
2323
}
2424
}
2525

26-
macro_rules! weak_only_lang_items {
27-
($($item:ident,)*) => {
28-
impl LangItem {
29-
pub fn is_weak_only(self) -> bool {
30-
matches!(self, $(LangItem::$item)|*)
31-
}
32-
}
33-
}
34-
}
35-
3626
weak_lang_items! {
3727
PanicImpl, rust_begin_unwind;
3828
EhPersonality, rust_eh_personality;
3929
}
40-
41-
weak_only_lang_items! {
42-
MemCpy,
43-
MemMove,
44-
MemSet,
45-
MemCmp,
46-
Bcmp,
47-
StrLen,
48-
Open,
49-
Read,
50-
Write,
51-
Close,
52-
Malloc,
53-
Realloc,
54-
Free,
55-
Exit,
56-
}

compiler/rustc_interface/src/passes.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
12441244
// diagnostic item. If the crate compiles without checking any diagnostic items,
12451245
// we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally.
12461246
let _ = tcx.all_diagnostic_items(());
1247+
1248+
// This query is only invoked normally if a diagnostic is emitted that needs any
1249+
// canonical symbol. If the crate compiles without checking any runtime symbols,
1250+
// we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally.
1251+
let _ = tcx.all_canonical_symbols(());
12471252
});
12481253

12491254
// If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item

0 commit comments

Comments
 (0)