Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/AST/MicrosoftCXXABI.cpp
Line
Count
Source (jump to first uncovered line)
1
//===------- MicrosoftCXXABI.cpp - AST support for the Microsoft C++ ABI --===//
2
//
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
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This provides C++ AST support targeting the Microsoft Visual C++
10
// ABI.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "CXXABI.h"
15
#include "clang/AST/ASTContext.h"
16
#include "clang/AST/Attr.h"
17
#include "clang/AST/CXXInheritance.h"
18
#include "clang/AST/DeclCXX.h"
19
#include "clang/AST/Mangle.h"
20
#include "clang/AST/MangleNumberingContext.h"
21
#include "clang/AST/RecordLayout.h"
22
#include "clang/AST/Type.h"
23
#include "clang/Basic/TargetInfo.h"
24
25
using namespace clang;
26
27
namespace {
28
29
/// Numbers things which need to correspond across multiple TUs.
30
/// Typically these are things like static locals, lambdas, or blocks.
31
class MicrosoftNumberingContext : public MangleNumberingContext {
32
  llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
33
  unsigned LambdaManglingNumber = 0;
34
  unsigned StaticLocalNumber = 0;
35
  unsigned StaticThreadlocalNumber = 0;
36
37
public:
38
0
  MicrosoftNumberingContext() = default;
39
40
0
  unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
41
0
    return ++LambdaManglingNumber;
42
0
  }
43
44
0
  unsigned getManglingNumber(const BlockDecl *BD) override {
45
0
    const Type *Ty = nullptr;
46
0
    return ++ManglingNumbers[Ty];
47
0
  }
48
49
0
  unsigned getStaticLocalNumber(const VarDecl *VD) override {
50
0
    if (VD->getTLSKind())
51
0
      return ++StaticThreadlocalNumber;
52
0
    return ++StaticLocalNumber;
53
0
  }
54
55
  unsigned getManglingNumber(const VarDecl *VD,
56
0
                             unsigned MSLocalManglingNumber) override {
57
0
    return MSLocalManglingNumber;
58
0
  }
59
60
  unsigned getManglingNumber(const TagDecl *TD,
61
0
                             unsigned MSLocalManglingNumber) override {
62
0
    return MSLocalManglingNumber;
63
0
  }
64
};
65
66
class MSHIPNumberingContext : public MicrosoftNumberingContext {
67
  std::unique_ptr<MangleNumberingContext> DeviceCtx;
68
69
public:
70
  using MicrosoftNumberingContext::getManglingNumber;
71
0
  MSHIPNumberingContext(MangleContext *DeviceMangler) {
72
0
    DeviceCtx = createItaniumNumberingContext(DeviceMangler);
73
0
  }
74
75
0
  unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override {
76
0
    return DeviceCtx->getManglingNumber(CallOperator);
77
0
  }
78
79
  unsigned getManglingNumber(const TagDecl *TD,
80
0
                             unsigned MSLocalManglingNumber) override {
81
0
    unsigned DeviceN = DeviceCtx->getManglingNumber(TD, MSLocalManglingNumber);
82
0
    unsigned HostN =
83
0
        MicrosoftNumberingContext::getManglingNumber(TD, MSLocalManglingNumber);
84
0
    if (DeviceN > 0xFFFF || HostN > 0xFFFF) {
85
0
      DiagnosticsEngine &Diags = TD->getASTContext().getDiagnostics();
86
0
      unsigned DiagID = Diags.getCustomDiagID(
87
0
          DiagnosticsEngine::Error, "Mangling number exceeds limit (65535)");
88
0
      Diags.Report(TD->getLocation(), DiagID);
89
0
    }
90
0
    return (DeviceN << 16) | HostN;
91
0
  }
92
};
93
94
class MSSYCLNumberingContext : public MicrosoftNumberingContext {
95
  std::unique_ptr<MangleNumberingContext> DeviceCtx;
96
97
public:
98
0
  MSSYCLNumberingContext(MangleContext *DeviceMangler) {
99
0
    DeviceCtx = createItaniumNumberingContext(DeviceMangler);
100
0
  }
101
102
0
  unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override {
103
0
    return DeviceCtx->getManglingNumber(CallOperator);
104
0
  }
105
};
106
107
class MicrosoftCXXABI : public CXXABI {
108
  ASTContext &Context;
109
  llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> RecordToCopyCtor;
110
111
  llvm::SmallDenseMap<TagDecl *, DeclaratorDecl *>
112
      UnnamedTagDeclToDeclaratorDecl;
113
  llvm::SmallDenseMap<TagDecl *, TypedefNameDecl *>
114
      UnnamedTagDeclToTypedefNameDecl;
115
116
  // MangleContext for device numbering context, which is based on Itanium C++
117
  // ABI.
118
  std::unique_ptr<MangleContext> DeviceMangler;
119
120
public:
121
0
  MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) {
122
0
    if (Context.getLangOpts().CUDA && Context.getAuxTargetInfo()) {
123
0
      assert(Context.getTargetInfo().getCXXABI().isMicrosoft() &&
124
0
             Context.getAuxTargetInfo()->getCXXABI().isItaniumFamily() &&
125
0
             "Unexpected combination of C++ ABIs.");
126
0
      DeviceMangler.reset(
127
0
          Context.createMangleContext(Context.getAuxTargetInfo()));
128
0
    }
129
0
    else if (Context.getLangOpts().isSYCL()) {
130
0
      DeviceMangler.reset(
131
0
          ItaniumMangleContext::create(Context, Context.getDiagnostics()));
132
0
    }
133
0
  }
