From d1205bb37d8c37c6e427c339d704e707147989d2 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Mon, 4 Apr 2022 06:25:07 -0700 Subject: [PATCH] Reapply"[GH54588]Fix ItaniumMangler for NTTP unnamed unions w/ unnamed structs" AND the followups that fixed builds. I attempted to get 'cute' and use llvm-cxxfilt to make the test look nicer, but apparently some of the bots have a version of llvm-cxxfilt that is not the in-tree one, so it fails to properly demangle the stuff. I've disabled this "RUN" line. This reverts commit 50186b63d1807d389f31c515377d94185795ab44. --- clang/lib/AST/ItaniumMangle.cpp | 46 ++++++- .../CodeGenCXX/mangle-nttp-anon-union.cpp | 117 ++++++++++++++++++ 2 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index fb76fa7b896f..50e110ec1f57 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -5545,6 +5545,47 @@ static QualType getLValueType(ASTContext &Ctx, const APValue &LV) { 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 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V, 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 index 000000000000..4382d1406cfe --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp @@ -0,0 +1,117 @@ +// RUN: %clang_cc1 -std=c++20 -emit-llvm %s -o - -triple=x86_64-linux-gnu | FileCheck %s + +// FIXME: In the future we could possibly do this to get nicer looking output +// for this, but it seems that some of the bots don't have a recent enough +// version of llvm-cxxfilt to demangle these. +// %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.ec{{.*}}p+6}}}>()() + dummy{123.0}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper2IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_ELd405ec00000000000EEEEEEvv + // DEMANGLED: call void @void dummy{wrapper2::'unnamed'{.RightName = wrapper2::'unnamed'::'unnamed'{0x1.ec{{.*}}p+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.c8{{.*}}p+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.ec{{.*}}p+6}, 0x1.c8{{.*}}p+8}}}>()() + dummy{1}>(); + // CHECK: call void @_Z5dummyIXtl8wrapper6IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Edi9RightNameLd3ff0000000000000EEEEEEvv + // DEMANGELD: call void @void dummy{wrapper6::'unnamed'{.RightName = wrapper6::'unnamed'::'unnamed'{.RightName = 0x1{{.*}}p+0}}}>()() +}