Path: blob/main/contrib/llvm-project/clang/lib/AST/ItaniumCXXABI.cpp
35260 views
//===------- ItaniumCXXABI.cpp - AST support for the Itanium C++ ABI ------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This provides C++ AST support targeting the Itanium C++ ABI, which is9// documented at:10// http://www.codesourcery.com/public/cxx-abi/abi.html11// http://www.codesourcery.com/public/cxx-abi/abi-eh.html12//13// It also supports the closely-related ARM C++ ABI, documented at:14// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf15//16//===----------------------------------------------------------------------===//1718#include "CXXABI.h"19#include "clang/AST/ASTContext.h"20#include "clang/AST/DeclCXX.h"21#include "clang/AST/Mangle.h"22#include "clang/AST/MangleNumberingContext.h"23#include "clang/AST/RecordLayout.h"24#include "clang/AST/Type.h"25#include "clang/Basic/TargetInfo.h"26#include "llvm/ADT/FoldingSet.h"27#include "llvm/ADT/iterator.h"28#include <optional>2930using namespace clang;3132namespace {3334/// According to Itanium C++ ABI 5.1.2:35/// the name of an anonymous union is considered to be36/// the name of the first named data member found by a pre-order,37/// depth-first, declaration-order walk of the data members of38/// the anonymous union.39/// If there is no such data member (i.e., if all of the data members40/// in the union are unnamed), then there is no way for a program to41/// refer to the anonymous union, and there is therefore no need to mangle its name.42///43/// Returns the name of anonymous union VarDecl or nullptr if it is not found.44static const IdentifierInfo *findAnonymousUnionVarDeclName(const VarDecl& VD) {45const RecordType *RT = VD.getType()->getAs<RecordType>();46assert(RT && "type of VarDecl is expected to be RecordType.");47assert(RT->getDecl()->isUnion() && "RecordType is expected to be a union.");48if (const FieldDecl *FD = RT->getDecl()->findFirstNamedDataMember()) {49return FD->getIdentifier();50}5152return nullptr;53}5455/// The name of a decomposition declaration.56struct DecompositionDeclName {57using BindingArray = ArrayRef<const BindingDecl*>;5859/// Representative example of a set of bindings with these names.60BindingArray Bindings;6162/// Iterators over the sequence of identifiers in the name.63struct Iterator64: llvm::iterator_adaptor_base<Iterator, BindingArray::const_iterator,65std::random_access_iterator_tag,66const IdentifierInfo *> {67Iterator(BindingArray::const_iterator It) : iterator_adaptor_base(It) {}68const IdentifierInfo *operator*() const {69return (*this->I)->getIdentifier();70}71};72Iterator begin() const { return Iterator(Bindings.begin()); }73Iterator end() const { return Iterator(Bindings.end()); }74};75}7677namespace llvm {78template<typename T> bool isDenseMapKeyEmpty(T V) {79return llvm::DenseMapInfo<T>::isEqual(80V, llvm::DenseMapInfo<T>::getEmptyKey());81}82template<typename T> bool isDenseMapKeyTombstone(T V) {83return llvm::DenseMapInfo<T>::isEqual(84V, llvm::DenseMapInfo<T>::getTombstoneKey());85}8687template <typename T>88std::optional<bool> areDenseMapKeysEqualSpecialValues(T LHS, T RHS) {89bool LHSEmpty = isDenseMapKeyEmpty(LHS);90bool RHSEmpty = isDenseMapKeyEmpty(RHS);91if (LHSEmpty || RHSEmpty)92return LHSEmpty && RHSEmpty;9394bool LHSTombstone = isDenseMapKeyTombstone(LHS);95bool RHSTombstone = isDenseMapKeyTombstone(RHS);96if (LHSTombstone || RHSTombstone)97return LHSTombstone && RHSTombstone;9899return std::nullopt;100}101102template<>103struct DenseMapInfo<DecompositionDeclName> {104using ArrayInfo = llvm::DenseMapInfo<ArrayRef<const BindingDecl*>>;105static DecompositionDeclName getEmptyKey() {106return {ArrayInfo::getEmptyKey()};107}108static DecompositionDeclName getTombstoneKey() {109return {ArrayInfo::getTombstoneKey()};110}111static unsigned getHashValue(DecompositionDeclName Key) {112assert(!isEqual(Key, getEmptyKey()) && !isEqual(Key, getTombstoneKey()));113return llvm::hash_combine_range(Key.begin(), Key.end());114}115static bool isEqual(DecompositionDeclName LHS, DecompositionDeclName RHS) {116if (std::optional<bool> Result =117areDenseMapKeysEqualSpecialValues(LHS.Bindings, RHS.Bindings))118return *Result;119120return LHS.Bindings.size() == RHS.Bindings.size() &&121std::equal(LHS.begin(), LHS.end(), RHS.begin());122}123};124}125126namespace {127128/// Keeps track of the mangled names of lambda expressions and block129/// literals within a particular context.130class ItaniumNumberingContext : public MangleNumberingContext {131ItaniumMangleContext *Mangler;132llvm::StringMap<unsigned> LambdaManglingNumbers;133unsigned BlockManglingNumber = 0;134llvm::DenseMap<const IdentifierInfo *, unsigned> VarManglingNumbers;135llvm::DenseMap<const IdentifierInfo *, unsigned> TagManglingNumbers;136llvm::DenseMap<DecompositionDeclName, unsigned>137DecompsitionDeclManglingNumbers;138139public:140ItaniumNumberingContext(ItaniumMangleContext *Mangler) : Mangler(Mangler) {}141142unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {143const CXXRecordDecl *Lambda = CallOperator->getParent();144assert(Lambda->isLambda());145146// Computation of the <lambda-sig> is non-trivial and subtle. Rather than147// duplicating it here, just mangle the <lambda-sig> directly.148llvm::SmallString<128> LambdaSig;149llvm::raw_svector_ostream Out(LambdaSig);150Mangler->mangleLambdaSig(Lambda, Out);151152return ++LambdaManglingNumbers[LambdaSig];153}154155unsigned getManglingNumber(const BlockDecl *BD) override {156return ++BlockManglingNumber;157}158159unsigned getStaticLocalNumber(const VarDecl *VD) override {160return 0;161}162163/// Variable decls are numbered by identifier.164unsigned getManglingNumber(const VarDecl *VD, unsigned) override {165if (auto *DD = dyn_cast<DecompositionDecl>(VD)) {166DecompositionDeclName Name{DD->bindings()};167return ++DecompsitionDeclManglingNumbers[Name];168}169170const IdentifierInfo *Identifier = VD->getIdentifier();171if (!Identifier) {172// VarDecl without an identifier represents an anonymous union173// declaration.174Identifier = findAnonymousUnionVarDeclName(*VD);175}176return ++VarManglingNumbers[Identifier];177}178179unsigned getManglingNumber(const TagDecl *TD, unsigned) override {180return ++TagManglingNumbers[TD->getIdentifier()];181}182};183184// A version of this for SYCL that makes sure that 'device' mangling context185// matches the lambda mangling number, so that __builtin_sycl_unique_stable_name186// can be consistently generated between a MS and Itanium host by just referring187// to the device mangling number.188class ItaniumSYCLNumberingContext : public ItaniumNumberingContext {189llvm::DenseMap<const CXXMethodDecl *, unsigned> ManglingNumbers;190using ManglingItr = decltype(ManglingNumbers)::iterator;191192public:193ItaniumSYCLNumberingContext(ItaniumMangleContext *Mangler)194: ItaniumNumberingContext(Mangler) {}195196unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {197unsigned Number = ItaniumNumberingContext::getManglingNumber(CallOperator);198std::pair<ManglingItr, bool> emplace_result =199ManglingNumbers.try_emplace(CallOperator, Number);200(void)emplace_result;201assert(emplace_result.second && "Lambda number set multiple times?");202return Number;203}204205using ItaniumNumberingContext::getManglingNumber;206207unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override {208ManglingItr Itr = ManglingNumbers.find(CallOperator);209assert(Itr != ManglingNumbers.end() && "Lambda not yet mangled?");210211return Itr->second;212}213};214215class ItaniumCXXABI : public CXXABI {216private:217std::unique_ptr<MangleContext> Mangler;218protected:219ASTContext &Context;220public:221ItaniumCXXABI(ASTContext &Ctx)222: Mangler(Ctx.createMangleContext()), Context(Ctx) {}223224MemberPointerInfo225getMemberPointerInfo(const MemberPointerType *MPT) const override {226const TargetInfo &Target = Context.getTargetInfo();227TargetInfo::IntType PtrDiff = Target.getPtrDiffType(LangAS::Default);228MemberPointerInfo MPI;229MPI.Width = Target.getTypeWidth(PtrDiff);230MPI.Align = Target.getTypeAlign(PtrDiff);231MPI.HasPadding = false;232if (MPT->isMemberFunctionPointer())233MPI.Width *= 2;234return MPI;235}236237CallingConv getDefaultMethodCallConv(bool isVariadic) const override {238const llvm::Triple &T = Context.getTargetInfo().getTriple();239if (!isVariadic && T.isWindowsGNUEnvironment() &&240T.getArch() == llvm::Triple::x86)241return CC_X86ThisCall;242return Context.getTargetInfo().getDefaultCallingConv();243}244245// We cheat and just check that the class has a vtable pointer, and that it's246// only big enough to have a vtable pointer and nothing more (or less).247bool isNearlyEmpty(const CXXRecordDecl *RD) const override {248249// Check that the class has a vtable pointer.250if (!RD->isDynamicClass())251return false;252253const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);254CharUnits PointerSize = Context.toCharUnitsFromBits(255Context.getTargetInfo().getPointerWidth(LangAS::Default));256return Layout.getNonVirtualSize() == PointerSize;257}258259const CXXConstructorDecl *260getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override {261return nullptr;262}263264void addCopyConstructorForExceptionObject(CXXRecordDecl *RD,265CXXConstructorDecl *CD) override {}266267void addTypedefNameForUnnamedTagDecl(TagDecl *TD,268TypedefNameDecl *DD) override {}269270TypedefNameDecl *getTypedefNameForUnnamedTagDecl(const TagDecl *TD) override {271return nullptr;272}273274void addDeclaratorForUnnamedTagDecl(TagDecl *TD,275DeclaratorDecl *DD) override {}276277DeclaratorDecl *getDeclaratorForUnnamedTagDecl(const TagDecl *TD) override {278return nullptr;279}280281std::unique_ptr<MangleNumberingContext>282createMangleNumberingContext() const override {283if (Context.getLangOpts().isSYCL())284return std::make_unique<ItaniumSYCLNumberingContext>(285cast<ItaniumMangleContext>(Mangler.get()));286return std::make_unique<ItaniumNumberingContext>(287cast<ItaniumMangleContext>(Mangler.get()));288}289};290}291292CXXABI *clang::CreateItaniumCXXABI(ASTContext &Ctx) {293return new ItaniumCXXABI(Ctx);294}295296std::unique_ptr<MangleNumberingContext>297clang::createItaniumNumberingContext(MangleContext *Mangler) {298return std::make_unique<ItaniumNumberingContext>(299cast<ItaniumMangleContext>(Mangler));300}301302303