/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/CodeGen/CGCXXABI.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===----- CGCXXABI.cpp - Interface to C++ ABIs ---------------------------===// |
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 an abstract class for C++ code generation. Concrete subclasses |
10 | | // of this implement code generation for specific C++ ABIs. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "CGCXXABI.h" |
15 | | #include "CGCleanup.h" |
16 | | #include "clang/AST/Attr.h" |
17 | | |
18 | | using namespace clang; |
19 | | using namespace CodeGen; |
20 | | |
21 | 31.3k | CGCXXABI::~CGCXXABI() { } |
22 | | |
23 | 0 | void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) { |
24 | 0 | DiagnosticsEngine &Diags = CGF.CGM.getDiags(); |
25 | 0 | unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, |
26 | 0 | "cannot yet compile %0 in this ABI"); |
27 | 0 | Diags.Report(CGF.getContext().getFullLoc(CGF.CurCodeDecl->getLocation()), |
28 | 0 | DiagID) |
29 | 0 | << S; |
30 | 0 | } |
31 | | |
32 | 0 | llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) { |
33 | 0 | return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T)); |
34 | 0 | } |
35 | | |
36 | | llvm::Type * |
37 | 0 | CGCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { |
38 | 0 | return CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); |
39 | 0 | } |
40 | | |
41 | | CGCallee CGCXXABI::EmitLoadOfMemberFunctionPointer( |
42 | | CodeGenFunction &CGF, const Expr *E, Address This, |
43 | | llvm::Value *&ThisPtrForCall, |
44 | 0 | llvm::Value *MemPtr, const MemberPointerType *MPT) { |
45 | 0 | ErrorUnsupportedABI(CGF, "calls through member pointers"); |
46 | |
|
47 | 0 | ThisPtrForCall = This.getPointer(); |
48 | 0 | const FunctionProtoType *FPT = |
49 | 0 | MPT->getPointeeType()->getAs<FunctionProtoType>(); |
50 | 0 | const auto *RD = |
51 | 0 | cast<CXXRecordDecl>(MPT->getClass()->castAs<RecordType>()->getDecl()); |
52 | 0 | llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType( |
53 | 0 | CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr)); |
54 | 0 | llvm::Constant *FnPtr = llvm::Constant::getNullValue(FTy->getPointerTo()); |
55 | 0 | return CGCallee::forDirect(FnPtr, FPT); |
56 | 0 | } |
57 | | |
58 | | llvm::Value * |
59 | | CGCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E, |
60 | | Address Base, llvm::Value *MemPtr, |
61 | 0 | const MemberPointerType *MPT) { |
62 | 0 | ErrorUnsupportedABI(CGF, "loads of member pointers"); |
63 | 0 | llvm::Type *Ty = CGF.ConvertType(MPT->getPointeeType()) |
64 | 0 | ->getPointerTo(Base.getAddressSpace()); |
65 | 0 | return llvm::Constant::getNullValue(Ty); |
66 | 0 | } |
67 | | |
68 | | llvm::Value *CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, |
69 | | const CastExpr *E, |
70 | 0 | llvm::Value *Src) { |
71 | 0 | ErrorUnsupportedABI(CGF, "member function pointer conversions"); |
72 | 0 | return GetBogusMemberPointer(E->getType()); |
73 | 0 | } |
74 | | |
75 | | llvm::Constant *CGCXXABI::EmitMemberPointerConversion(const CastExpr *E, |
76 | 0 | llvm::Constant *Src) { |
77 | 0 | return GetBogusMemberPointer(E->getType()); |
78 | 0 | } |
79 | | |
80 | | llvm::Value * |
81 | | CGCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, |
82 | | llvm::Value *L, |
83 | | llvm::Value *R, |
84 | | const MemberPointerType *MPT, |
85 | 0 | bool Inequality) { |
86 | 0 | ErrorUnsupportedABI(CGF, "member function pointer comparison"); |
87 | 0 | return CGF.Builder.getFalse(); |
88 | 0 | } |
89 | | |
90 | | llvm::Value * |
91 | | CGCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, |
92 | | llvm::Value *MemPtr, |
93 | 0 | const MemberPointerType *MPT) { |
94 | 0 | ErrorUnsupportedABI(CGF, "member function pointer null testing"); |
95 | 0 | return CGF.Builder.getFalse(); |
96 | 0 | } |
97 | | |
98 | | llvm::Constant * |
99 | 0 | CGCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { |
100 | 0 | return GetBogusMemberPointer(QualType(MPT, 0)); |
101 | 0 | } |
102 | | |
103 | 0 | llvm::Constant *CGCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) { |
104 | 0 | return GetBogusMemberPointer(CGM.getContext().getMemberPointerType( |
105 | 0 | MD->getType(), MD->getParent()->getTypeForDecl())); |
106 | 0 | } |
107 | | |
108 | | llvm::Constant *CGCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, |
109 | 0 | CharUnits offset) { |
110 | 0 | return GetBogusMemberPointer(QualType(MPT, 0)); |
111 | 0 | } |
112 | | |
113 | 0 | llvm::Constant *CGCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) { |
114 | 0 | return GetBogusMemberPointer(MPT); |
115 | 0 | } |
116 | | |
117 | 0 | bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) { |
118 | | // Fake answer. |
119 | 0 | return true; |
120 | 0 | } |
121 | | |
122 | 97.9k | void CGCXXABI::buildThisParam(CodeGenFunction &CGF, FunctionArgList ¶ms) { |
123 | 97.9k | const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl()); |
124 | | |
125 | | // FIXME: I'm not entirely sure I like using a fake decl just for code |
126 | | // generation. Maybe we can come up with a better way? |
127 | 97.9k | auto *ThisDecl = ImplicitParamDecl::Create( |
128 | 97.9k | CGM.getContext(), nullptr, MD->getLocation(), |
129 | 97.9k | &CGM.getContext().Idents.get("this"), MD->getThisType(), |
130 | 97.9k | ImplicitParamDecl::CXXThis); |
131 | 97.9k | params.push_back(ThisDecl); |
132 | 97.9k | CGF.CXXABIThisDecl = ThisDecl; |
133 | | |
134 | | // Compute the presumed alignment of 'this', which basically comes |
135 | | // down to whether we know it's a complete object or not. |
136 | 97.9k | auto &Layout = CGF.getContext().getASTRecordLayout(MD->getParent()); |
137 | 97.9k | if (MD->getParent()->getNumVBases() == 0 || // avoid vcall in common case |
138 | 1.86k | MD->getParent()->isEffectivelyFinal() || |
139 | 96.8k | isThisCompleteObject(CGF.CurGD)1.86k ) { |
140 | 96.8k | CGF.CXXABIThisAlignment = Layout.getAlignment(); |
141 | 1.13k | } else { |
142 | 1.13k | CGF.CXXABIThisAlignment = Layout.getNonVirtualAlignment(); |
143 | 1.13k | } |
144 | 97.9k | } |
145 | | |
146 | 97.9k | llvm::Value *CGCXXABI::loadIncomingCXXThis(CodeGenFunction &CGF) { |
147 | 97.9k | return CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getThisDecl(CGF)), |
148 | 97.9k | "this"); |
149 | 97.9k | } |
150 | | |
151 | 97.9k | void CGCXXABI::setCXXABIThisValue(CodeGenFunction &CGF, llvm::Value *ThisPtr) { |
152 | | /// Initialize the 'this' slot. |
153 | 97.9k | assert(getThisDecl(CGF) && "no 'this' variable for function"); |
154 | 97.9k | CGF.CXXABIThisValue = ThisPtr; |
155 | 97.9k | } |
156 | | |
157 | | void CGCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF, |
158 | 196 | RValue RV, QualType ResultType) { |
159 | 196 | assert(!CGF.hasAggregateEvaluationKind(ResultType) && |
160 | 196 | "cannot handle aggregates"); |
161 | 196 | CGF.EmitReturnOfRValue(RV, ResultType); |
162 | 196 | } |
163 | | |
164 | 650 | CharUnits CGCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) { |
165 | 650 | if (!requiresArrayCookie(expr)) |
166 | 524 | return CharUnits::Zero(); |
167 | 126 | return getArrayCookieSizeImpl(expr->getAllocatedType()); |
168 | 126 | } |
169 | | |
170 | 0 | CharUnits CGCXXABI::getArrayCookieSizeImpl(QualType elementType) { |
171 | | // BOGUS |
172 | 0 | return CharUnits::Zero(); |
173 | 0 | } |
174 | | |
175 | | Address CGCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, |
176 | | Address NewPtr, |
177 | | llvm::Value *NumElements, |
178 | | const CXXNewExpr *expr, |
179 | 0 | QualType ElementType) { |
180 | | // Should never be called. |
181 | 0 | ErrorUnsupportedABI(CGF, "array cookie initialization"); |
182 | 0 | return Address::invalid(); |
183 | 0 | } |
184 | | |
185 | | bool CGCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr, |
186 | 227 | QualType elementType) { |
187 | | // If the class's usual deallocation function takes two arguments, |
188 | | // it needs a cookie. |
189 | 227 | if (expr->doesUsualArrayDeleteWantSize()) |
190 | 18 | return true; |
191 | | |
192 | 209 | return elementType.isDestructedType(); |
193 | 209 | } |
194 | | |
195 | 677 | bool CGCXXABI::requiresArrayCookie(const CXXNewExpr *expr) { |
196 | | // If the class's usual deallocation function takes two arguments, |
197 | | // it needs a cookie. |
198 | 677 | if (expr->doesUsualArrayDeleteWantSize()) |
199 | 45 | return true; |
200 | | |
201 | 632 | return expr->getAllocatedType().isDestructedType(); |
202 | 632 | } |
203 | | |
204 | | void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, Address ptr, |
205 | | const CXXDeleteExpr *expr, QualType eltTy, |
206 | | llvm::Value *&numElements, |
207 | 241 | llvm::Value *&allocPtr, CharUnits &cookieSize) { |
208 | | // Derive a char* in the same address space as the pointer. |
209 | 241 | ptr = CGF.Builder.CreateElementBitCast(ptr, CGF.Int8Ty); |
210 | | |
211 | | // If we don't need an array cookie, bail out early. |
212 | 241 | if (!requiresArrayCookie(expr, eltTy)) { |
213 | 181 | allocPtr = ptr.getPointer(); |
214 | 181 | numElements = nullptr; |
215 | 181 | cookieSize = CharUnits::Zero(); |
216 | 181 | return; |
217 | 181 | } |
218 | | |
219 | 60 | cookieSize = getArrayCookieSizeImpl(eltTy); |
220 | 60 | Address allocAddr = |
221 | 60 | CGF.Builder.CreateConstInBoundsByteGEP(ptr, -cookieSize); |
222 | 60 | allocPtr = allocAddr.getPointer(); |
223 | 60 | numElements = readArrayCookieImpl(CGF, allocAddr, cookieSize); |
224 | 60 | } |
225 | | |
226 | | llvm::Value *CGCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, |
227 | | Address ptr, |
228 | 0 | CharUnits cookieSize) { |
229 | 0 | ErrorUnsupportedABI(CGF, "reading a new[] cookie"); |
230 | 0 | return llvm::ConstantInt::get(CGF.SizeTy, 0); |
231 | 0 | } |
232 | | |
233 | | /// Returns the adjustment, in bytes, required for the given |
234 | | /// member-pointer operation. Returns null if no adjustment is |
235 | | /// required. |
236 | 59 | llvm::Constant *CGCXXABI::getMemberPointerAdjustment(const CastExpr *E) { |
237 | 59 | assert(E->getCastKind() == CK_DerivedToBaseMemberPointer || |
238 | 59 | E->getCastKind() == CK_BaseToDerivedMemberPointer); |
239 | | |
240 | 59 | QualType derivedType; |
241 | 59 | if (E->getCastKind() == CK_DerivedToBaseMemberPointer) |
242 | 9 | derivedType = E->getSubExpr()->getType(); |
243 | 50 | else |
244 | 50 | derivedType = E->getType(); |
245 | | |
246 | 59 | const CXXRecordDecl *derivedClass = |
247 | 59 | derivedType->castAs<MemberPointerType>()->getClass()->getAsCXXRecordDecl(); |
248 | | |
249 | 59 | return CGM.GetNonVirtualBaseClassOffset(derivedClass, |
250 | 59 | E->path_begin(), |
251 | 59 | E->path_end()); |
252 | 59 | } |
253 | | |
254 | | llvm::BasicBlock * |
255 | | CGCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF, |
256 | 0 | const CXXRecordDecl *RD) { |
257 | 0 | if (CGM.getTarget().getCXXABI().hasConstructorVariants()) |
258 | 0 | llvm_unreachable("shouldn't be called in this ABI"); |
259 | |
|
260 | 0 | ErrorUnsupportedABI(CGF, "complete object detection in ctor"); |
261 | 0 | return nullptr; |
262 | 0 | } |
263 | | |
264 | | void CGCXXABI::setCXXDestructorDLLStorage(llvm::GlobalValue *GV, |
265 | | const CXXDestructorDecl *Dtor, |
266 | 16.2k | CXXDtorType DT) const { |
267 | | // Assume the base C++ ABI has no special rules for destructor variants. |
268 | 16.2k | CGM.setDLLImportDLLExport(GV, Dtor); |
269 | 16.2k | } |
270 | | |
271 | | llvm::GlobalValue::LinkageTypes CGCXXABI::getCXXDestructorLinkage( |
272 | 32.6k | GVALinkage Linkage, const CXXDestructorDecl *Dtor, CXXDtorType DT) const { |
273 | | // Delegate back to CGM by default. |
274 | 32.6k | return CGM.getLLVMLinkageForDeclarator(Dtor, Linkage, |
275 | 32.6k | /*IsConstantVariable=*/false); |
276 | 32.6k | } |
277 | | |
278 | 0 | bool CGCXXABI::NeedsVTTParameter(GlobalDecl GD) { |
279 | 0 | return false; |
280 | 0 | } |
281 | | |
282 | | llvm::CallInst * |
283 | | CGCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF, |
284 | 12 | llvm::Value *Exn) { |
285 | | // Just call std::terminate and ignore the violating exception. |
286 | 12 | return CGF.EmitNounwindRuntimeCall(CGF.CGM.getTerminateFn()); |
287 | 12 | } |
288 | | |
289 | 220 | CatchTypeInfo CGCXXABI::getCatchAllTypeInfo() { |
290 | 220 | return CatchTypeInfo{nullptr, 0}; |
291 | 220 | } |
292 | | |
293 | 15 | std::vector<CharUnits> CGCXXABI::getVBPtrOffsets(const CXXRecordDecl *RD) { |
294 | 15 | return std::vector<CharUnits>(); |
295 | 15 | } |
296 | | |
297 | | CGCXXABI::AddedStructorArgCounts CGCXXABI::addImplicitConstructorArgs( |
298 | | CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type, |
299 | 51.0k | bool ForVirtualBase, bool Delegating, CallArgList &Args) { |
300 | 51.0k | AddedStructorArgs AddedArgs = |
301 | 51.0k | getImplicitConstructorArgs(CGF, D, Type, ForVirtualBase, Delegating); |
302 | 51.2k | for (size_t i = 0; i < AddedArgs.Prefix.size(); ++i136 ) { |
303 | 136 | Args.insert(Args.begin() + 1 + i, |
304 | 136 | CallArg(RValue::get(AddedArgs.Prefix[i].Value), |
305 | 136 | AddedArgs.Prefix[i].Type)); |
306 | 136 | } |
307 | 472 | for (const auto &arg : AddedArgs.Suffix) { |
308 | 472 | Args.add(RValue::get(arg.Value), arg.Type); |
309 | 472 | } |
310 | 51.0k | return AddedStructorArgCounts(AddedArgs.Prefix.size(), |
311 | 51.0k | AddedArgs.Suffix.size()); |
312 | 51.0k | } |