diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -5545,6 +5545,47 @@ return T; } +static IdentifierInfo *getUnionInitName(SourceLocation UnionLoc, + DiagnosticsEngine &Diags, + 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 or if it is an unnamed bitfield. + // There is no type to descend into in the case of a bitfield, so we can just + // return nullptr in that case. + if (FD->isBitField()) + return nullptr; + 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(UnionLoc, Diags, RDField)) + return II; + } + + // According to the Itanium ABI: 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. However, we should diagnose this anyway. + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, "cannot mangle this unnamed union NTTP yet"); + Diags.Report(UnionLoc, DiagID); + + return nullptr; +} + void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V, bool TopLevel, bool NeedExactType) { @@ -5628,7 +5669,10 @@ mangleType(T); if (!isZeroInitialized(T, V)) { Out << "di"; - mangleSourceName(FD->getIdentifier()); + IdentifierInfo *II = (getUnionInitName( + T->getAsCXXRecordDecl()->getLocation(), Context.getDiags(), FD)); + if (II) + mangleSourceName(II); mangleValueInTemplateArg(FD->getType(), V.getUnionValue(), false); } Out << 'E'; diff --git a/clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp b/clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp @@ -0,0 +1,113 @@ +// 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 +struct wrapper6 { + union { + union{ + int : 5; + T RightName; + }; + }; +}; + + + +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{}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper6IiEEEEvv + // 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}}}>()() + dummy{1}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper6IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Edi9RightNameLd3ff0000000000000EEEEEEvv + // DEMANGELD: call void @void dummy{wrapper6::'unnamed'{.RightName = wrapper6::'unnamed'::'unnamed'{.RightName = 0x1p+0}}}>()() +}