134
135
  MemberPointerInfo
136
  getMemberPointerInfo(const MemberPointerType *MPT) const override;
137
138
0
  CallingConv getDefaultMethodCallConv(bool isVariadic) const override {
139
0
    if (!isVariadic &&
140
0
        Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
141
0
      return CC_X86ThisCall;
142
0
    return Context.getTargetInfo().getDefaultCallingConv();
143
0
  }
144
145
0
  bool isNearlyEmpty(const CXXRecordDecl *RD) const override {
146
0
    llvm_unreachable("unapplicable to the MS ABI");
147
0
  }
148
149
  const CXXConstructorDecl *
150
0
  getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override {
151
0
    return RecordToCopyCtor[RD];
152
0
  }
153
154
  void
155
  addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
156
0
                                       CXXConstructorDecl *CD) override {
157
0
    assert(CD != nullptr);
158
0
    assert(RecordToCopyCtor[RD] == nullptr || RecordToCopyCtor[RD] == CD);
159
0
    RecordToCopyCtor[RD] = CD;
160
0
  }
161
162
  void addTypedefNameForUnnamedTagDecl(TagDecl *TD,
163
0
                                       TypedefNameDecl *DD) override {
164
0
    TD = TD->getCanonicalDecl();
165
0
    DD = DD->getCanonicalDecl();
166
0
    TypedefNameDecl *&I = UnnamedTagDeclToTypedefNameDecl[TD];
167
0
    if (!I)
168
0
      I = DD;
169
0
  }
170
171
0
  TypedefNameDecl *getTypedefNameForUnnamedTagDecl(const TagDecl *TD) override {
172
0
    return UnnamedTagDeclToTypedefNameDecl.lookup(
173
0
        const_cast<TagDecl *>(TD->getCanonicalDecl()));
174
0
  }
175
176
  void addDeclaratorForUnnamedTagDecl(TagDecl *TD,
177
0
                                      DeclaratorDecl *DD) override {
178
0
    TD = TD->getCanonicalDecl();
179
0
    DD = cast<DeclaratorDecl>(DD->getCanonicalDecl());
180
0
    DeclaratorDecl *&I = UnnamedTagDeclToDeclaratorDecl[TD];
181
0
    if (!I)
182
0
      I = DD;
183
0
  }
184
185
0
  DeclaratorDecl *getDeclaratorForUnnamedTagDecl(const TagDecl *TD) override {
186
0
    return UnnamedTagDeclToDeclaratorDecl.lookup(
187
0
        const_cast<TagDecl *>(TD->getCanonicalDecl()));
188
0
  }
189
190
  std::unique_ptr<MangleNumberingContext>
191
0
  createMangleNumberingContext() const override {
192
0
    if (Context.getLangOpts().CUDA && Context.getAuxTargetInfo()) {
193
0
      assert(DeviceMangler && "Missing device mangler");
194
0
      return std::make_unique<MSHIPNumberingContext>(DeviceMangler.get());
195
0
    } else if (Context.getLangOpts().isSYCL()) {
196
0
      assert(DeviceMangler && "Missing device mangler");
197
0
      return std::make_unique<MSSYCLNumberingContext>(DeviceMangler.get());
198
0
    }
199
200
0
    return std::make_unique<MicrosoftNumberingContext>();
201
0
  }
