1 //===------- ItaniumCXXABI.cpp - AST support for the Itanium C++ ABI ------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This provides C++ AST support targeting the Itanium C++ ABI, which is
11 // http://www.codesourcery.com/public/cxx-abi/abi.html
12 // http://www.codesourcery.com/public/cxx-abi/abi-eh.html
14 // It also supports the closely-related ARM C++ ABI, documented at:
15 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf
17 //===----------------------------------------------------------------------===//
20 #include "clang/AST/ASTContext.h"
21 #include "clang/AST/DeclCXX.h"
22 #include "clang/AST/Mangle.h"
23 #include "clang/AST/MangleNumberingContext.h"
24 #include "clang/AST/RecordLayout.h"
25 #include "clang/AST/Type.h"
26 #include "clang/Basic/TargetInfo.h"
27 #include "llvm/ADT/FoldingSet.h"
28 #include "llvm/ADT/iterator.h"
31 using namespace clang
;
35 /// According to Itanium C++ ABI 5.1.2:
36 /// the name of an anonymous union is considered to be
37 /// the name of the first named data member found by a pre-order,
38 /// depth-first, declaration-order walk of the data members of
39 /// the anonymous union.
40 /// If there is no such data member (i.e., if all of the data members
41 /// in the union are unnamed), then there is no way for a program to
42 /// refer to the anonymous union, and there is therefore no need to mangle its name.
44 /// Returns the name of anonymous union VarDecl or nullptr if it is not found.
45 static const IdentifierInfo
*findAnonymousUnionVarDeclName(const VarDecl
& VD
) {
46 const RecordType
*RT
= VD
.getType()->getAs
<RecordType
>();
47 assert(RT
&& "type of VarDecl is expected to be RecordType.");
48 assert(RT
->getDecl()->isUnion() && "RecordType is expected to be a union.");
49 if (const FieldDecl
*FD
= RT
->getDecl()->findFirstNamedDataMember()) {
50 return FD
->getIdentifier();
56 /// The name of a decomposition declaration.
57 struct DecompositionDeclName
{
58 using BindingArray
= ArrayRef
<const BindingDecl
*>;
60 /// Representative example of a set of bindings with these names.
61 BindingArray Bindings
;
63 /// Iterators over the sequence of identifiers in the name.
65 : llvm::iterator_adaptor_base
<Iterator
, BindingArray::const_iterator
,
66 std::random_access_iterator_tag
,
67 const IdentifierInfo
*> {
68 Iterator(BindingArray::const_iterator It
) : iterator_adaptor_base(It
) {}
69 const IdentifierInfo
*operator*() const {
70 return (*this->I
)->getIdentifier();
73 Iterator
begin() const { return Iterator(Bindings
.begin()); }
74 Iterator
end() const { return Iterator(Bindings
.end()); }
79 template<typename T
> bool isDenseMapKeyEmpty(T V
) {
80 return llvm::DenseMapInfo
<T
>::isEqual(
81 V
, llvm::DenseMapInfo
<T
>::getEmptyKey());
83 template<typename T
> bool isDenseMapKeyTombstone(T V
) {
84 return llvm::DenseMapInfo
<T
>::isEqual(
85 V
, llvm::DenseMapInfo
<T
>::getTombstoneKey());
89 std::optional
<bool> areDenseMapKeysEqualSpecialValues(T LHS
, T RHS
) {
90 bool LHSEmpty
= isDenseMapKeyEmpty(LHS
);
91 bool RHSEmpty
= isDenseMapKeyEmpty(RHS
);
92 if (LHSEmpty
|| RHSEmpty
)
93 return LHSEmpty
&& RHSEmpty
;
95 bool LHSTombstone
= isDenseMapKeyTombstone(LHS
);
96 bool RHSTombstone
= isDenseMapKeyTombstone(RHS
);
97 if (LHSTombstone
|| RHSTombstone
)
98 return LHSTombstone
&& RHSTombstone
;
104 struct DenseMapInfo
<DecompositionDeclName
> {
105 using ArrayInfo
= llvm::DenseMapInfo
<ArrayRef
<const BindingDecl
*>>;
106 static DecompositionDeclName
getEmptyKey() {
107 return {ArrayInfo::getEmptyKey()};
109 static DecompositionDeclName
getTombstoneKey() {
110 return {ArrayInfo::getTombstoneKey()};
112 static unsigned getHashValue(DecompositionDeclName Key
) {
113 assert(!isEqual(Key
, getEmptyKey()) && !isEqual(Key
, getTombstoneKey()));
114 return llvm::hash_combine_range(Key
.begin(), Key
.end());
116 static bool isEqual(DecompositionDeclName LHS
, DecompositionDeclName RHS
) {
117 if (std::optional
<bool> Result
=
118 areDenseMapKeysEqualSpecialValues(LHS
.Bindings
, RHS
.Bindings
))
121 return LHS
.Bindings
.size() == RHS
.Bindings
.size() &&
122 std::equal(LHS
.begin(), LHS
.end(), RHS
.begin());
129 /// Keeps track of the mangled names of lambda expressions and block
130 /// literals within a particular context.
131 class ItaniumNumberingContext
: public MangleNumberingContext
{
132 ItaniumMangleContext
*Mangler
;
133 llvm::StringMap
<unsigned> LambdaManglingNumbers
;
134 unsigned BlockManglingNumber
= 0;
135 llvm::DenseMap
<const IdentifierInfo
*, unsigned> VarManglingNumbers
;
136 llvm::DenseMap
<const IdentifierInfo
*, unsigned> TagManglingNumbers
;
137 llvm::DenseMap
<DecompositionDeclName
, unsigned>
138 DecompsitionDeclManglingNumbers
;
141 ItaniumNumberingContext(ItaniumMangleContext
*Mangler
) : Mangler(Mangler
) {}
143 unsigned getManglingNumber(const CXXMethodDecl
*CallOperator
) override
{
144 const CXXRecordDecl
*Lambda
= CallOperator
->getParent();
145 assert(Lambda
->isLambda());
147 // Computation of the <lambda-sig> is non-trivial and subtle. Rather than
148 // duplicating it here, just mangle the <lambda-sig> directly.
149 llvm::SmallString
<128> LambdaSig
;
150 llvm::raw_svector_ostream
Out(LambdaSig
);
151 Mangler
->mangleLambdaSig(Lambda
, Out
);
153 return ++LambdaManglingNumbers
[LambdaSig
];
156 unsigned getManglingNumber(const BlockDecl
*BD
) override
{
157 return ++BlockManglingNumber
;
160 unsigned getStaticLocalNumber(const VarDecl
*VD
) override
{
164 /// Variable decls are numbered by identifier.
165 unsigned getManglingNumber(const VarDecl
*VD
, unsigned) override
{
166 if (auto *DD
= dyn_cast
<DecompositionDecl
>(VD
)) {
167 DecompositionDeclName Name
{DD
->bindings()};
168 return ++DecompsitionDeclManglingNumbers
[Name
];
171 const IdentifierInfo
*Identifier
= VD
->getIdentifier();
173 // VarDecl without an identifier represents an anonymous union
175 Identifier
= findAnonymousUnionVarDeclName(*VD
);
177 return ++VarManglingNumbers
[Identifier
];
180 unsigned getManglingNumber(const TagDecl
*TD
, unsigned) override
{
181 return ++TagManglingNumbers
[TD
->getIdentifier()];
185 // A version of this for SYCL that makes sure that 'device' mangling context
186 // matches the lambda mangling number, so that __builtin_sycl_unique_stable_name
187 // can be consistently generated between a MS and Itanium host by just referring
188 // to the device mangling number.
189 class ItaniumSYCLNumberingContext
: public ItaniumNumberingContext
{
190 llvm::DenseMap
<const CXXMethodDecl
*, unsigned> ManglingNumbers
;
191 using ManglingItr
= decltype(ManglingNumbers
)::iterator
;
194 ItaniumSYCLNumberingContext(ItaniumMangleContext
*Mangler
)
195 : ItaniumNumberingContext(Mangler
) {}
197 unsigned getManglingNumber(const CXXMethodDecl
*CallOperator
) override
{
198 unsigned Number
= ItaniumNumberingContext::getManglingNumber(CallOperator
);
199 std::pair
<ManglingItr
, bool> emplace_result
=
200 ManglingNumbers
.try_emplace(CallOperator
, Number
);
201 (void)emplace_result
;
202 assert(emplace_result
.second
&& "Lambda number set multiple times?");
206 using ItaniumNumberingContext::getManglingNumber
;
208 unsigned getDeviceManglingNumber(const CXXMethodDecl
*CallOperator
) override
{
209 ManglingItr Itr
= ManglingNumbers
.find(CallOperator
);
210 assert(Itr
!= ManglingNumbers
.end() && "Lambda not yet mangled?");
216 class ItaniumCXXABI
: public CXXABI
{
218 std::unique_ptr
<MangleContext
> Mangler
;
222 ItaniumCXXABI(ASTContext
&Ctx
)
223 : Mangler(Ctx
.createMangleContext()), Context(Ctx
) {}
226 getMemberPointerInfo(const MemberPointerType
*MPT
) const override
{
227 const TargetInfo
&Target
= Context
.getTargetInfo();
228 TargetInfo::IntType PtrDiff
= Target
.getPtrDiffType(LangAS::Default
);
229 MemberPointerInfo MPI
;
230 MPI
.Width
= Target
.getTypeWidth(PtrDiff
);
231 MPI
.Align
= Target
.getTypeAlign(PtrDiff
);
232 MPI
.HasPadding
= false;
233 if (MPT
->isMemberFunctionPointer())
238 CallingConv
getDefaultMethodCallConv(bool isVariadic
) const override
{
239 const llvm::Triple
&T
= Context
.getTargetInfo().getTriple();
240 if (!isVariadic
&& T
.isWindowsGNUEnvironment() &&
241 T
.getArch() == llvm::Triple::x86
)
242 return CC_X86ThisCall
;
243 return Context
.getTargetInfo().getDefaultCallingConv();
246 // We cheat and just check that the class has a vtable pointer, and that it's
247 // only big enough to have a vtable pointer and nothing more (or less).
248 bool isNearlyEmpty(const CXXRecordDecl
*RD
) const override
{
250 // Check that the class has a vtable pointer.
251 if (!RD
->isDynamicClass())
254 const ASTRecordLayout
&Layout
= Context
.getASTRecordLayout(RD
);
255 CharUnits PointerSize
= Context
.toCharUnitsFromBits(
256 Context
.getTargetInfo().getPointerWidth(LangAS::Default
));
257 return Layout
.getNonVirtualSize() == PointerSize
;
260 const CXXConstructorDecl
*
261 getCopyConstructorForExceptionObject(CXXRecordDecl
*RD
) override
{
265 void addCopyConstructorForExceptionObject(CXXRecordDecl
*RD
,
266 CXXConstructorDecl
*CD
) override
{}
268 void addTypedefNameForUnnamedTagDecl(TagDecl
*TD
,
269 TypedefNameDecl
*DD
) override
{}
271 TypedefNameDecl
*getTypedefNameForUnnamedTagDecl(const TagDecl
*TD
) override
{
275 void addDeclaratorForUnnamedTagDecl(TagDecl
*TD
,
276 DeclaratorDecl
*DD
) override
{}
278 DeclaratorDecl
*getDeclaratorForUnnamedTagDecl(const TagDecl
*TD
) override
{
282 std::unique_ptr
<MangleNumberingContext
>
283 createMangleNumberingContext() const override
{
284 if (Context
.getLangOpts().isSYCL())
285 return std::make_unique
<ItaniumSYCLNumberingContext
>(
286 cast
<ItaniumMangleContext
>(Mangler
.get()));
287 return std::make_unique
<ItaniumNumberingContext
>(
288 cast
<ItaniumMangleContext
>(Mangler
.get()));
293 CXXABI
*clang::CreateItaniumCXXABI(ASTContext
&Ctx
) {
294 return new ItaniumCXXABI(Ctx
);
297 std::unique_ptr
<MangleNumberingContext
>
298 clang::createItaniumNumberingContext(MangleContext
*Mangler
) {
299 return std::make_unique
<ItaniumNumberingContext
>(
300 cast
<ItaniumMangleContext
>(Mangler
));