void CodeGenVTables::addVTableComponent( ConstantArrayBuilder &builder, const VTableLayout &layout, unsigned idx, llvm::Constant *rtti, unsigned &nextVTableThunkIndex) { auto &component = layout.vtable_components()[idx]; auto addOffsetConstant = [&](CharUnits offset) { builder.add(llvm::ConstantExpr::getIntToPtr( llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity()), CGM.Int8PtrTy)); }; switch (component.getKind()) { case VTableComponent::CK_VCallOffset: return addOffsetConstant(component.getVCallOffset()); case VTableComponent::CK_VBaseOffset: return addOffsetConstant(component.getVBaseOffset()); case VTableComponent::CK_OffsetToTop: return addOffsetConstant(component.getOffsetToTop()); case VTableComponent::CK_RTTI: return builder.add(llvm::ConstantExpr::getBitCast(rtti, CGM.Int8PtrTy)); case VTableComponent::CK_FunctionPointer: case VTableComponent::CK_CompleteDtorPointer: case VTableComponent::CK_DeletingDtorPointer: { GlobalDecl GD; // Get the right global decl. switch (component.getKind()) { default: llvm_unreachable("Unexpected vtable component kind"); case VTableComponent::CK_FunctionPointer: GD = component.getFunctionDecl(); break; case VTableComponent::CK_CompleteDtorPointer: GD = GlobalDecl(component.getDestructorDecl(), Dtor_Complete); break; case VTableComponent::CK_DeletingDtorPointer: GD = GlobalDecl(component.getDestructorDecl(), Dtor_Deleting); break; } if (CGM.getLangOpts().CUDA) { // Emit NULL for methods we can't codegen on this // side. Otherwise we'd end up with vtable with unresolved // references. const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); // OK on device side: functions w/ __device__ attribute // OK on host side: anything except __device__-only functions. bool CanEmitMethod = CGM.getLangOpts().CUDAIsDevice ? MD->hasAttr<CUDADeviceAttr>() : (MD->hasAttr<CUDAHostAttr>() || !MD->hasAttr<CUDADeviceAttr>()); if (!CanEmitMethod) return builder.addNullPointer(CGM.Int8PtrTy); // Method is acceptable, continue processing as usual. } auto getSpecialVirtualFn = [&](StringRef name) { llvm::FunctionType *fnTy = llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); llvm::Constant *fn = CGM.CreateRuntimeFunction(fnTy, name); if (auto f = dyn_cast<llvm::Function>(fn)) f->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); return llvm::ConstantExpr::getBitCast(fn, CGM.Int8PtrTy); }; llvm::Constant *fnPtr; // Pure virtual member functions. if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) { if (!PureVirtualFn) PureVirtualFn = getSpecialVirtualFn(CGM.getCXXABI().GetPureVirtualCallName()); fnPtr = PureVirtualFn; // Deleted virtual member functions. } else if (cast<CXXMethodDecl>(GD.getDecl())->isDeleted()) { if (!DeletedVirtualFn) DeletedVirtualFn = getSpecialVirtualFn(CGM.getCXXABI().GetDeletedVirtualCallName()); fnPtr = DeletedVirtualFn; // Thunks. } else if (nextVTableThunkIndex < layout.vtable_thunks().size() && layout.vtable_thunks()[nextVTableThunkIndex].first == idx) { auto &thunkInfo = layout.vtable_thunks()[nextVTableThunkIndex].second; maybeEmitThunkForVTable(GD, thunkInfo); nextVTableThunkIndex++; fnPtr = CGM.GetAddrOfThunk(GD, thunkInfo); // Otherwise we can use the method definition directly. } else { llvm::Type *fnTy = CGM.getTypes().GetFunctionTypeForVTable(GD); fnPtr = CGM.GetAddrOfFunction(GD, fnTy, /*ForVTable=*/true); } fnPtr = llvm::ConstantExpr::getBitCast(fnPtr, CGM.Int8PtrTy); builder.add(fnPtr); return; } case VTableComponent::CK_UnusedFunctionPointer: return builder.addNullPointer(CGM.Int8PtrTy); } llvm_unreachable("Unexpected vtable component kind"); }