Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ impl SingleAttributeParser for LangParser {
// Only weak lang items may be applied to foreign items
if [Target::ForeignFn, Target::ForeignStatic, Target::ForeignTy, Target::ForeignMod]
.contains(&cx.target)
&& !(lang_item.is_weak() || lang_item.is_weak_only())
&& !lang_item.is_weak()
{
cx.emit_err(UnknownExternLangItem { span: cx.attr_span, lang_item: lang_item.name() });
return None;
Expand Down Expand Up @@ -1145,3 +1145,18 @@ impl NoArgsAttributeParser for RustcExhaustiveParser {
const STABILITY: AttributeStability = unstable!(rustc_attrs);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcMustMatchExhaustively;
}

pub(crate) struct RustcCanonicalSymbolParser;

impl NoArgsAttributeParser for RustcCanonicalSymbolParser {
const PATH: &[Symbol] = &[sym::rustc_canonical_symbol];
const ALLOWED_TARGETS: AllowedTargets<'_> =
AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
const STABILITY: AttributeStability = unstable!(
rustc_attrs,
"the `#[rustc_canonical_symbol]` attribute registers a function's symbol to be linted against \
by the `invalid_runtime_symbol_definitions` and `suspicious_runtime_symbol_definitions` \
lints"
);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCanonicalSymbol;
}
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ attribute_parsers!(
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
Single<WithoutArgs<RustcAllowIncoherentImplParser>>,
Single<WithoutArgs<RustcAsPtrParser>>,
Single<WithoutArgs<RustcCanonicalSymbolParser>>,
Single<WithoutArgs<RustcCaptureAnalysisParser>>,
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
Single<WithoutArgs<RustcCoinductiveParser>>,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[
sym::rustc_has_incoherent_inherent_impls,
sym::rustc_non_const_trait_method,

sym::rustc_canonical_symbol,
sym::rustc_diagnostic_item,
sym::prelude_import,
sym::rustc_paren_sugar,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,10 @@ pub enum AttributeKind {
builtin_name: Option<Symbol>,
helper_attrs: ThinVec<Symbol>,
},

/// Represents `#[rustc_canonical_symbol]`
RustcCanonicalSymbol,

/// Represents `#[rustc_capture_analysis]`
RustcCaptureAnalysis,

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ impl AttributeKind {
RustcAutodiff(..) => Yes,
RustcBodyStability { .. } => No,
RustcBuiltinMacro { .. } => Yes,
RustcCanonicalSymbol => No,
RustcCaptureAnalysis => No,
RustcCguTestAttr { .. } => No,
RustcClean { .. } => No,
Expand Down
41 changes: 41 additions & 0 deletions compiler/rustc_hir/src/canonical_symbols.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_macros::{Encodable, StableHash};
use rustc_span::Symbol;
use rustc_span::def_id::DefId;

/// A representation of a canonical symbol
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, StableHash)]
pub struct CanonicalSymbol {
pub def_id: DefId,
pub symbol: Symbol,
}

#[derive(StableHash, Debug)]
pub struct CanonicalSymbols {
symbols: FxIndexMap<Symbol, CanonicalSymbol>,
}

impl CanonicalSymbols {
/// Construct an empty collection of canonical symbols
pub fn new() -> Self {
Self { symbols: FxIndexMap::default() }
}

pub fn get(&self, symbol: Symbol) -> Option<CanonicalSymbol> {
self.symbols.get(&symbol).copied()
}

pub fn set(&mut self, symbol: Symbol, def_id: DefId) -> Option<DefId> {
let preexisting = self.symbols.insert(symbol, CanonicalSymbol { def_id, symbol });

if let Some(preexisting) = preexisting {
(preexisting.def_id != def_id).then_some(preexisting.def_id)
} else {
None
}
}

pub fn iter(&self) -> impl Iterator<Item = CanonicalSymbol> {
self.symbols.values().copied()
}
}
16 changes: 0 additions & 16 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,22 +453,6 @@ language_item_table! {

// Used to fallback `{float}` to `f32` when `f32: From<{float}>`
From, sym::From, from_trait, Target::Trait, GenericRequirement::Exact(1);

// Runtime symbols
MemCpy, sym::memcpy_fn, memcpy_fn, Target::ForeignFn, GenericRequirement::None;
MemMove, sym::memmove_fn, memmove_fn, Target::ForeignFn, GenericRequirement::None;
MemSet, sym::memset_fn, memset_fn, Target::ForeignFn, GenericRequirement::None;
MemCmp, sym::memcmp_fn, memcmp_fn, Target::ForeignFn, GenericRequirement::None;
Bcmp, sym::bcmp_fn, bcmp_fn, Target::ForeignFn, GenericRequirement::None;
StrLen, sym::strlen_fn, strlen_fn, Target::ForeignFn, GenericRequirement::None;
Open, sym::open_fn, open_fn, Target::ForeignFn, GenericRequirement::None;
Read, sym::read_fn, read_fn, Target::ForeignFn, GenericRequirement::None;
Write, sym::write_fn, write_fn, Target::ForeignFn, GenericRequirement::None;
Close, sym::close_fn, close_fn, Target::ForeignFn, GenericRequirement::None;
Malloc, sym::malloc_fn, malloc_fn, Target::ForeignFn, GenericRequirement::None;
Realloc, sym::realloc_fn, realloc_fn, Target::ForeignFn, GenericRequirement::None;
Free, sym::free_fn, free_fn, Target::ForeignFn, GenericRequirement::None;
Exit, sym::exit_fn, exit_fn, Target::ForeignFn, GenericRequirement::None;
}

/// The requirement imposed on the generics of a lang item
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ extern crate self as rustc_hir;

mod arena;
pub mod attrs;
pub mod canonical_symbols;
pub mod def;
pub mod def_path_hash_map;
pub mod definitions;
Expand All @@ -39,6 +40,7 @@ pub mod weak_lang_items;
#[cfg(test)]
mod tests;

pub use canonical_symbols::{CanonicalSymbol, CanonicalSymbols};
#[doc(no_inline)]
pub use hir::*;
pub use lang_items::{LangItem, LanguageItems};
Expand Down
27 changes: 0 additions & 27 deletions compiler/rustc_hir/src/weak_lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,7 @@ macro_rules! weak_lang_items {
}
}

macro_rules! weak_only_lang_items {
($($item:ident,)*) => {
impl LangItem {
pub fn is_weak_only(self) -> bool {
matches!(self, $(LangItem::$item)|*)
}
}
}
}

weak_lang_items! {
PanicImpl, rust_begin_unwind;
EhPersonality, rust_eh_personality;
}

weak_only_lang_items! {
MemCpy,
MemMove,
MemSet,
MemCmp,
Bcmp,
StrLen,
Open,
Read,
Write,
Close,
Malloc,
Realloc,
Free,
Exit,
}
5 changes: 5 additions & 0 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
// diagnostic item. If the crate compiles without checking any diagnostic items,
// we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally.
let _ = tcx.all_diagnostic_items(());

// This query is only invoked normally if a diagnostic is emitted that needs any
// canonical symbol. If the crate compiles without checking any runtime symbols,
// we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally.
let _ = tcx.all_canonical_symbols(());
});

