mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 07:34:45 +01:00
Fix mangling collision for C++ class template specializations (#7269)
Carbon-side thunks (for example the `Copy`/`Destroy` witness thunks generated for imported C++ types) are mangled by Carbon, and their names incorporate a fingerprint of the involved types. The instruction fingerprinter identifies a class only by its name and parent scope, which is sufficient for Carbon classes but not for imported C++ classes: different specializations of one class template (and other cases such as types in anonymous namespaces) share a Carbon name and parent scope. As a result, the thunks for two distinct specializations could mangle to the same name, producing a single LLVM function with two definitions and failing `verifyModule` during lowering. When fingerprinting a class imported from C++, also include the Clang mangled name of its type. Test: toolchain/lower/testdata/interop/cpp/thunks.carbon gains a split with two specializations of one class template, each requiring a thunk; their thunks now get distinct mangled names instead of colliding. Assisted-by: Claude Code --------- Co-authored-by: Christopher Di Bella <cjdb.ns@gmail.com>
This commit is contained in:
co-authored by
Christopher Di Bella
parent
3ef128ac91
commit
8a59f2a76b
+26
-26
@@ -209,7 +209,7 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT: %PublicDestructor: type = class_type @PublicDestructor [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.512: type = pattern_type %PublicDestructor [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.c53: type = pattern_type %PublicDestructor [concrete]
|
||||
// CHECK:STDOUT: %empty_struct: %empty_struct_type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %PublicDestructor.val: %PublicDestructor = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Destroy.type: type = facet_type <@Destroy> [concrete]
|
||||
@@ -222,11 +222,11 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT: %TrivialDestroy.type: type = fn_type @TrivialDestroy [concrete]
|
||||
// CHECK:STDOUT: %TrivialDestroy: %TrivialDestroy.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %TrivialDestructor: type = class_type @TrivialDestructor [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.2d3: type = pattern_type %TrivialDestructor [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.322: type = pattern_type %TrivialDestructor [concrete]
|
||||
// CHECK:STDOUT: %TrivialDestructor.val: %TrivialDestructor = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %TrivialDestructor.cpp_destructor.type: type = fn_type @TrivialDestructor.cpp_destructor [concrete]
|
||||
// CHECK:STDOUT: %TrivialDestructor.cpp_destructor: %TrivialDestructor.cpp_destructor.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Destroy.facet.c9e: %Destroy.type = facet_value %TrivialDestructor, (%custom_witness.cc4) [concrete]
|
||||
// CHECK:STDOUT: %Destroy.facet.b4f: %Destroy.type = facet_value %TrivialDestructor, (%custom_witness.cc4) [concrete]
|
||||
// CHECK:STDOUT: %TrivialDestructor.Op.type: type = fn_type @TrivialDestructor.Op [concrete]
|
||||
// CHECK:STDOUT: %TrivialDestructor.Op: %TrivialDestructor.Op.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
@@ -247,8 +247,8 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT: %Destroy.WithSelf.Op.decl: %Destroy.WithSelf.Op.type.12b = fn_decl @Destroy.WithSelf.Op [symbolic = @Destroy.WithSelf.%Destroy.WithSelf.Op (constants.%Destroy.WithSelf.Op.73c)] {} {}
|
||||
// CHECK:STDOUT: %TrivialDestructor.decl: type = class_decl @TrivialDestructor [concrete = constants.%TrivialDestructor] {} {}
|
||||
// CHECK:STDOUT: %TrivialDestructor.cpp_destructor.decl: %TrivialDestructor.cpp_destructor.type = fn_decl @TrivialDestructor.cpp_destructor [concrete = constants.%TrivialDestructor.cpp_destructor] {
|
||||
// CHECK:STDOUT: %self.param_patt: %pattern_type.2d3 = ref_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %self.patt: %pattern_type.2d3 = at_binding_pattern self, %self.param_patt [concrete]
|
||||
// CHECK:STDOUT: %self.param_patt: %pattern_type.322 = ref_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %self.patt: %pattern_type.322 = at_binding_pattern self, %self.param_patt [concrete]
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: %self.param: ref %TrivialDestructor = ref_param call_param0
|
||||
// CHECK:STDOUT: %self: ref %TrivialDestructor = ref_binding self, %self.param
|
||||
@@ -291,8 +291,8 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT: fn @PublicDestroy() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %a.patt: %pattern_type.512 = ref_binding_pattern a [concrete]
|
||||
// CHECK:STDOUT: %a.var_patt: %pattern_type.512 = var_pattern %a.patt [concrete]
|
||||
// CHECK:STDOUT: %a.patt: %pattern_type.c53 = ref_binding_pattern a [concrete]
|
||||
// CHECK:STDOUT: %a.var_patt: %pattern_type.c53 = var_pattern %a.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %a.var: ref %PublicDestructor = var %a.var_patt
|
||||
// CHECK:STDOUT: %.loc11_41.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
|
||||
@@ -314,8 +314,8 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT: fn @TrivialDestroy() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %a.patt: %pattern_type.2d3 = ref_binding_pattern a [concrete]
|
||||
// CHECK:STDOUT: %a.var_patt: %pattern_type.2d3 = var_pattern %a.patt [concrete]
|
||||
// CHECK:STDOUT: %a.patt: %pattern_type.322 = ref_binding_pattern a [concrete]
|
||||
// CHECK:STDOUT: %a.var_patt: %pattern_type.322 = var_pattern %a.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %a.var: ref %TrivialDestructor = var %a.var_patt
|
||||
// CHECK:STDOUT: %.loc15_42.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
|
||||
@@ -328,8 +328,8 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %a: ref %TrivialDestructor = ref_binding a, %a.var
|
||||
// CHECK:STDOUT: %TrivialDestructor.Op.decl: %TrivialDestructor.Op.type = fn_decl @TrivialDestructor.Op [concrete = constants.%TrivialDestructor.Op] {
|
||||
// CHECK:STDOUT: %self.param_patt: %pattern_type.2d3 = ref_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %self.patt: %pattern_type.2d3 = at_binding_pattern self, %self.param_patt [concrete]
|
||||
// CHECK:STDOUT: %self.param_patt: %pattern_type.322 = ref_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %self.patt: %pattern_type.322 = at_binding_pattern self, %self.param_patt [concrete]
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: %self.param: ref %TrivialDestructor = ref_param call_param0
|
||||
// CHECK:STDOUT: %self: ref %TrivialDestructor = ref_binding self, %self.param
|
||||
@@ -343,7 +343,7 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @TrivialDestructor.cpp_destructor(%self.param: ref %TrivialDestructor) = "no_op";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @TrivialDestructor.Op(%self.param: ref %TrivialDestructor) [thunk imports.%TrivialDestructor.cpp_destructor.decl for imports.%Destroy.WithSelf.Op.decl, @Destroy.WithSelf.Op(constants.%Destroy.facet.c9e)] {
|
||||
// CHECK:STDOUT: fn @TrivialDestructor.Op(%self.param: ref %TrivialDestructor) [thunk imports.%TrivialDestructor.cpp_destructor.decl for imports.%Destroy.WithSelf.Op.decl, @Destroy.WithSelf.Op(constants.%Destroy.facet.b4f)] {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Op.ref: %TrivialDestructor.cpp_destructor.type = name_ref Op, imports.%TrivialDestructor.cpp_destructor.decl [concrete = constants.%TrivialDestructor.cpp_destructor]
|
||||
// CHECK:STDOUT: %TrivialDestructor.cpp_destructor.bound: <bound method> = bound_method %self.param, %Op.ref
|
||||
@@ -358,13 +358,13 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT: %ProtectedDestructor: type = class_type @ProtectedDestructor [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %struct_type.base.ebf: type = struct_type {.base: %ProtectedDestructor} [concrete]
|
||||
// CHECK:STDOUT: %struct_type.base.233: type = struct_type {.base: %ProtectedDestructor} [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.e25: type = pattern_type %Derived [concrete]
|
||||
// CHECK:STDOUT: %empty_struct.a40: %empty_struct_type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %struct_type.base.f5e: type = struct_type {.base: %empty_struct_type} [concrete]
|
||||
// CHECK:STDOUT: %struct: %struct_type.base.f5e = struct_value (%empty_struct.a40) [concrete]
|
||||
// CHECK:STDOUT: %.46a: type = partial_type %ProtectedDestructor [concrete]
|
||||
// CHECK:STDOUT: %empty_struct.73e: %.46a = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %.1d0: type = partial_type %ProtectedDestructor [concrete]
|
||||
// CHECK:STDOUT: %empty_struct.724: %.1d0 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %ProtectedDestructor.val: %ProtectedDestructor = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Derived.val: %Derived = struct_value (%ProtectedDestructor.val) [concrete]
|
||||
// CHECK:STDOUT: %Destroy.Op.type.af7ec0.2: type = fn_type @Destroy.Op.loc20_3.2 [concrete]
|
||||
@@ -380,9 +380,9 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT: %a.var: ref %Derived = var %a.var_patt
|
||||
// CHECK:STDOUT: %.loc20_37.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct.a40]
|
||||
// CHECK:STDOUT: %.loc20_38.1: %struct_type.base.f5e = struct_literal (%.loc20_37.1) [concrete = constants.%struct]
|
||||
// CHECK:STDOUT: %.loc20_38.2: ref %.46a = class_element_access %a.var, element0
|
||||
// CHECK:STDOUT: %.loc20_37.2: init %.46a to %.loc20_38.2 = class_init () [concrete = constants.%empty_struct.73e]
|
||||
// CHECK:STDOUT: %.loc20_38.3: init %.46a = converted %.loc20_37.1, %.loc20_37.2 [concrete = constants.%empty_struct.73e]
|
||||
// CHECK:STDOUT: %.loc20_38.2: ref %.1d0 = class_element_access %a.var, element0
|
||||
// CHECK:STDOUT: %.loc20_37.2: init %.1d0 to %.loc20_38.2 = class_init () [concrete = constants.%empty_struct.724]
|
||||
// CHECK:STDOUT: %.loc20_38.3: init %.1d0 = converted %.loc20_37.1, %.loc20_37.2 [concrete = constants.%empty_struct.724]
|
||||
// CHECK:STDOUT: %.loc20_38.4: init %ProtectedDestructor = as_compatible %.loc20_38.3 [concrete = constants.%ProtectedDestructor.val]
|
||||
// CHECK:STDOUT: %.loc20_38.5: init %Derived to %a.var = class_init (%.loc20_38.4) [concrete = constants.%Derived.val]
|
||||
// CHECK:STDOUT: %.loc20_3: init %Derived = converted %.loc20_38.1, %.loc20_38.5 [concrete = constants.%Derived.val]
|
||||
@@ -394,7 +394,7 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Destroy.Op.loc20_3.1(%self.param: ref %struct_type.base.ebf) {
|
||||
// CHECK:STDOUT: fn @Destroy.Op.loc20_3.1(%self.param: ref %struct_type.base.233) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
@@ -411,13 +411,13 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT: %PrivateDestructor: type = class_type @PrivateDestructor [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %struct_type.base.59d: type = struct_type {.base: %PrivateDestructor} [concrete]
|
||||
// CHECK:STDOUT: %struct_type.base.dea: type = struct_type {.base: %PrivateDestructor} [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.377: type = pattern_type %Derived [concrete]
|
||||
// CHECK:STDOUT: %empty_struct.a40: %empty_struct_type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %struct_type.base.f5e: type = struct_type {.base: %empty_struct_type} [concrete]
|
||||
// CHECK:STDOUT: %struct: %struct_type.base.f5e = struct_value (%empty_struct.a40) [concrete]
|
||||
// CHECK:STDOUT: %.8c2: type = partial_type %PrivateDestructor [concrete]
|
||||
// CHECK:STDOUT: %empty_struct.441: %.8c2 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %.ddb: type = partial_type %PrivateDestructor [concrete]
|
||||
// CHECK:STDOUT: %empty_struct.0b0: %.ddb = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %PrivateDestructor.val: %PrivateDestructor = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Derived.val: %Derived = struct_value (%PrivateDestructor.val) [concrete]
|
||||
// CHECK:STDOUT: %Destroy.Op.type.af7ec0.2: type = fn_type @Destroy.Op.loc21_3.2 [concrete]
|
||||
@@ -433,9 +433,9 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT: %a.var: ref %Derived = var %a.var_patt
|
||||
// CHECK:STDOUT: %.loc21_37.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct.a40]
|
||||
// CHECK:STDOUT: %.loc21_38.1: %struct_type.base.f5e = struct_literal (%.loc21_37.1) [concrete = constants.%struct]
|
||||
// CHECK:STDOUT: %.loc21_38.2: ref %.8c2 = class_element_access %a.var, element0
|
||||
// CHECK:STDOUT: %.loc21_37.2: init %.8c2 to %.loc21_38.2 = class_init () [concrete = constants.%empty_struct.441]
|
||||
// CHECK:STDOUT: %.loc21_38.3: init %.8c2 = converted %.loc21_37.1, %.loc21_37.2 [concrete = constants.%empty_struct.441]
|
||||
// CHECK:STDOUT: %.loc21_38.2: ref %.ddb = class_element_access %a.var, element0
|
||||
// CHECK:STDOUT: %.loc21_37.2: init %.ddb to %.loc21_38.2 = class_init () [concrete = constants.%empty_struct.0b0]
|
||||
// CHECK:STDOUT: %.loc21_38.3: init %.ddb = converted %.loc21_37.1, %.loc21_37.2 [concrete = constants.%empty_struct.0b0]
|
||||
// CHECK:STDOUT: %.loc21_38.4: init %PrivateDestructor = as_compatible %.loc21_38.3 [concrete = constants.%PrivateDestructor.val]
|
||||
// CHECK:STDOUT: %.loc21_38.5: init %Derived to %a.var = class_init (%.loc21_38.4) [concrete = constants.%Derived.val]
|
||||
// CHECK:STDOUT: %.loc21_3: init %Derived = converted %.loc21_38.1, %.loc21_38.5 [concrete = constants.%Derived.val]
|
||||
@@ -447,7 +447,7 @@ fn EqualWitnesses(p: Wrap(Cpp.PublicDestructor)*) -> Wrap(Cpp.PublicDestructor)*
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Destroy.Op.loc21_3.1(%self.param: ref %struct_type.base.59d) {
|
||||
// CHECK:STDOUT: fn @Destroy.Op.loc21_3.1(%self.param: ref %struct_type.base.dea) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
|
||||
Reference in New Issue
Block a user