/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 | } |