mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +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
+11
-11
@@ -45,20 +45,20 @@ fn G() {
|
||||
// CHECK:STDOUT: %G: %G.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %F.cpp_overload_set.type: type = cpp_overload_set_type @F.cpp_overload_set [concrete]
|
||||
// CHECK:STDOUT: %F.cpp_overload_set.value: %F.cpp_overload_set.type = cpp_overload_set_value @F.cpp_overload_set [concrete]
|
||||
// CHECK:STDOUT: %.dcc: type = class_type @.1 [concrete]
|
||||
// CHECK:STDOUT: %int_1.0f6: %.dcc = int_value 1 [concrete]
|
||||
// CHECK:STDOUT: %.730: type = class_type @.1 [concrete]
|
||||
// CHECK:STDOUT: %int_1.94f: %.730 = int_value 1 [concrete]
|
||||
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
|
||||
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %C: type = class_type @C [concrete]
|
||||
// CHECK:STDOUT: %C.C.cpp_overload_set.type: type = cpp_overload_set_type @C.C.cpp_overload_set [concrete]
|
||||
// CHECK:STDOUT: %C.C.cpp_overload_set.value: %C.C.cpp_overload_set.type = cpp_overload_set_value @C.C.cpp_overload_set [concrete]
|
||||
// CHECK:STDOUT: %ptr.dbb: type = ptr_type %C [concrete]
|
||||
// CHECK:STDOUT: %ptr.3a8: type = ptr_type %C [concrete]
|
||||
// CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete]
|
||||
// CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %C.F.cpp_overload_set.type: type = cpp_overload_set_type @C.F.cpp_overload_set [concrete]
|
||||
// CHECK:STDOUT: %C.F.cpp_overload_set.value: %C.F.cpp_overload_set.type = cpp_overload_set_value @C.F.cpp_overload_set [concrete]
|
||||
// CHECK:STDOUT: %.fd8: type = class_type @.2 [concrete]
|
||||
// CHECK:STDOUT: %int_1.ea9: %.fd8 = int_value 1 [concrete]
|
||||
// CHECK:STDOUT: %.149: type = class_type @.2 [concrete]
|
||||
// CHECK:STDOUT: %int_1.9c2: %.149 = int_value 1 [concrete]
|
||||
// CHECK:STDOUT: %C.F.type: type = fn_type @C.F [concrete]
|
||||
// CHECK:STDOUT: %C.F: %C.F.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %C.cpp_destructor.type: type = fn_type @C.cpp_destructor [concrete]
|
||||
@@ -68,12 +68,12 @@ fn G() {
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .F = %F.cpp_overload_set.value
|
||||
// CHECK:STDOUT: .b = %int_1.0f6
|
||||
// CHECK:STDOUT: .b = %int_1.94f
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %F.cpp_overload_set.value: %F.cpp_overload_set.type = cpp_overload_set_value @F.cpp_overload_set [concrete = constants.%F.cpp_overload_set.value]
|
||||
// CHECK:STDOUT: %int_1.0f6: %.dcc = int_value 1 [concrete = constants.%int_1.0f6]
|
||||
// CHECK:STDOUT: %int_1.94f: %.730 = int_value 1 [concrete = constants.%int_1.94f]
|
||||
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
@@ -87,7 +87,7 @@ fn G() {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.F.cpp_overload_set.value: %C.F.cpp_overload_set.type = cpp_overload_set_value @C.F.cpp_overload_set [concrete = constants.%C.F.cpp_overload_set.value]
|
||||
// CHECK:STDOUT: %int_1.ea9: %.fd8 = int_value 1 [concrete = constants.%int_1.ea9]
|
||||
// CHECK:STDOUT: %int_1.9c2: %.149 = int_value 1 [concrete = constants.%int_1.9c2]
|
||||
// CHECK:STDOUT: %C.F.decl: %C.F.type = fn_decl @C.F [concrete = constants.%C.F] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
@@ -104,13 +104,13 @@ fn G() {
|
||||
// CHECK:STDOUT: %Cpp.ref.loc8_3: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %F.ref.loc8: %F.cpp_overload_set.type = name_ref F, imports.%F.cpp_overload_set.value [concrete = constants.%F.cpp_overload_set.value]
|
||||
// CHECK:STDOUT: %Cpp.ref.loc8_9: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %b.ref: %.dcc = name_ref b, imports.%int_1.0f6 [concrete = constants.%int_1.0f6]
|
||||
// CHECK:STDOUT: %b.ref: %.730 = name_ref b, imports.%int_1.94f [concrete = constants.%int_1.94f]
|
||||
// CHECK:STDOUT: %F.call: init %empty_tuple.type = call imports.%F.decl(%b.ref)
|
||||
// CHECK:STDOUT: %Cpp.ref.loc10_3: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %C.ref.loc10_6: type = name_ref C, imports.%C.decl [concrete = constants.%C]
|
||||
// CHECK:STDOUT: %C.ref.loc10_8: %C.C.cpp_overload_set.type = name_ref C, imports.%C.C.cpp_overload_set.value [concrete = constants.%C.C.cpp_overload_set.value]
|
||||
// CHECK:STDOUT: %.loc10_11.1: ref %C = temporary_storage
|
||||
// CHECK:STDOUT: %addr: %ptr.dbb = addr_of %.loc10_11.1
|
||||
// CHECK:STDOUT: %addr: %ptr.3a8 = addr_of %.loc10_11.1
|
||||
// CHECK:STDOUT: %C__carbon_thunk.call: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr)
|
||||
// CHECK:STDOUT: %.loc10_11.2: init %C to %.loc10_11.1 = mark_in_place_init %C__carbon_thunk.call
|
||||
// CHECK:STDOUT: %.loc10_11.3: ref %C = temporary %.loc10_11.1, %.loc10_11.2
|
||||
@@ -118,7 +118,7 @@ fn G() {
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc10_11.3, %F.ref.loc10
|
||||
// CHECK:STDOUT: %Cpp.ref.loc10_15: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %C.ref.loc10_18: type = name_ref C, imports.%C.decl [concrete = constants.%C]
|
||||
// CHECK:STDOUT: %e.ref: %.fd8 = name_ref e, imports.%int_1.ea9 [concrete = constants.%int_1.ea9]
|
||||
// CHECK:STDOUT: %e.ref: %.149 = name_ref e, imports.%int_1.9c2 [concrete = constants.%int_1.9c2]
|
||||
// CHECK:STDOUT: %.loc10_11.4: %C = acquire_value %.loc10_11.3
|
||||
// CHECK:STDOUT: %C.F.call: init %empty_tuple.type = call imports.%C.F.decl(%.loc10_11.4, %e.ref)
|
||||
// CHECK:STDOUT: %C.cpp_destructor.bound: <bound method> = bound_method %.loc10_11.3, constants.%C.cpp_destructor
|
||||
|
||||
Reference in New Issue
Block a user