202
};
203
}
204
205
// getNumBases() seems to only give us the number of direct bases, and not the
206
// total.  This function tells us if we inherit from anybody that uses MI, or if
207
// we have a non-primary base class, which uses the multiple inheritance model.
208
0
static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {
209
0
  while (RD->getNumBases() > 0) {
210
0
    if (RD->getNumBases() > 1)
211
0
      return true;
212
0
    assert(RD->getNumBases() == 1);
213
0
    const CXXRecordDecl *Base =
214
0
        RD->bases_begin()->getType()->getAsCXXRecordDecl();
215
0
    if (RD->isPolymorphic() && !Base->isPolymorphic())
216
0
      return true;
217
0
    RD = Base;
218
0
  }
219
0
  return false;
220
0
}
221
222
0
MSInheritanceModel CXXRecordDecl::calculateInheritanceModel() const {
223
0
  if (!hasDefinition() || isParsingBaseSpecifiers())
224
0
    return MSInheritanceModel::Unspecified;
225
0
  if (getNumVBases() > 0)
226
0
    return MSInheritanceModel::Virtual;
227
0
  if (usesMultipleInheritanceModel(this))
228
0
    return MSInheritanceModel::Multiple;
229
0
  return MSInheritanceModel::Single;
230
0
}
231
232
0
MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const {
233
0
  MSInheritanceAttr *IA = getAttr<MSInheritanceAttr>();
234
0
  assert(IA && "Expected MSInheritanceAttr on the CXXRecordDecl!");
235
0
  return IA->getInheritanceModel();
236
0
}
237
238
0
bool CXXRecordDecl::nullFieldOffsetIsZero() const {
239
0
  return !inheritanceModelHasOnlyOneField(/*IsMemberFunction=*/false,
240
0
                                          getMSInheritanceModel()) ||
241
0
         (hasDefinition() && isPolymorphic());
242
0
}
243
244
0
MSVtorDispMode CXXRecordDecl::getMSVtorDispMode() const {
245
0
  if (MSVtorDispAttr *VDA = getAttr<MSVtorDispAttr>())
246
0
    return VDA->getVtorDispMode();
247
0
  return getASTContext().getLangOpts().getVtorDispMode();
248
0
}
249
250
// Returns the number of pointer and integer slots used to represent a member
251
// pointer in the MS C++ ABI.
252
//
253
// Member function pointers have the following general form;  however, fields
254
// are dropped as permitted (under the MSVC interpretation) by the inheritance
255
// model of the actual class.
256
//
257
//   struct {
258
//     // A pointer to the member function to call.  If the member function is
259
//     // virtual, this will be a thunk that forwards to the appropriate vftable
260
//     // slot.
261
//     void *FunctionPointerOrVirtualThunk;
262
//
263
//     // An offset to add to the address of the vbtable pointer after
264
//     // (possibly) selecting the virtual base but before resolving and calling
265
//     // the function.
266
//     // Only needed if the class has any virtual bases or bases at a non-zero
267
//     // offset.
268
//     int NonVirtualBaseAdjustment;
269
//
270
//     // The offset of the vb-table pointer within the object.  Only needed for
271
//     // incomplete types.
272
//     int VBPtrOffset;
273
//
274
//     // An offset within the vb-table that selects the virtual base containing
275
//     // the member.  Loading from this offset produces a new offset that is
276
//     // added to the address of the vb-table pointer to produce the base.
277
//     int VirtualBaseAdjustmentOffset;
278
//   };
279
static std::pair<unsigned, unsigned>
280
0
getMSMemberPointerSlots(const MemberPointerType *MPT) {
281
0
  const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
282
0
  MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
283
0
  unsigned Ptrs = 0;
284
0
  unsigned Ints = 0;
285
0
  if (MPT->isMemberFunctionPointer())
286
0
    Ptrs = 1;
287
0
  else
288
0
    Ints = 1;
289
0
  if (inheritanceModelHasNVOffsetField(MPT->isMemberFunctionPointer(),
290
0
                                          Inheritance))
291
0
    Ints++;
292
0
  if (inheritanceModelHasVBPtrOffsetField(Inheritance))
293
0
    Ints++;
294
0
  if (inheritanceModelHasVBTableOffsetField(Inheritance))
295
0
    Ints++;
296
0
  return std::make_pair(Ptrs, Ints);
297
0
}
298
299
CXXABI::MemberPointerInfo MicrosoftCXXABI::getMemberPointerInfo(
300
0
    const MemberPointerType *MPT) const {
301
  // The nominal struct is laid out with pointers followed by ints and aligned
302
  // to a pointer width if any are present and an int width otherwise.
303
0
  const TargetInfo &Target = Context.getTargetInfo();
304
0
  unsigned PtrSize = Target.getPointerWidth(LangAS::Default);
305
0
  unsigned IntSize = Target.getIntWidth();
306
307
0
  unsigned Ptrs, Ints;
308
0
  std::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT);
309
0
  MemberPointerInfo MPI;
310
0
  MPI.HasPadding = false;
311
0
  MPI.Width = Ptrs * PtrSize + Ints * IntSize;
312
313
  // When MSVC does x86_32 record layout, it aligns aggregate member pointers to
314
  // 8 bytes.  However, __alignof usually returns 4 for data memptrs and 8 for
315
  // function memptrs.
316
0
  if (Ptrs + Ints > 1 && Target.getTriple().isArch32Bit())
317
0
    MPI.Align = 64;
318
0
  else if (Ptrs)
319
0
    MPI.Align = Target.getPointerAlign(LangAS::Default);
320
0
  else
321
0
    MPI.Align = Target.getIntAlign();
322
323
0
  if (Target.getTriple().isArch64Bit()) {
324
0
    MPI.Width = llvm::alignTo(MPI.Width, MPI.Align);
325
0
    MPI.HasPadding = MPI.Width != (Ptrs * PtrSize + Ints * IntSize);
326
0
  }
327
0
  return MPI;
328
0
}
329
330
0
CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) {
331
0
  return new MicrosoftCXXABI(Ctx);
332
0
}