Index: clang/lib/AST/ItaniumMangle.cpp =================================================================== --- clang/lib/AST/ItaniumMangle.cpp +++ clang/lib/AST/ItaniumMangle.cpp @@ -5545,6 +5545,37 @@ return T; } +static IdentifierInfo *getUnionInitName(const FieldDecl *FD) { + // According to: + // http://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.anonymous + // For the purposes of mangling, the name of an anonymous union is considered + // to be the name of the first named data member found by a pre-order, + // depth-first, declaration-order walk of the data members of the anonymous + // union. + + if (FD->getIdentifier()) + return FD->getIdentifier(); + + // The only cases where the identifer of a FieldDecl would be blank is if the + // field represents an anonymous record type. + const CXXRecordDecl *RD = FD->getType()->getAsCXXRecordDecl(); + + // Consider only the fields in declaration order, searched depth-first. We + // don't care about the active member of the union, as all we are doing is + // looking for a valid name. We also don't check bases, due to guidance from + // the Itanium ABI folks. + for (const FieldDecl *RDField : RD->fields()) { + if (IdentifierInfo *II = getUnionInitName(RDField)) + return II; + } + + llvm_unreachable( + "Itanium ABI claims: ' If there is no such data member (i.e., if all of " + "the data members in the union are unnamed), then there is no way for a " + "program to refer to the anonymous union, and there is therefore no need " + "to mangle its name. '"); +} + void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V, bool TopLevel, bool NeedExactType) { @@ -5628,7 +5659,7 @@ mangleType(T); if (!isZeroInitialized(T, V)) { Out << "di"; - mangleSourceName(FD->getIdentifier()); + mangleSourceName(getUnionInitName(FD)); mangleValueInTemplateArg(FD->getType(), V.getUnionValue(), false); } Out << 'E'; Index: clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp @@ -0,0 +1,99 @@ +// RUN: %clang_cc1 -std=c++20 -emit-llvm %s -o - -triple=x86_64-linux-gnu | FileCheck %s +// RUN: %clang_cc1 -std=c++20 -emit-llvm %s -o - -triple=x86_64-linux-gnu | llvm-cxxfilt | FileCheck %s --check-prefix DEMANGLED + +template +struct wrapper1 { + union { + struct { + T RightName; + }; + }; +}; + +template +struct wrapper2 { + union { + struct { + T RightName; + }; + T WrongName; + }; +}; + +struct Base { + int WrongName; +}; + +template +struct wrapper3 { + union { + struct : Base { + T RightName; + }; + T WrongName; + }; +}; + +template +struct wrapper4 { + union { + int RightName; + struct { + T WrongName; + }; + T AlsoWrongName; + }; +}; + +template +struct wrapper5 { + union { + struct { + struct { + T RightName; + }; + T WrongName; + }; + }; +}; + + + +template void dummy(){} + + +void uses() { + // Zero init'ed cases. + dummy{}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper1IiEEEEvv + // DEMANGLED: call void @void dummy{}>()() + dummy{}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper2IfEEEEvv + // DEMANGLED: call void @void dummy{}>()() + dummy{}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper3IsEEEEvv + // DEMANGLED: call void @void dummy{}>()() + dummy{}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper4IdEEEEvv + // DEMANGLED: call void @void dummy{}>()() + dummy{}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper5IxEEEEvv + // DEMANGLED: call void @void dummy{}>()() + + + dummy{123.0}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper1IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_ELd405ec00000000000EEEEEEvv + // DEMANGLED: call void @void dummy{wrapper1::'unnamed'{.RightName = wrapper1::'unnamed'::'unnamed'{0x1.ecp+6}}}>()() + dummy{123.0}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper2IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_ELd405ec00000000000EEEEEEvv + // DEMANGLED: call void @void dummy{wrapper2::'unnamed'{.RightName = wrapper2::'unnamed'::'unnamed'{0x1.ecp+6}}}>()() + dummy{123, 456}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper3IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Etl4BaseLi123EELd407c800000000000EEEEEEvv + // DEMANGLED: call void @void dummy{wrapper3::'unnamed'{.RightName = wrapper3::'unnamed'::'unnamed'{Base{123}, 0x1.c8p+8}}}>()() + dummy{123}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper4IdEtlNS1_Ut_Edi9RightNameLi123EEEEEvv + // DEMANGLED: call void @void dummy{wrapper4::'unnamed'{.RightName = 123}}>()() + dummy{123.0, 456.0}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper5IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_EtlNS3_Ut_ELd405ec00000000000EELd407c800000000000EEEEEEvv + // DEMANGLED: call void @void dummy{wrapper5::'unnamed'{.RightName = wrapper5::'unnamed'::'unnamed'{wrapper5::'unnamed'::'unnamed'::'unnamed'{0x1.ecp+6}, 0x1.c8p+8}}}>()() +}