diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:42 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:42 +0000 |
commit | 837b550238aa671a591ccf282dddeab29cadb206 (patch) | |
tree | 914b6b8862bace72bd3245ca184d374b08d8a672 /compiler/rustc_symbol_mangling | |
parent | Adding debian version 1.70.0+dfsg2-1. (diff) | |
download | rustc-837b550238aa671a591ccf282dddeab29cadb206.tar.xz rustc-837b550238aa671a591ccf282dddeab29cadb206.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.toml | 1 | ||||
-rw-r--r-- | compiler/rustc_symbol_mangling/src/legacy.rs | 14 | ||||
-rw-r--r-- | compiler/rustc_symbol_mangling/src/lib.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_symbol_mangling/src/test.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_symbol_mangling/src/typeid.rs | 91 | ||||
-rw-r--r-- | compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs | 338 | ||||
-rw-r--r-- | compiler/rustc_symbol_mangling/src/v0.rs | 5 |
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) |