summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_symbol_mangling
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_symbol_mangling
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_symbol_mangling')
-rw-r--r--compiler/rustc_symbol_mangling/Cargo.toml1
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs14
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs4
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid.rs91
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs338
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs5
7 files changed, 341 insertions, 114 deletions
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index 4e447eab0..052ef8bb9 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -15,6 +15,7 @@ twox-hash = "1.6.3"
rustc_span = { path = "../rustc_span" }
rustc_middle = { path = "../rustc_middle" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_target = { path = "../rustc_target" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 5cbca8192..254ede4e6 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
use rustc_hir::def_id::CrateNum;
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_middle::ty::print::{PrettyPrinter, Print, Printer};
@@ -93,7 +93,7 @@ fn get_symbol_hash<'tcx>(
item_type: Ty<'tcx>,
instantiating_crate: Option<CrateNum>,
-) -> u64 {
+) -> Hash64 {
let def_id = instance.def_id();
let substs = instance.substs;
debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
@@ -108,7 +108,7 @@ fn get_symbol_hash<'tcx>(
tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher);
// Include the main item-type. Note that, in this case, the
- // assertions about `needs_subst` may not hold, but this item-type
+ // assertions about `has_param` may not hold, but this item-type
// ought to be the same for every reference anyway.
assert!(!item_type.has_erasable_regions());
hcx.while_hashing_spans(false, |hcx| {
@@ -138,7 +138,7 @@ fn get_symbol_hash<'tcx>(
});
// 64 bits should be enough to avoid collisions.
- hasher.finish::<u64>()
+ hasher.finish::<Hash64>()
})
}
@@ -176,7 +176,7 @@ impl SymbolPath {
}
}
- fn finish(mut self, hash: u64) -> String {
+ fn finish(mut self, hash: Hash64) -> String {
self.finalize_pending_component();
// E = end name-sequence
let _ = write!(self.result, "17h{hash:016x}E");
@@ -220,7 +220,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> {
match *ty.kind() {
// Print all nominal types as paths (unlike `pretty_print_type`).
ty::FnDef(def_id, substs)
- | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. })
| ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
@@ -241,6 +241,8 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> {
Ok(self)
}
+ ty::Alias(ty::Inherent, _) => panic!("unexpected inherent projection"),
+
_ => self.pretty_print_type(ty),
}
}
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index c2fd3304f..692542da7 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -101,13 +101,13 @@ extern crate rustc_middle;
extern crate tracing;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
-use rustc_macros::fluent_messages;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Instance, TyCtxt};
use rustc_session::config::SymbolManglingVersion;
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index b4d5b7f36..985b22107 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -83,7 +83,7 @@ impl SymbolNamesTest<'_> {
tcx.sess.emit_err(TestOutput {
span: attr.span,
kind: Kind::DefPath,
- content: with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id())),
+ content: with_no_trimmed_paths!(tcx.def_path_str(def_id)),
});
}
}
diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs
index 53983bed7..cda16e3a3 100644
--- a/compiler/rustc_symbol_mangling/src/typeid.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid.rs
@@ -1,42 +1,87 @@
-// For more information about type metadata and type metadata identifiers for cross-language LLVM
-// CFI support, see Type metadata in the design document in the tracking issue #89653.
-
-use rustc_middle::ty::{FnSig, Ty, TyCtxt};
+/// Type metadata identifiers for LLVM Control Flow Integrity (CFI) and cross-language LLVM CFI
+/// support.
+///
+/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
+/// see design document in the tracking issue #89653.
+use bitflags::bitflags;
+use rustc_middle::ty::{FnSig, Instance, Ty, TyCtxt};
use rustc_target::abi::call::FnAbi;
use std::hash::Hasher;
use twox_hash::XxHash64;
+bitflags! {
+ /// Options for typeid_for_fnabi and typeid_for_fnsig.
+ pub struct TypeIdOptions: u32 {
+ const GENERALIZE_POINTERS = 1;
+ const GENERALIZE_REPR_C = 2;
+ const NORMALIZE_INTEGERS = 4;
+ }
+}
+
mod typeid_itanium_cxx_abi;
-use typeid_itanium_cxx_abi::TypeIdOptions;
/// Returns a type metadata identifier for the specified FnAbi.
-pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
- typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, TypeIdOptions::NO_OPTIONS)
+pub fn typeid_for_fnabi<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+ options: TypeIdOptions,
+) -> String {
+ typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options)
}
/// Returns a type metadata identifier for the specified FnSig.
-pub fn typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> String {
- typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS)
+pub fn typeid_for_fnsig<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ fn_sig: &FnSig<'tcx>,
+ options: TypeIdOptions,
+) -> String {
+ typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, options)
+}
+
+/// Returns a type metadata identifier for the specified Instance.
+pub fn typeid_for_instance<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: &Instance<'tcx>,
+ options: TypeIdOptions,
+) -> String {
+ typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options)
+}
+
+/// Returns a KCFI type metadata identifier for the specified FnAbi.
+pub fn kcfi_typeid_for_fnabi<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+ options: TypeIdOptions,
+) -> u32 {
+ // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
+ // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
+ let mut hash: XxHash64 = Default::default();
+ hash.write(typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options).as_bytes());
+ hash.finish() as u32
}
-/// Returns an LLVM KCFI type metadata identifier for the specified FnAbi.
-pub fn kcfi_typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> u32 {
- // An LLVM KCFI type metadata identifier is a 32-bit constant produced by taking the lower half
- // of the xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
+/// Returns a KCFI type metadata identifier for the specified FnSig.
+pub fn kcfi_typeid_for_fnsig<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ fn_sig: &FnSig<'tcx>,
+ options: TypeIdOptions,
+) -> u32 {
+ // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
+ // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
let mut hash: XxHash64 = Default::default();
- hash.write(
- typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, TypeIdOptions::NO_OPTIONS).as_bytes(),
- );
+ hash.write(typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, options).as_bytes());
hash.finish() as u32
}
-/// Returns an LLVM KCFI type metadata identifier for the specified FnSig.
-pub fn kcfi_typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> u32 {
- // An LLVM KCFI type metadata identifier is a 32-bit constant produced by taking the lower half
- // of the xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
+/// Returns a KCFI type metadata identifier for the specified Instance.
+pub fn kcfi_typeid_for_instance<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: &Instance<'tcx>,
+ options: TypeIdOptions,
+) -> u32 {
+ // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
+ // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
let mut hash: XxHash64 = Default::default();
- hash.write(
- typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS).as_bytes(),
- );
+ hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes());
hash.finish() as u32
}
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 1a679f32c..9fa49123a 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -1,26 +1,30 @@
-// For more information about type metadata and type metadata identifiers for cross-language LLVM
-// CFI support, see Type metadata in the design document in the tracking issue #89653.
-
-// FIXME(rcvalle): Identify C char and integer type uses and encode them with their respective
-// builtin type encodings as specified by the Itanium C++ ABI for extern function types with the "C"
-// calling convention to use this encoding for cross-language LLVM CFI.
-
-use bitflags::bitflags;
+/// Type metadata identifiers (using Itanium C++ ABI mangling for encoding) for LLVM Control Flow
+/// Integrity (CFI) and cross-language LLVM CFI support.
+///
+/// Encodes type metadata identifiers for LLVM CFI and cross-language LLVM CFI support using Itanium
+/// C++ ABI mangling for encoding with vendor extended type qualifiers and types for Rust types that
+/// are not used across the FFI boundary.
+///
+/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
+/// see design document in the tracking issue #89653.
use core::fmt::Display;
use rustc_data_structures::base_n;
use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::DiagnosticMessage;
use rustc_hir as hir;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{
- self, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind, TermKind,
- Ty, TyCtxt, UintTy,
+ self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind,
+ TermKind, Ty, TyCtxt, UintTy,
};
use rustc_span::def_id::DefId;
-use rustc_span::symbol::sym;
+use rustc_span::sym;
use rustc_target::abi::call::{Conv, FnAbi};
use rustc_target::spec::abi::Abi;
use std::fmt::Write as _;
+use crate::typeid::TypeIdOptions;
+
/// Type and extended type qualifiers.
#[derive(Eq, Hash, PartialEq)]
enum TyQ {
@@ -38,15 +42,6 @@ enum DictKey<'tcx> {
Predicate(ExistentialPredicate<'tcx>),
}
-bitflags! {
- /// Options for typeid_for_fnabi and typeid_for_fnsig.
- pub struct TypeIdOptions: u32 {
- const NO_OPTIONS = 0;
- const GENERALIZE_POINTERS = 1;
- const GENERALIZE_REPR_C = 2;
- }
-}
-
/// Options for encode_ty.
type EncodeTyOptions = TypeIdOptions;
@@ -91,21 +86,6 @@ fn compress<'tcx>(
}
}
-// FIXME(rcvalle): Move to compiler/rustc_middle/src/ty/sty.rs after C types work is done, possibly
-// along with other is_c_type methods.
-/// Returns whether a `ty::Ty` is `c_void`.
-fn is_c_void_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
- match ty.kind() {
- ty::Adt(adt_def, ..) => {
- let def_id = adt_def.0.did;
- let crate_name = tcx.crate_name(def_id.krate);
- tcx.item_name(def_id).as_str() == "c_void"
- && (crate_name == sym::core || crate_name == sym::std || crate_name == sym::libc)
- }
- _ => false,
- }
-}
-
/// Encodes a const using the Itanium C++ ABI as a literal argument (see
/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>).
fn encode_const<'tcx>(
@@ -292,12 +272,11 @@ fn encode_region<'tcx>(
s.push('E');
compress(dict, DictKey::Region(region), &mut s);
}
- RegionKind::ReErased => {
+ RegionKind::ReEarlyBound(..) | RegionKind::ReErased => {
s.push_str("u6region");
compress(dict, DictKey::Region(region), &mut s);
}
- RegionKind::ReEarlyBound(..)
- | RegionKind::ReFree(..)
+ RegionKind::ReFree(..)
| RegionKind::ReStatic
| RegionKind::ReError(_)
| RegionKind::ReVar(..)
@@ -406,7 +385,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
// Crate disambiguator and name
s.push('C');
- s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).to_u64()));
+ s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64()));
let crate_name = tcx.crate_name(def_path.krate).to_string();
let _ = write!(s, "{}{}", crate_name.len(), &crate_name);
@@ -448,6 +427,12 @@ fn encode_ty<'tcx>(
match ty.kind() {
// Primitive types
+
+ // Rust's bool has the same layout as C17's _Bool, that is, its size and alignment are
+ // implementation-defined. Any bool can be cast into an integer, taking on the values 1
+ // (true) or 0 (false).
+ //
+ // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
ty::Bool => {
typeid.push('b');
}
@@ -535,9 +520,33 @@ fn encode_ty<'tcx>(
// User-defined types
ty::Adt(adt_def, substs) => {
let mut s = String::new();
- let def_id = adt_def.0.did;
- if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
- // For cross-language CFI support, the encoding must be compatible at the FFI
+ let def_id = adt_def.did();
+ if let Some(cfi_encoding) = tcx.get_attr(def_id, sym::cfi_encoding) {
+ // Use user-defined CFI encoding for type
+ if let Some(value_str) = cfi_encoding.value_str() {
+ if !value_str.to_string().trim().is_empty() {
+ s.push_str(&value_str.to_string().trim());
+ } else {
+ #[allow(
+ rustc::diagnostic_outside_of_impl,
+ rustc::untranslatable_diagnostic
+ )]
+ tcx.sess
+ .struct_span_err(
+ cfi_encoding.span,
+ DiagnosticMessage::Str(format!(
+ "invalid `cfi_encoding` for `{:?}`",
+ ty.kind()
+ )),
+ )
+ .emit();
+ }
+ } else {
+ bug!("encode_ty: invalid `cfi_encoding` for `{:?}`", ty.kind());
+ }
+ compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+ } else if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
+ // For cross-language LLVM CFI support, the encoding must be compatible at the FFI
// boundary. For instance:
//
// struct type1 {};
@@ -567,8 +576,33 @@ fn encode_ty<'tcx>(
ty::Foreign(def_id) => {
// <length><name>, where <name> is <unscoped-name>
let mut s = String::new();
- let name = tcx.item_name(*def_id).to_string();
- let _ = write!(s, "{}{}", name.len(), &name);
+ if let Some(cfi_encoding) = tcx.get_attr(*def_id, sym::cfi_encoding) {
+ // Use user-defined CFI encoding for type
+ if let Some(value_str) = cfi_encoding.value_str() {
+ if !value_str.to_string().trim().is_empty() {
+ s.push_str(&value_str.to_string().trim());
+ } else {
+ #[allow(
+ rustc::diagnostic_outside_of_impl,
+ rustc::untranslatable_diagnostic
+ )]
+ tcx.sess
+ .struct_span_err(
+ cfi_encoding.span,
+ DiagnosticMessage::Str(format!(
+ "invalid `cfi_encoding` for `{:?}`",
+ ty.kind()
+ )),
+ )
+ .emit();
+ }
+ } else {
+ bug!("encode_ty: invalid `cfi_encoding` for `{:?}`", ty.kind());
+ }
+ } else {
+ let name = tcx.item_name(*def_id).to_string();
+ let _ = write!(s, "{}{}", name.len(), &name);
+ }
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
typeid.push_str(&s);
}
@@ -618,7 +652,7 @@ fn encode_ty<'tcx>(
ty::FnPtr(fn_sig) => {
// PF<return-type><parameter-type1..parameter-typeN>E
let mut s = String::from("P");
- s.push_str(&encode_fnsig(tcx, &fn_sig.skip_binder(), dict, TypeIdOptions::NO_OPTIONS));
+ s.push_str(&encode_fnsig(tcx, &fn_sig.skip_binder(), dict, TypeIdOptions::empty()));
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
typeid.push_str(&s);
}
@@ -638,6 +672,14 @@ fn encode_ty<'tcx>(
typeid.push_str(&s);
}
+ // Type parameters
+ ty::Param(..) => {
+ // u5param as vendor extended type
+ let mut s = String::from("u5param");
+ compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+ typeid.push_str(&s);
+ }
+
// Unexpected types
ty::Bound(..)
| ty::Error(..)
@@ -645,7 +687,6 @@ fn encode_ty<'tcx>(
| ty::GeneratorWitnessMIR(..)
| ty::Infer(..)
| ty::Alias(..)
- | ty::Param(..)
| ty::Placeholder(..) => {
bug!("encode_ty: unexpected `{:?}`", ty.kind());
}
@@ -654,23 +695,96 @@ fn encode_ty<'tcx>(
typeid
}
+/// Transforms predicates for being encoded and used in the substitution dictionary.
+fn transform_predicates<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ predicates: &List<ty::PolyExistentialPredicate<'tcx>>,
+ _options: EncodeTyOptions,
+) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> {
+ let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> = predicates
+ .iter()
+ .filter_map(|predicate| match predicate.skip_binder() {
+ ty::ExistentialPredicate::Trait(trait_ref) => {
+ let trait_ref = ty::TraitRef::identity(tcx, trait_ref.def_id);
+ Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait(
+ ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
+ )))
+ }
+ ty::ExistentialPredicate::Projection(..) => None,
+ ty::ExistentialPredicate::AutoTrait(..) => Some(predicate),
+ })
+ .collect();
+ tcx.mk_poly_existential_predicates(&predicates)
+}
+
+/// Transforms substs for being encoded and used in the substitution dictionary.
+fn transform_substs<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ substs: SubstsRef<'tcx>,
+ options: TransformTyOptions,
+) -> SubstsRef<'tcx> {
+ let substs = substs.iter().map(|subst| match subst.unpack() {
+ GenericArgKind::Type(ty) if ty.is_c_void(tcx) => tcx.mk_unit().into(),
+ GenericArgKind::Type(ty) => transform_ty(tcx, ty, options).into(),
+ _ => subst,
+ });
+ tcx.mk_substs_from_iter(substs)
+}
+
// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
-// c_void types into unit types unconditionally, and generalizes all pointers if
-// TransformTyOptions::GENERALIZE_POINTERS option is set.
-#[instrument(level = "trace", skip(tcx))]
+// c_void types into unit types unconditionally, generalizes pointers if
+// TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
+// TransformTyOptions::NORMALIZE_INTEGERS option is set.
fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> {
let mut ty = ty;
match ty.kind() {
- ty::Bool
- | ty::Int(..)
- | ty::Uint(..)
- | ty::Float(..)
- | ty::Char
- | ty::Str
- | ty::Never
- | ty::Foreign(..)
- | ty::Dynamic(..) => {}
+ ty::Float(..) | ty::Char | ty::Str | ty::Never | ty::Foreign(..) => {}
+
+ ty::Bool => {
+ if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+ // Note: on all platforms that Rust's currently supports, its size and alignment are
+ // 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
+ //
+ // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
+ //
+ // Clang represents bool as an 8-bit unsigned integer.
+ ty = tcx.types.u8;
+ }
+ }
+
+ ty::Int(..) | ty::Uint(..) => {
+ if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+ // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit wide.
+ // All platforms we currently support have a C platform, and as a consequence,
+ // isize/usize are at least 16-bit wide for all of them.
+ //
+ // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
+ match ty.kind() {
+ ty::Int(IntTy::Isize) => match tcx.sess.target.pointer_width {
+ 16 => ty = tcx.types.i16,
+ 32 => ty = tcx.types.i32,
+ 64 => ty = tcx.types.i64,
+ 128 => ty = tcx.types.i128,
+ _ => bug!(
+ "transform_ty: unexpected pointer width `{}`",
+ tcx.sess.target.pointer_width
+ ),
+ },
+ ty::Uint(UintTy::Usize) => match tcx.sess.target.pointer_width {
+ 16 => ty = tcx.types.u16,
+ 32 => ty = tcx.types.u32,
+ 64 => ty = tcx.types.u64,
+ 128 => ty = tcx.types.u128,
+ _ => bug!(
+ "transform_ty: unexpected pointer width `{}`",
+ tcx.sess.target.pointer_width
+ ),
+ },
+ _ => (),
+ }
+ }
+ }
_ if ty.is_unit() => {}
@@ -688,18 +802,23 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
}
ty::Adt(adt_def, substs) => {
- if is_c_void_ty(tcx, ty) {
+ if ty.is_c_void(tcx) {
ty = tcx.mk_unit();
} else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
{
ty = tcx.mk_adt(*adt_def, ty::List::empty());
} else if adt_def.repr().transparent() && adt_def.is_struct() {
+ // Don't transform repr(transparent) types with an user-defined CFI encoding to
+ // preserve the user-defined CFI encoding.
+ if let Some(_) = tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
+ return ty;
+ }
let variant = adt_def.non_enum_variant();
let param_env = tcx.param_env(variant.def_id);
let field = variant.fields.iter().find(|field| {
let ty = tcx.type_of(field.did).subst_identity();
let is_zst =
- tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.is_zst());
+ tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.is_zst());
!is_zst
});
if let Some(field) = field {
@@ -793,6 +912,14 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
}
}
+ ty::Dynamic(predicates, _region, kind) => {
+ ty = tcx.mk_dynamic(
+ transform_predicates(tcx, predicates, options),
+ tcx.lifetimes.re_erased,
+ *kind,
+ );
+ }
+
ty::Bound(..)
| ty::Error(..)
| ty::GeneratorWitness(..)
@@ -808,26 +935,6 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
ty
}
-/// Transforms substs for being encoded and used in the substitution dictionary.
-fn transform_substs<'tcx>(
- tcx: TyCtxt<'tcx>,
- substs: SubstsRef<'tcx>,
- options: TransformTyOptions,
-) -> SubstsRef<'tcx> {
- let substs = substs.iter().map(|subst| {
- if let GenericArgKind::Type(ty) = subst.unpack() {
- if is_c_void_ty(tcx, ty) {
- tcx.mk_unit().into()
- } else {
- transform_ty(tcx, ty, options).into()
- }
- } else {
- subst
- }
- });
- tcx.mk_substs_from_iter(substs)
-}
-
/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
/// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
#[instrument(level = "trace", skip(tcx))]
@@ -893,6 +1000,15 @@ pub fn typeid_for_fnabi<'tcx>(
// Close the "F..E" pair
typeid.push('E');
+ // Add encoding suffixes
+ if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+ typeid.push_str(".normalized");
+ }
+
+ if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) {
+ typeid.push_str(".generalized");
+ }
+
typeid
}
@@ -919,5 +1035,67 @@ pub fn typeid_for_fnsig<'tcx>(
// Encode the function signature
typeid.push_str(&encode_fnsig(tcx, fn_sig, &mut dict, options));
+ // Add encoding suffixes
+ if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+ typeid.push_str(".normalized");
+ }
+
+ if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) {
+ typeid.push_str(".generalized");
+ }
+
typeid
}
+
+/// Returns a type metadata identifier for the specified Instance using the Itanium C++ ABI with
+/// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary.
+pub fn typeid_for_instance<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: &Instance<'tcx>,
+ options: TypeIdOptions,
+) -> String {
+ let fn_abi = tcx
+ .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((*instance, ty::List::empty())))
+ .unwrap_or_else(|instance| {
+ bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance)
+ });
+
+ // If this instance is a method and self is a reference, get the impl it belongs to
+ let impl_def_id = tcx.impl_of_method(instance.def_id());
+ if impl_def_id.is_some() && !fn_abi.args.is_empty() && fn_abi.args[0].layout.ty.is_ref() {
+ // If this impl is not an inherent impl, get the trait it implements
+ if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id.unwrap()) {
+ // Transform the concrete self into a reference to a trait object
+ let existential_predicate = trait_ref.map_bound(|trait_ref| {
+ ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
+ tcx, trait_ref,
+ ))
+ });
+ let existential_predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(
+ existential_predicate.skip_binder(),
+ )]);
+ // Is the concrete self mutable?
+ let self_ty = if fn_abi.args[0].layout.ty.is_mutable_ptr() {
+ tcx.mk_mut_ref(
+ tcx.lifetimes.re_erased,
+ tcx.mk_dynamic(existential_predicates, tcx.lifetimes.re_erased, ty::Dyn),
+ )
+ } else {
+ tcx.mk_imm_ref(
+ tcx.lifetimes.re_erased,
+ tcx.mk_dynamic(existential_predicates, tcx.lifetimes.re_erased, ty::Dyn),
+ )
+ };
+
+ // Replace the concrete self in an fn_abi clone by the reference to a trait object
+ let mut fn_abi = fn_abi.clone();
+ // HACK(rcvalle): It is okay to not replace or update the entire ArgAbi here because the
+ // other fields are never used.
+ fn_abi.args[0].layout.ty = self_ty;
+
+ return typeid_for_fnabi(tcx, &fn_abi, options);
+ }
+ }
+
+ typeid_for_fnabi(tcx, &fn_abi, options)
+}
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index ee8832855..4cccc6398 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -433,7 +433,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
// Mangle all nominal types as paths.
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
| ty::FnDef(def_id, substs)
- | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. })
| ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, _) => {
self = self.print_def_path(def_id, substs)?;
@@ -482,6 +482,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
self = r.print(self)?;
}
+ ty::Alias(ty::Inherent, _) => bug!("symbol_names: unexpected inherent projection"),
ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"),
ty::GeneratorWitnessMIR(..) => bug!("symbol_names: unexpected `GeneratorWitnessMIR`"),
}
@@ -731,7 +732,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
self.push("C");
let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
- self.push_disambiguator(stable_crate_id.to_u64());
+ self.push_disambiguator(stable_crate_id.as_u64());
let name = self.tcx.crate_name(cnum);
self.push_ident(name.as_str());
Ok(self)