// If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item
Expand Down
51 changes: 11 additions & 40 deletions compiler/rustc_lint/src/runtime_symbols.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, FnSig, ForeignItemKind, LanguageItems};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{self as hir, CanonicalSymbol, FnSig, ForeignItemKind};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_session::{declare_lint, declare_lint_pass};
use rustc_span::Span;
use rustc_span::{Span, Symbol};
use rustc_trait_selection::infer::TyCtxtInferExt;

use crate::lints::RedefiningRuntimeSymbolsDiag;
Expand Down Expand Up @@ -73,31 +73,6 @@ declare_lint! {

declare_lint_pass!(RuntimeSymbols => [INVALID_RUNTIME_SYMBOL_DEFINITIONS, SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS]);

static EXPECTED_SYMBOLS: &[ExpectedSymbol] = &[
// `core` symbols
ExpectedSymbol { symbol: "memcpy", lang: LanguageItems::memcpy_fn },
ExpectedSymbol { symbol: "memmove", lang: LanguageItems::memmove_fn },
ExpectedSymbol { symbol: "memset", lang: LanguageItems::memset_fn },
ExpectedSymbol { symbol: "memcmp", lang: LanguageItems::memcmp_fn },
ExpectedSymbol { symbol: "bcmp", lang: LanguageItems::bcmp_fn },
ExpectedSymbol { symbol: "strlen", lang: LanguageItems::strlen_fn },
// POSIX symbols
ExpectedSymbol { symbol: "open", lang: LanguageItems::open_fn },
ExpectedSymbol { symbol: "read", lang: LanguageItems::read_fn },
ExpectedSymbol { symbol: "write", lang: LanguageItems::write_fn },
ExpectedSymbol { symbol: "close", lang: LanguageItems::close_fn },
ExpectedSymbol { symbol: "malloc", lang: LanguageItems::malloc_fn },
ExpectedSymbol { symbol: "realloc", lang: LanguageItems::realloc_fn },
ExpectedSymbol { symbol: "free", lang: LanguageItems::free_fn },
ExpectedSymbol { symbol: "exit", lang: LanguageItems::exit_fn },
];

#[derive(Copy, Clone, Debug)]
struct ExpectedSymbol {
symbol: &'static str,
lang: fn(&LanguageItems) -> Option<DefId>,
}

impl<'tcx> LateLintPass<'tcx> for RuntimeSymbols {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
// Bail-out if the item is not a function/method or static.
Expand Down Expand Up @@ -162,16 +137,14 @@ impl<'tcx> LateLintPass<'tcx> for RuntimeSymbols {
}

fn check_fn(cx: &LateContext<'_>, symbol_name: &str, sig: FnSig<'_>, did: LocalDefId) {
let Some(expected_symbol) = EXPECTED_SYMBOLS.iter().find(|es| es.symbol == symbol_name) else {
let s = Symbol::intern(symbol_name);
let Some(CanonicalSymbol { symbol: _, def_id: expected_def_id }) =
cx.tcx.all_canonical_symbols(()).iter().find(|cs| cs.symbol == s)
else {
// The symbol name does not correspond to a runtime symbols, bail out
return;
};

let Some(expected_def_id) = (expected_symbol.lang)(&cx.tcx.lang_items()) else {
// Can't find the corresponding language item, bail out
return;
};

// Get the two function signatures
let lang_sig = cx.tcx.normalize_erasing_regions(
cx.typing_env(),
Expand Down Expand Up @@ -222,16 +195,14 @@ fn check_fn(cx: &LateContext<'_>, symbol_name: &str, sig: FnSig<'_>, did: LocalD
}

fn check_static<'tcx>(cx: &LateContext<'tcx>, symbol_name: &str, did: LocalDefId, sp: Span) {
let Some(expected_symbol) = EXPECTED_SYMBOLS.iter().find(|es| es.symbol == symbol_name) else {
let s = Symbol::intern(symbol_name);
let Some(CanonicalSymbol { symbol: _, def_id: expected_def_id }) =
cx.tcx.all_canonical_symbols(()).iter().find(|cs| cs.symbol == s)
else {
// The symbol name does not correspond to a runtime symbols, bail out
return;
};

let Some(expected_def_id) = (expected_symbol.lang)(&cx.tcx.lang_items()) else {
// Can't find the corresponding language item, bail out
return;
};

// Get the static type
let static_ty = cx.tcx.type_of(did).instantiate_identity().skip_norm_wip();

Expand Down
14 changes: 13 additions & 1 deletion compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ use rustc_data_structures::sync::Lock;
use rustc_data_structures::unhash::UnhashMap;
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro};
use rustc_hir::Safety;
use rustc_hir::def::Res;
use rustc_hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefPath, DefPathData};
use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_hir::{CanonicalSymbols, Safety};
use rustc_index::Idx;
use rustc_middle::middle::lib_features::LibFeatures;
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
Expand Down Expand Up @@ -1263,6 +1263,18 @@ impl CrateMetadata {
DiagnosticItems { id_to_name, name_to_id }
}

/// Iterates over the canonical_symbols in the given crate.
fn get_canonical_symbols(&self, tcx: TyCtxt<'_>) -> CanonicalSymbols {
let mut canonical_symbols = CanonicalSymbols::new();

for (name, def_index) in self.root.canonical_symbols.decode((self, tcx)) {
let id = self.local_def_id(def_index);
let _ = canonical_symbols.set(name, id);
}

canonical_symbols
}

fn get_mod_child(&self, tcx: TyCtxt<'_>, id: DefIndex) -> ModChild {
let ident = self.item_ident(tcx, id);
let res = Res::Def(self.def_kind(id), self.local_def_id(id));
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ provide! { tcx, def_id, other, cdata,
intrinsic_raw => { cdata.get_intrinsic(tcx, def_id.index) }
defined_lang_items => { cdata.get_lang_items(tcx) }
diagnostic_items => { cdata.get_diagnostic_items(tcx) }
canonical_symbols => { cdata.get_canonical_symbols(tcx) }
missing_lang_items => { cdata.get_missing_lang_items(tcx) }

missing_extern_crate_item => {
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {

let diagnostic_items = stat!("diagnostic-items", || self.encode_diagnostic_items());

let canonical_symbols = stat!("canonical-symbols", || self.encode_canonical_symbols());

let native_libraries = stat!("native-libs", || self.encode_native_libraries());

let foreign_modules = stat!("foreign-modules", || self.encode_foreign_modules());
Expand Down Expand Up @@ -757,6 +759,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
stability_implications,
lang_items,
diagnostic_items,
canonical_symbols,
lang_items_missing,
stripped_cfg_items,
native_libraries,
Expand Down Expand Up @@ -2134,6 +2137,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
self.lazy_array(sorted.into_iter().map(|(k, v)| (*k, *v)))
}

fn encode_canonical_symbols(&mut self) -> LazyArray<(Symbol, DefIndex)> {
empty_proc_macro!(self);
let tcx = self.tcx;
let canonical_symbols = &tcx.canonical_symbols(LOCAL_CRATE);
self.lazy_array(canonical_symbols.iter().map(|cs| (cs.symbol, cs.def_id.index)))
}

fn encode_diagnostic_items(&mut self) -> LazyArray<(Symbol, DefIndex)> {
empty_proc_macro!(self);
let tcx = self.tcx;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ pub(crate) struct CrateRoot {
lang_items_missing: LazyArray<LangItem>,
stripped_cfg_items: LazyArray<StrippedCfgItem<DefIndex>>,
diagnostic_items: LazyArray<(Symbol, DefIndex)>,
canonical_symbols: LazyArray<(Symbol, DefIndex)>,
native_libraries: LazyArray<NativeLib>,
foreign_modules: LazyArray<ForeignModule>,
traits: LazyArray<DefIndex>,
Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_middle/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::{ErrorGuaranteed, catch_fatal_errors};
use rustc_hir as hir;
use rustc_hir::attrs::{EiiDecl, EiiImpl, StrippedCfgItem};
use rustc_hir::canonical_symbols::CanonicalSymbols;
use rustc_hir::def::{DefKind, DocLinkResMap};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdSet, LocalModId};
use rustc_hir::lang_items::{LangItem, LanguageItems};
Expand Down Expand Up @@ -2262,6 +2263,13 @@ rustc_queries! {
desc { "calculating the diagnostic items map" }
}

/// Returns all the canonical symbols defined in all crates.
query all_canonical_symbols(_: ()) -> &'tcx CanonicalSymbols {
arena_cache
eval_always
desc { "calculating the canonical symbols map" }
}

/// Returns the lang items defined in another crate by loading it from metadata.
query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, LangItem)] {
desc { "calculating the lang items defined in a crate" }
Expand All @@ -2275,6 +2283,13 @@ rustc_queries! {
separate_provide_extern
}

/// Returns the canonical symbols defined in a crate.
query canonical_symbols(_: CrateNum) -> &'tcx CanonicalSymbols {
arena_cache
desc { "calculating the canonical symbols map in a crate" }
separate_provide_extern
}

query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] {
desc { "calculating the missing lang items in a crate" }
separate_provide_extern
Expand Down
Loading
Loading