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/iterator.h"
30 using namespace clang
;
34 /// According to Itanium C++ ABI 5.1.2:
35 /// the name of an anonymous union is considered to be
36 /// the name of the first named data member found by a pre-order,
37 /// depth-first, declaration-order walk of the data members of
38 /// the anonymous union.
39 /// If there is no such data member (i.e., if all of the data members
40 /// in the union are unnamed), then there is no way for a program to
41 /// refer to the anonymous union, and there is therefore no need to mangle its name.
43 /// Returns the name of anonymous union VarDecl or nullptr if it is not found.
44 static const IdentifierInfo
*findAnonymousUnionVarDeclName(const VarDecl
& VD
) {
45 const RecordType
*RT
= VD
.getType()->getAs
<RecordType
>();
46 assert(RT
&& "type of VarDecl is expected to be RecordType.");
47 assert(RT
->getDecl()->isUnion() && "RecordType is expected to be a union.");
48 if (const FieldDecl
*FD
= RT
->getDecl()->findFirstNamedDataMember()) {
49 return FD
->getIdentifier();
55 /// The name of a decomposition declaration.
56 struct DecompositionDeclName
{
57 using BindingArray
= ArrayRef
<const BindingDecl
*>;
59 /// Representative example of a set of bindings with these names.
60 BindingArray Bindings
;
62 /// Iterators over the sequence of identifiers in the name.
64 : llvm::iterator_adaptor_base
<Iterator
, BindingArray::const_iterator
,
65 std::random_access_iterator_tag
,
66 const IdentifierInfo
*> {
67 Iterator(BindingArray::const_iterator It
) : iterator_adaptor_base(It
) {}
68 const IdentifierInfo
*operator*() const {
69 return (*this->I
)->getIdentifier();
72 Iterator
begin() const { return Iterator(Bindings
.begin()); }
73 Iterator
end() const { return Iterator(Bindings
.end()); }
78 template<typename T
> bool isDenseMapKeyEmpty(T V
) {
79 return llvm::DenseMapInfo
<T
>::isEqual(
80 V
, llvm::DenseMapInfo
<T
>::getEmptyKey());
82 template<typename T
> bool isDenseMapKeyTombstone(T V
) {
83 return llvm::DenseMapInfo
<T
>::isEqual(
84 V
, llvm::DenseMapInfo
<T
>::getTombstoneKey());
88 std::optional
<bool> areDenseMapKeysEqualSpecialValues(T LHS
, T RHS
) {
89 bool LHSEmpty
= isDenseMapKeyEmpty(LHS
);
90 bool RHSEmpty
= isDenseMapKeyEmpty(RHS
);
91 if (LHSEmpty
|| RHSEmpty
)
92 return LHSEmpty
&& RHSEmpty
;
94 bool LHSTombstone
= isDenseMapKeyTombstone(LHS
);
95 bool RHSTombstone
= isDenseMapKeyTombstone(RHS
);
96 if (LHSTombstone
|| RHSTombstone
)
97 return LHSTombstone
&& RHSTombstone
;
103 struct DenseMapInfo
<DecompositionDeclName
> {
104 using ArrayInfo
= llvm::DenseMapInfo
<ArrayRef
<const BindingDecl
*>>;
105 static DecompositionDeclName
getEmptyKey() {
106 return {ArrayInfo::getEmptyKey()};
108 static DecompositionDeclName
getTombstoneKey() {
109 return {ArrayInfo::getTombstoneKey()};
111 static unsigned getHashValue(DecompositionDeclName Key
) {
112 assert(!isEqual(Key
, getEmptyKey()) && !isEqual(Key
, getTombstoneKey()));
113 return llvm::hash_combine_range(Key
.begin(), Key
.end());
115 static bool isEqual(DecompositionDeclName LHS
, DecompositionDeclName RHS
) {
116 if (std::optional
<bool> Result
=
117 areDenseMapKeysEqualSpecialValues(LHS
.Bindings
, RHS
.Bindings
))
120 return LHS
.Bindings
.size() == RHS
.Bindings
.size() &&
121 std::equal(LHS
.begin(), LHS
.end(), RHS
.begin());
128 /// Keeps track of the mangled names of lambda expressions and block
129 /// literals within a particular context.
130 class ItaniumNumberingContext
: public MangleNumberingContext
{
131 ItaniumMangleContext
*Mangler
;
132 llvm::StringMap
<unsigned> LambdaManglingNumbers
;
133 unsigned BlockManglingNumber
= 0;
134 llvm::DenseMap
<const IdentifierInfo
*, unsigned> VarManglingNumbers
;
135 llvm::DenseMap
<const IdentifierInfo
*, unsigned> TagManglingNumbers
;
136 llvm::DenseMap
<DecompositionDeclName
, unsigned>
137 DecompsitionDeclManglingNumbers
;
140 ItaniumNumberingContext(ItaniumMangleContext
*Mangler
) : Mangler(Mangler
) {}
142 unsigned getManglingNumber(const CXXMethodDecl
*CallOperator
) override
{
143 const CXXRecordDecl
*Lambda
= CallOperator
->getParent();
144 assert(Lambda
->isLambda());
146 // Computation of the <lambda-sig> is non-trivial and subtle. Rather than
147 // duplicating it here, just mangle the <lambda-sig> directly.
148 llvm::SmallString
<128> LambdaSig
;
149 llvm::raw_svector_ostream
Out(LambdaSig
);
150 Mangler
->mangleLambdaSig(Lambda
, Out
);
152 return ++LambdaManglingNumbers
[LambdaSig
];
155 unsigned getManglingNumber(const BlockDecl
*BD
) override
{
156 return ++BlockManglingNumber
;
159 unsigned getStaticLocalNumber(const VarDecl
*VD
) override
{
163 /// Variable decls are numbered by identifier.
164 unsigned getManglingNumber(const VarDecl
*VD
, unsigned) override
{
165 if (auto *DD
= dyn_cast
<DecompositionDecl
>(VD
)) {
166 DecompositionDeclName Name
{DD
->bindings()};
167 return ++DecompsitionDeclManglingNumbers
[Name
];
170 const IdentifierInfo
*Identifier
= VD
->getIdentifier();
172 // VarDecl without an identifier represents an anonymous union
174 Identifier
= findAnonymousUnionVarDeclName(*VD
);
176 return ++VarManglingNumbers
[Identifier
];
179 unsigned getManglingNumber(const TagDecl
*TD
, unsigned) override
{
180 return ++TagManglingNumbers
[TD
->getIdentifier()];
184 // A version of this for SYCL that makes sure that 'device' mangling context
185 // matches the lambda mangling number, so that __builtin_sycl_unique_stable_name
186 // can be consistently generated between a MS and Itanium host by just referring
187 // to the device mangling number.
188 class ItaniumSYCLNumberingContext
: public ItaniumNumberingContext
{
189 llvm::DenseMap
<const CXXMethodDecl
*, unsigned> ManglingNumbers
;
190 using ManglingItr
= decltype(ManglingNumbers
)::iterator
;
193 ItaniumSYCLNumberingContext(ItaniumMangleContext
*Mangler
)
194 : ItaniumNumberingContext(Mangler
) {}
196 unsigned getManglingNumber(const CXXMethodDecl
*CallOperator
) override
{
197 unsigned Number
= ItaniumNumberingContext::getManglingNumber(CallOperator
);
198 std::pair
<ManglingItr
, bool> emplace_result
=
199 ManglingNumbers
.try_emplace(CallOperator
, Number
);
200 (void)emplace_result
;
201 assert(emplace_result
.second
&& "Lambda number set multiple times?");
205 using ItaniumNumberingContext::getManglingNumber
;
207 unsigned getDeviceManglingNumber(const CXXMethodDecl
*CallOperator
) override
{
208 ManglingItr Itr
= ManglingNumbers
.find(CallOperator
);
209 assert(Itr
!= ManglingNumbers
.end() && "Lambda not yet mangled?");
215 class ItaniumCXXABI
: public CXXABI
{
217 std::unique_ptr
<MangleContext
> Mangler
;
221 ItaniumCXXABI(ASTContext
&Ctx
)
222 : Mangler(Ctx
.createMangleContext()), Context(Ctx
) {}
225 getMemberPointerInfo(const MemberPointerType
*MPT
) const override
{
226 const TargetInfo
&Target
= Context
.getTargetInfo();
227 TargetInfo::IntType PtrDiff
= Target
.getPtrDiffType(LangAS::Default
);
228 MemberPointerInfo MPI
;
229 MPI
.Width
= Target
.getTypeWidth(PtrDiff
);
230 MPI
.Align
= Target
.getTypeAlign(PtrDiff
);
231 MPI
.HasPadding
= false;
232 if (MPT
->isMemberFunctionPointer())
237 CallingConv
getDefaultMethodCallConv(bool isVariadic
) const override
{
238 const llvm::Triple
&T
= Context
.getTargetInfo().getTriple();
239 if (!isVariadic
&& T
.isWindowsGNUEnvironment() &&
240 T
.getArch() == llvm::Triple::x86
)
241 return CC_X86ThisCall
;
242 return Context
.getTargetInfo().getDefaultCallingConv();
245 // We cheat and just check that the class has a vtable pointer, and that it's
246 // only big enough to have a vtable pointer and nothing more (or less).
247 bool isNearlyEmpty(const CXXRecordDecl
*RD
) const override
{
249 // Check that the class has a vtable pointer.
250 if (!RD
->isDynamicClass())
253 const ASTRecordLayout
&Layout
= Context
.getASTRecordLayout(RD
);
254 CharUnits PointerSize
= Context
.toCharUnitsFromBits(
255 Context
.getTargetInfo().getPointerWidth(LangAS::Default
));
256 return Layout
.getNonVirtualSize() == PointerSize
;
259 const CXXConstructorDecl
*
260 getCopyConstructorForExceptionObject(CXXRecordDecl
*RD
) override
{
264 void addCopyConstructorForExceptionObject(CXXRecordDecl
*RD
,
265 CXXConstructorDecl
*CD
) override
{}
267 void addTypedefNameForUnnamedTagDecl(TagDecl
*TD
,
268 TypedefNameDecl
*DD
) override
{}
270 TypedefNameDecl
*getTypedefNameForUnnamedTagDecl(const TagDecl
*TD
) override
{
274 void addDeclaratorForUnnamedTagDecl(TagDecl
*TD
,
275 DeclaratorDecl
*DD
) override
{}
277 DeclaratorDecl
*getDeclaratorForUnnamedTagDecl(const TagDecl
*TD
) override
{
281 std::unique_ptr
<MangleNumberingContext
>
282 createMangleNumberingContext() const override
{
283 if (Context
.getLangOpts().isSYCL())
284 return std::make_unique
<ItaniumSYCLNumberingContext
>(
285 cast
<ItaniumMangleContext
>(Mangler
.get()));
286 return std::make_unique
<ItaniumNumberingContext
>(
287 cast
<ItaniumMangleContext
>(Mangler
.get()));
292 CXXABI
*clang::CreateItaniumCXXABI(ASTContext
&Ctx
) {
293 return new ItaniumCXXABI(Ctx
);
296 std::unique_ptr
<MangleNumberingContext
>
297 clang::createItaniumNumberingContext(MangleContext
*Mangler
) {
298 return std::make_unique
<ItaniumNumberingContext
>(
299 cast
<ItaniumMangleContext
>(Mangler
));