ItaniumCXXABI.cpp revision e9fd7eb6c67676dc27e84eac429aec4f3be51f26
1//===------- ItaniumCXXABI.cpp - Emit LLVM Code from ASTs for a Module ----===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This provides C++ code generation targetting the Itanium C++ ABI. The class 11// in this file generates structures that follow the Itanium C++ ABI, which is 12// documented at: 13// http://www.codesourcery.com/public/cxx-abi/abi.html 14// http://www.codesourcery.com/public/cxx-abi/abi-eh.html 15// 16// It also supports the closely-related ARM ABI, documented at: 17// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf 18// 19//===----------------------------------------------------------------------===// 20 21#include "CGCXXABI.h" 22#include "CodeGenFunction.h" 23#include "CodeGenModule.h" 24#include "Mangle.h" 25#include <clang/AST/Type.h> 26#include <llvm/Value.h> 27 28using namespace clang; 29using namespace CodeGen; 30 31namespace { 32class ItaniumCXXABI : public CodeGen::CGCXXABI { 33protected: 34 CodeGenModule &CGM; 35 CodeGen::MangleContext MangleCtx; 36 bool IsARM; 37public: 38 ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) : 39 CGM(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()), IsARM(IsARM) { } 40 41 CodeGen::MangleContext &getMangleContext() { 42 return MangleCtx; 43 } 44 45 bool RequiresNonZeroInitializer(QualType T); 46 bool RequiresNonZeroInitializer(const CXXRecordDecl *D); 47 48 llvm::Value *EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, 49 llvm::Value *&This, 50 llvm::Value *MemFnPtr, 51 const MemberPointerType *MPT); 52 53 void EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, 54 const CastExpr *E, 55 llvm::Value *Src, 56 llvm::Value *Dest, 57 bool VolatileDest); 58 59 llvm::Constant *EmitMemberFunctionPointerConversion(llvm::Constant *C, 60 const CastExpr *E); 61 62 void EmitNullMemberFunctionPointer(CodeGenFunction &CGF, 63 const MemberPointerType *MPT, 64 llvm::Value *Dest, 65 bool VolatileDest); 66 67 llvm::Constant *EmitNullMemberFunctionPointer(const MemberPointerType *MPT); 68 69 void EmitMemberFunctionPointer(CodeGenFunction &CGF, 70 const CXXMethodDecl *MD, 71 llvm::Value *Dest, 72 bool VolatileDest); 73 74 llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD); 75 76 llvm::Value *EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, 77 llvm::Value *L, 78 llvm::Value *R, 79 const MemberPointerType *MPT, 80 bool Inequality); 81 82 llvm::Value *EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, 83 llvm::Value *Addr, 84 const MemberPointerType *MPT); 85 86private: 87 void GetMemberFunctionPointer(const CXXMethodDecl *MD, 88 llvm::Constant *(&Array)[2]); 89}; 90 91class ARMCXXABI : public ItaniumCXXABI { 92public: 93 ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {} 94}; 95} 96 97CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) { 98 return new ItaniumCXXABI(CGM); 99} 100 101CodeGen::CGCXXABI *CodeGen::CreateARMCXXABI(CodeGenModule &CGM) { 102 return new ARMCXXABI(CGM); 103} 104 105void ItaniumCXXABI::GetMemberFunctionPointer(const CXXMethodDecl *MD, 106 llvm::Constant *(&MemPtr)[2]) { 107 assert(MD->isInstance() && "Member function must not be static!"); 108 109 MD = MD->getCanonicalDecl(); 110 111 CodeGenTypes &Types = CGM.getTypes(); 112 const llvm::Type *ptrdiff_t = 113 Types.ConvertType(CGM.getContext().getPointerDiffType()); 114 115 // Get the function pointer (or index if this is a virtual function). 116 if (MD->isVirtual()) { 117 uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD); 118 119 // FIXME: We shouldn't use / 8 here. 120 uint64_t PointerWidthInBytes = 121 CGM.getContext().Target.getPointerWidth(0) / 8; 122 uint64_t VTableOffset = (Index * PointerWidthInBytes); 123 124 if (IsARM) { 125 // ARM C++ ABI 3.2.1: 126 // This ABI specifies that adj contains twice the this 127 // adjustment, plus 1 if the member function is virtual. The 128 // least significant bit of adj then makes exactly the same 129 // discrimination as the least significant bit of ptr does for 130 // Itanium. 131 MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset); 132 MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 1); 133 } else { 134 // Itanium C++ ABI 2.3: 135 // For a virtual function, [the pointer field] is 1 plus the 136 // virtual table offset (in bytes) of the function, 137 // represented as a ptrdiff_t. 138 MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1); 139 MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); 140 } 141 } else { 142 const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); 143 const llvm::Type *Ty; 144 // Check whether the function has a computable LLVM signature. 145 if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) { 146 // The function has a computable LLVM signature; use the correct type. 147 Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic()); 148 } else { 149 // Use an arbitrary non-function type to tell GetAddrOfFunction that the 150 // function type is incomplete. 151 Ty = ptrdiff_t; 152 } 153 154 llvm::Constant *Addr = CGM.GetAddrOfFunction(MD, Ty); 155 MemPtr[0] = llvm::ConstantExpr::getPtrToInt(Addr, ptrdiff_t); 156 MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); 157 } 158} 159 160 161/// In the Itanium and ARM ABIs, method pointers have the form: 162/// struct { ptrdiff_t ptr; ptrdiff_t adj; } memptr; 163/// 164/// In the Itanium ABI: 165/// - method pointers are virtual if (memptr.ptr & 1) is nonzero 166/// - the this-adjustment is (memptr.adj) 167/// - the virtual offset is (memptr.ptr - 1) 168/// 169/// In the ARM ABI: 170/// - method pointers are virtual if (memptr.adj & 1) is nonzero 171/// - the this-adjustment is (memptr.adj >> 1) 172/// - the virtual offset is (memptr.ptr) 173/// ARM uses 'adj' for the virtual flag because Thumb functions 174/// may be only single-byte aligned. 175/// 176/// If the member is virtual, the adjusted 'this' pointer points 177/// to a vtable pointer from which the virtual offset is applied. 178/// 179/// If the member is non-virtual, memptr.ptr is the address of 180/// the function to call. 181llvm::Value * 182ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, 183 llvm::Value *&This, 184 llvm::Value *MemFnPtr, 185 const MemberPointerType *MPT) { 186 CGBuilderTy &Builder = CGF.Builder; 187 188 const FunctionProtoType *FPT = 189 MPT->getPointeeType()->getAs<FunctionProtoType>(); 190 const CXXRecordDecl *RD = 191 cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl()); 192 193 const llvm::FunctionType *FTy = 194 CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), 195 FPT->isVariadic()); 196 197 const llvm::IntegerType *ptrdiff = CGF.IntPtrTy; 198 llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(ptrdiff, 1); 199 200 llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("memptr.virtual"); 201 llvm::BasicBlock *FnNonVirtual = CGF.createBasicBlock("memptr.nonvirtual"); 202 llvm::BasicBlock *FnEnd = CGF.createBasicBlock("memptr.end"); 203 204 // Load memptr.adj, which is in the second field. 205 llvm::Value *RawAdj = Builder.CreateStructGEP(MemFnPtr, 1); 206 RawAdj = Builder.CreateLoad(RawAdj, "memptr.adj"); 207 208 // Compute the true adjustment. 209 llvm::Value *Adj = RawAdj; 210 if (IsARM) 211 Adj = Builder.CreateAShr(Adj, ptrdiff_1, "memptr.adj.shifted"); 212 213 // Apply the adjustment and cast back to the original struct type 214 // for consistency. 215 llvm::Value *Ptr = Builder.CreateBitCast(This, Builder.getInt8PtrTy()); 216 Ptr = Builder.CreateInBoundsGEP(Ptr, Adj); 217 This = Builder.CreateBitCast(Ptr, This->getType(), "this.adjusted"); 218 219 // Load the function pointer. 220 llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0); 221 llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "memptr.ptr"); 222 223 // If the LSB in the function pointer is 1, the function pointer points to 224 // a virtual function. 225 llvm::Value *IsVirtual; 226 if (IsARM) 227 IsVirtual = Builder.CreateAnd(RawAdj, ptrdiff_1); 228 else 229 IsVirtual = Builder.CreateAnd(FnAsInt, ptrdiff_1); 230 IsVirtual = Builder.CreateIsNotNull(IsVirtual, "memptr.isvirtual"); 231 Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); 232 233 // In the virtual path, the adjustment left 'This' pointing to the 234 // vtable of the correct base subobject. The "function pointer" is an 235 // offset within the vtable (+1 for the virtual flag on non-ARM). 236 CGF.EmitBlock(FnVirtual); 237 238 // Cast the adjusted this to a pointer to vtable pointer and load. 239 const llvm::Type *VTableTy = Builder.getInt8PtrTy(); 240 llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo()); 241 VTable = Builder.CreateLoad(VTable, "memptr.vtable"); 242 243 // Apply the offset. 244 llvm::Value *VTableOffset = FnAsInt; 245 if (!IsARM) VTableOffset = Builder.CreateSub(VTableOffset, ptrdiff_1); 246 VTable = Builder.CreateGEP(VTable, VTableOffset); 247 248 // Load the virtual function to call. 249 VTable = Builder.CreateBitCast(VTable, FTy->getPointerTo()->getPointerTo()); 250 llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "memptr.virtualfn"); 251 CGF.EmitBranch(FnEnd); 252 253 // In the non-virtual path, the function pointer is actually a 254 // function pointer. 255 CGF.EmitBlock(FnNonVirtual); 256 llvm::Value *NonVirtualFn = 257 Builder.CreateIntToPtr(FnAsInt, FTy->getPointerTo(), "memptr.nonvirtualfn"); 258 259 // We're done. 260 CGF.EmitBlock(FnEnd); 261 llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo()); 262 Callee->reserveOperandSpace(2); 263 Callee->addIncoming(VirtualFn, FnVirtual); 264 Callee->addIncoming(NonVirtualFn, FnNonVirtual); 265 return Callee; 266} 267 268/// Perform a derived-to-base or base-to-derived member pointer conversion. 269void ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, 270 const CastExpr *E, 271 llvm::Value *Src, 272 llvm::Value *Dest, 273 bool VolatileDest) { 274 assert(E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer || 275 E->getCastKind() == CastExpr::CK_BaseToDerivedMemberPointer); 276 277 CGBuilderTy &Builder = CGF.Builder; 278 279 const MemberPointerType *SrcTy = 280 E->getSubExpr()->getType()->getAs<MemberPointerType>(); 281 const MemberPointerType *DestTy = E->getType()->getAs<MemberPointerType>(); 282 283 const CXXRecordDecl *SrcDecl = SrcTy->getClass()->getAsCXXRecordDecl(); 284 const CXXRecordDecl *DestDecl = DestTy->getClass()->getAsCXXRecordDecl(); 285 286 llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr"); 287 SrcPtr = Builder.CreateLoad(SrcPtr); 288 289 llvm::Value *SrcAdj = Builder.CreateStructGEP(Src, 1, "src.adj"); 290 SrcAdj = Builder.CreateLoad(SrcAdj); 291 292 llvm::Value *DstPtr = Builder.CreateStructGEP(Dest, 0, "dst.ptr"); 293 Builder.CreateStore(SrcPtr, DstPtr, VolatileDest); 294 295 llvm::Value *DstAdj = Builder.CreateStructGEP(Dest, 1, "dst.adj"); 296 297 bool DerivedToBase = 298 E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer; 299 300 const CXXRecordDecl *BaseDecl, *DerivedDecl; 301 if (DerivedToBase) 302 DerivedDecl = SrcDecl, BaseDecl = DestDecl; 303 else 304 BaseDecl = SrcDecl, DerivedDecl = DestDecl; 305 306 if (llvm::Constant *Adj = 307 CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, 308 E->path_begin(), 309 E->path_end())) { 310 // The this-adjustment is left-shifted by 1 on ARM. 311 if (IsARM) { 312 uint64_t Offset = cast<llvm::ConstantInt>(Adj)->getZExtValue(); 313 Offset <<= 1; 314 Adj = llvm::ConstantInt::get(Adj->getType(), Offset); 315 } 316 317 if (DerivedToBase) 318 SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj"); 319 else 320 SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj"); 321 } 322 323 Builder.CreateStore(SrcAdj, DstAdj, VolatileDest); 324} 325 326llvm::Constant * 327ItaniumCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C, 328 const CastExpr *E) { 329 const MemberPointerType *SrcTy = 330 E->getSubExpr()->getType()->getAs<MemberPointerType>(); 331 const MemberPointerType *DestTy = 332 E->getType()->getAs<MemberPointerType>(); 333 334 bool DerivedToBase = 335 E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer; 336 337 const CXXRecordDecl *DerivedDecl; 338 if (DerivedToBase) 339 DerivedDecl = SrcTy->getClass()->getAsCXXRecordDecl(); 340 else 341 DerivedDecl = DestTy->getClass()->getAsCXXRecordDecl(); 342 343 // Calculate the offset to the base class. 344 llvm::Constant *Offset = 345 CGM.GetNonVirtualBaseClassOffset(DerivedDecl, 346 E->path_begin(), 347 E->path_end()); 348 // If there's no offset, we're done. 349 if (!Offset) return C; 350 351 // The this-adjustment is left-shifted by 1 on ARM. 352 if (IsARM) { 353 uint64_t OffsetV = cast<llvm::ConstantInt>(Offset)->getZExtValue(); 354 OffsetV <<= 1; 355 Offset = llvm::ConstantInt::get(Offset->getType(), OffsetV); 356 } 357 358 llvm::ConstantStruct *CS = cast<llvm::ConstantStruct>(C); 359 360 llvm::Constant *Values[2] = { 361 CS->getOperand(0), 362 llvm::ConstantExpr::getAdd(CS->getOperand(1), Offset) 363 }; 364 return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2, 365 /*Packed=*/false); 366} 367 368 369void ItaniumCXXABI::EmitNullMemberFunctionPointer(CodeGenFunction &CGF, 370 const MemberPointerType *MPT, 371 llvm::Value *Dest, 372 bool VolatileDest) { 373 // Should this be "unabstracted" and implemented in terms of the 374 // Constant version? 375 376 CGBuilderTy &Builder = CGF.Builder; 377 378 const llvm::IntegerType *PtrDiffTy = CGF.IntPtrTy; 379 llvm::Value *Zero = llvm::ConstantInt::get(PtrDiffTy, 0); 380 381 llvm::Value *Ptr = Builder.CreateStructGEP(Dest, 0, "ptr"); 382 Builder.CreateStore(Zero, Ptr, VolatileDest); 383 384 llvm::Value *Adj = Builder.CreateStructGEP(Dest, 1, "adj"); 385 Builder.CreateStore(Zero, Adj, VolatileDest); 386} 387 388llvm::Constant * 389ItaniumCXXABI::EmitNullMemberFunctionPointer(const MemberPointerType *MPT) { 390 return CGM.EmitNullConstant(QualType(MPT, 0)); 391} 392 393llvm::Constant * 394ItaniumCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) { 395 llvm::Constant *Values[2]; 396 GetMemberFunctionPointer(MD, Values); 397 398 return llvm::ConstantStruct::get(CGM.getLLVMContext(), 399 Values, 2, /*Packed=*/false); 400} 401 402void ItaniumCXXABI::EmitMemberFunctionPointer(CodeGenFunction &CGF, 403 const CXXMethodDecl *MD, 404 llvm::Value *DestPtr, 405 bool VolatileDest) { 406 llvm::Constant *Values[2]; 407 GetMemberFunctionPointer(MD, Values); 408 409 CGBuilderTy &Builder = CGF.Builder; 410 411 llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "memptr.ptr"); 412 Builder.CreateStore(Values[0], DstPtr, VolatileDest); 413 414 llvm::Value *AdjPtr = Builder.CreateStructGEP(DestPtr, 1, "memptr.adj"); 415 Builder.CreateStore(Values[1], AdjPtr, VolatileDest); 416} 417 418/// The comparison algorithm is pretty easy: the member pointers are 419/// the same if they're either bitwise identical *or* both null. 420/// 421/// ARM is different here only because null-ness is more complicated. 422llvm::Value * 423ItaniumCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, 424 llvm::Value *L, 425 llvm::Value *R, 426 const MemberPointerType *MPT, 427 bool Inequality) { 428 CGBuilderTy &Builder = CGF.Builder; 429 430 llvm::Value *LPtr = Builder.CreateLoad(Builder.CreateStructGEP(L, 0), 431 "lhs.memptr.ptr"); 432 llvm::Value *RPtr = Builder.CreateLoad(Builder.CreateStructGEP(R, 0), 433 "rhs.memptr.ptr"); 434 435 // The Itanium tautology is: 436 // (L == R) <==> (L.ptr == R.ptr /\ (L.ptr == 0 \/ L.adj == R.adj)) 437 // The ARM tautology is: 438 // (L == R) <==> (L.ptr == R.ptr /\ 439 // (L.adj == R.adj \/ 440 // (L.ptr == 0 /\ ((L.adj|R.adj) & 1) == 0))) 441 // The inequality tautologies have exactly the same structure, except 442 // applying De Morgan's laws. 443 444 llvm::ICmpInst::Predicate Eq; 445 llvm::Instruction::BinaryOps And, Or; 446 if (Inequality) { 447 Eq = llvm::ICmpInst::ICMP_NE; 448 And = llvm::Instruction::Or; 449 Or = llvm::Instruction::And; 450 } else { 451 Eq = llvm::ICmpInst::ICMP_EQ; 452 And = llvm::Instruction::And; 453 Or = llvm::Instruction::Or; 454 } 455 456 // This condition tests whether L.ptr == R.ptr. This must always be 457 // true for equality to hold. 458 llvm::Value *PtrEq = Builder.CreateICmp(Eq, LPtr, RPtr, "cmp.ptr"); 459 460 // This condition, together with the assumption that L.ptr == R.ptr, 461 // tests whether the pointers are both null. ARM imposes an extra 462 // condition. 463 llvm::Value *Zero = llvm::Constant::getNullValue(LPtr->getType()); 464 llvm::Value *EqZero = Builder.CreateICmp(Eq, LPtr, Zero, "cmp.ptr.null"); 465 466 // This condition tests whether L.adj == R.adj. If this isn't 467 // true, the pointers are unequal unless they're both null. 468 llvm::Value *LAdj = Builder.CreateLoad(Builder.CreateStructGEP(L, 1), 469 "lhs.memptr.adj"); 470 llvm::Value *RAdj = Builder.CreateLoad(Builder.CreateStructGEP(R, 1), 471 "rhs.memptr.adj"); 472 llvm::Value *AdjEq = Builder.CreateICmp(Eq, LAdj, RAdj, "cmp.adj"); 473 474 // Null member function pointers on ARM clear the low bit of Adj, 475 // so the zero condition has to check that neither low bit is set. 476 if (IsARM) { 477 llvm::Value *One = llvm::ConstantInt::get(LPtr->getType(), 1); 478 479 // Compute (l.adj | r.adj) & 1 and test it against zero. 480 llvm::Value *OrAdj = Builder.CreateOr(LAdj, RAdj, "or.adj"); 481 llvm::Value *OrAdjAnd1 = Builder.CreateAnd(OrAdj, One); 482 llvm::Value *OrAdjAnd1EqZero = Builder.CreateICmp(Eq, OrAdjAnd1, Zero, 483 "cmp.or.adj"); 484 EqZero = Builder.CreateBinOp(And, EqZero, OrAdjAnd1EqZero); 485 } 486 487 // Tie together all our conditions. 488 llvm::Value *Result = Builder.CreateBinOp(Or, EqZero, AdjEq); 489 Result = Builder.CreateBinOp(And, PtrEq, Result, 490 Inequality ? "memptr.ne" : "memptr.eq"); 491 return Result; 492} 493 494llvm::Value * 495ItaniumCXXABI::EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, 496 llvm::Value *MemPtr, 497 const MemberPointerType *MPT) { 498 CGBuilderTy &Builder = CGF.Builder; 499 500 // In Itanium, a member function pointer is null if 'ptr' is null. 501 llvm::Value *Ptr = 502 Builder.CreateLoad(Builder.CreateStructGEP(MemPtr, 0), "memptr.ptr"); 503 504 llvm::Constant *Zero = llvm::ConstantInt::get(Ptr->getType(), 0); 505 llvm::Value *Result = Builder.CreateICmpNE(Ptr, Zero, "memptr.tobool"); 506 507 // In ARM, it's that, plus the low bit of 'adj' must be zero. 508 if (IsARM) { 509 llvm::Constant *One = llvm::ConstantInt::get(Ptr->getType(), 1); 510 llvm::Value *Adj = 511 Builder.CreateLoad(Builder.CreateStructGEP(MemPtr, 1), "memptr.adj"); 512 llvm::Value *VirtualBit = Builder.CreateAnd(Adj, One, "memptr.virtualbit"); 513 llvm::Value *IsNotVirtual = Builder.CreateICmpEQ(VirtualBit, Zero, 514 "memptr.notvirtual"); 515 Result = Builder.CreateAnd(Result, IsNotVirtual); 516 } 517 518 return Result; 519} 520 521bool ItaniumCXXABI::RequiresNonZeroInitializer(QualType T) { 522 return CGM.getTypes().ContainsPointerToDataMember(T); 523} 524 525bool ItaniumCXXABI::RequiresNonZeroInitializer(const CXXRecordDecl *D) { 526 return CGM.getTypes().ContainsPointerToDataMember(D); 527} 528