diff --git a/gen/classes.cpp b/gen/classes.cpp index 6fef7a6999..2fc6b321f6 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -390,7 +390,6 @@ LLValue *DtoVirtualFunctionPointer(DValue *inst, FuncDeclaration *fdecl, LLValue *funcval = vthis; // get the vtbl for objects - stripModifiers(inst->type->toBasetype())->ctype->isClass()->getVtblType(true); funcval = DtoGEPi(funcval, 0, 0); // load vtbl ptr funcval = DtoLoad(funcval); @@ -398,12 +397,12 @@ LLValue *DtoVirtualFunctionPointer(DValue *inst, FuncDeclaration *fdecl, std::string vtblname = name; vtblname.append("@vtbl"); funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, vtblname.c_str()); - // load funcptr + // load opaque pointer funcval = DtoAlignedLoad(funcval); IF_LOG Logger::cout() << "funcval: " << *funcval << '\n'; - // cast to final funcptr type + // cast to funcptr type funcval = DtoBitCast(funcval, getPtrToType(DtoFunctionType(fdecl))); // postpone naming until after casting to get the name in call instructions diff --git a/gen/toir.cpp b/gen/toir.cpp index 22402bf6dc..c6ecd29661 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -2664,13 +2664,12 @@ public: LLValue *val = DtoRVal(ex); // Get and load vtbl pointer. - stripModifiers(t)->ctype->isClass()->getVtblType(true); llvm::Value *vtbl = DtoLoad(DtoGEPi(val, 0, 0)); // TypeInfo ptr is first vtbl entry. llvm::Value *typinf = DtoGEPi(vtbl, 0, 0); - Type *resultType = Type::typeinfoclass->type; + Type *resultType; if (static_cast(t)->sym->isInterfaceDeclaration()) { // For interfaces, the first entry in the vtbl is actually a pointer // to an Interface instance, which has the type info as its first @@ -2678,6 +2677,9 @@ public: resultType = Type::typeinfointerface->type; typinf = DtoLoad( DtoBitCast(typinf, DtoType(resultType->pointerTo()->pointerTo()))); + } else { + resultType = Type::typeinfoclass->type; + typinf = DtoBitCast(typinf, DtoType(resultType->pointerTo())); } result = new DLValue(resultType, typinf); diff --git a/ir/irclass.cpp b/ir/irclass.cpp index aaab098d28..42fb19830b 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -49,7 +49,7 @@ LLGlobalVariable *IrAggr::getVtblSymbol() { // create the vtblZ symbol auto initname = getMangledVTableSymbolName(aggrdecl); - LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtblType(false); + LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtblType(); vtbl = getOrCreateGlobal(aggrdecl->loc, gIR->module, vtblTy, true, @@ -165,11 +165,13 @@ LLConstant *IrAggr::getVtblInit() { std::vector constants; constants.reserve(cd->vtbl.dim); + const auto voidPtrType = getVoidPtrType(); + // start with the classinfo llvm::Constant *c; if (!cd->isCPPclass()) { c = getClassInfoSymbol(); - c = DtoBitCast(c, DtoType(Type::typeinfoclass->type)); + c = DtoBitCast(c, voidPtrType); constants.push_back(c); } @@ -220,26 +222,12 @@ LLConstant *IrAggr::getVtblInit() { } } } - constants.push_back(c); + constants.push_back(DtoBitCast(c, voidPtrType)); } - // build the constant struct - LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtblType(true); -#ifndef NDEBUG - size_t nc = constants.size(); - - for (size_t i = 0; i < nc; ++i) { - if (constants[i]->getType() != vtblTy->getContainedType(i)) { - llvm::errs() << "type mismatch for entry # " << i - << " in vtbl initializer\n"; - - constants[i]->getType()->dump(); - vtblTy->getContainedType(i)->dump(); - } - } - -#endif - constVtbl = LLConstantStruct::get(isaStruct(vtblTy), constants); + // build the constant array + LLArrayType *vtblTy = LLArrayType::get(voidPtrType, constants.size()); + constVtbl = LLConstantArray::get(vtblTy, constants); return constVtbl; } @@ -277,6 +265,8 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance, std::vector constants; constants.reserve(vtbl_array.dim); + const auto voidPtrTy = getVoidPtrType(); + if (!b->sym->isCPPinterface()) { // skip interface info for CPP interfaces // index into the interfaces array llvm::Constant *idxs[2] = {DtoConstSize_t(0), @@ -289,7 +279,7 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance, #endif interfaceInfosZ, idxs, true); - constants.push_back(c); + constants.push_back(DtoBitCast(c, voidPtrTy)); } // Thunk prefix @@ -306,7 +296,7 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance, // FIXME // why is this null? // happens for mini/s.d - constants.push_back(getNullValue(getVoidPtrType())); + constants.push_back(getNullValue(voidPtrTy)); continue; } @@ -327,7 +317,7 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance, if (fd->interfaceVirtual) thunkOffset -= fd->interfaceVirtual->offset; if (thunkOffset == 0) { - constants.push_back(irFunc->func); + constants.push_back(DtoBitCast(irFunc->func, voidPtrTy)); continue; } @@ -434,12 +424,12 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance, gIR->funcGenStates.pop_back(); } - constants.push_back(thunk); + constants.push_back(DtoBitCast(thunk, voidPtrTy)); } // build the vtbl constant - llvm::Constant *vtbl_constant = - LLConstantStruct::getAnon(gIR->context(), constants, false); + llvm::Constant *vtbl_constant = LLConstantArray::get( + LLArrayType::get(voidPtrTy, constants.size()), constants); std::string mangledName("_D"); mangledName.append(mangle(cd)); @@ -526,7 +516,8 @@ LLConstant *IrAggr::getClassInfoInterfaces() { assert(itv != interfaceVtblMap.end() && "interface vtbl not found"); vtb = itv->second; vtb = DtoBitCast(vtb, voidptrptr_type); - vtb = DtoConstSlice(DtoConstSize_t(itc->getVtblSize()), vtb); + auto vtblSize = itc->getVtblType()->getNumContainedTypes(); + vtb = DtoConstSlice(DtoConstSize_t(vtblSize), vtb); } // offset diff --git a/ir/irtypeclass.cpp b/ir/irtypeclass.cpp index 0e37d61435..ef6b5a24ef 100644 --- a/ir/irtypeclass.cpp +++ b/ir/irtypeclass.cpp @@ -25,10 +25,7 @@ IrTypeClass::IrTypeClass(ClassDeclaration *cd) : IrTypeAggr(cd), cd(cd), tc(static_cast(cd->type)) { - std::string vtbl_name(cd->toPrettyChars()); - vtbl_name.append(".__vtbl"); - vtbl_type = LLStructType::create(gIR->context(), vtbl_name); - vtbl_size = cd->vtbl.dim; + vtbl_type = LLArrayType::get(getVoidPtrType(), cd->vtbl.dim); } void IrTypeClass::addClassData(AggrTypeBuilder &builder, @@ -52,15 +49,10 @@ void IrTypeClass::addClassData(AggrTypeBuilder &builder, IF_LOG Logger::println("Adding interface vtbl for %s", b->sym->toPrettyChars()); - FuncDeclarations arr; - b->fillVtbl(cd, &arr, currCd == cd); - // add to the interface map addInterfaceToMap(b->sym, builder.currentFieldIndex()); - Type* first = b->sym->isCPPinterface() ? nullptr : interfacePtrType; - const auto ivtblType = - llvm::StructType::get(gIR->context(), buildVtblType(first, &arr)); - builder.addType(llvm::PointerType::get(ivtblType, 0), Target::ptrsize); + auto vtblTy = LLArrayType::get(getVoidPtrType(), b->sym->vtbl.dim); + builder.addType(llvm::PointerType::get(vtblTy, 0), Target::ptrsize); ++num_interface_vtbls; } @@ -122,83 +114,10 @@ IrTypeClass *IrTypeClass::get(ClassDeclaration *cd) { return t; } -std::vector -IrTypeClass::buildVtblType(Type *first, FuncDeclarations *vtbl_array) { - IF_LOG Logger::println("Building vtbl type for class %s", - cd->toPrettyChars()); - LOG_SCOPE; - - std::vector types; - types.reserve(vtbl_array->dim); - - auto I = vtbl_array->begin(); - // first comes the classinfo for D interfaces - if (first) { - types.push_back(DtoType(first)); - ++I; - } - - // then come the functions - for (auto E = vtbl_array->end(); I != E; ++I) { - FuncDeclaration *fd = *I; - if (fd == nullptr) { - // FIXME: This stems from the ancient D1 days – can it still happen? - types.push_back(getVoidPtrType()); - continue; - } - - IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); - - // If inferring return type and semantic3 has not been run, do it now. - // This pops up in some other places in the frontend as well, however - // it is probably a bug that it still occurs that late. - if (!fd->type->nextOf() && fd->inferRetType) { - Logger::println("Running late functionSemantic to infer return type."); - TemplateInstance *spec = fd->isSpeculative(); - unsigned int olderrs = global.errors; - fd->functionSemantic(); - if (spec && global.errors != olderrs) { - spec->errors = global.errors - olderrs; - } - } - - if (!fd->type->nextOf()) { - // Return type of the function has not been inferred. This seems to - // happen with virtual functions and is probably a frontend bug. - IF_LOG Logger::println("Broken function type, semanticRun: %d", - fd->semanticRun); - types.push_back(getVoidPtrType()); - continue; - } - - types.push_back(getPtrToType(DtoFunctionType(fd))); - } - - return types; -} - llvm::Type *IrTypeClass::getLLType() { return llvm::PointerType::get(type, 0); } llvm::Type *IrTypeClass::getMemoryLLType() { return type; } -llvm::StructType *IrTypeClass::getVtblType(bool notOpaque) { - if (notOpaque && vtbl_type->isOpaque()) { - FuncDeclarations vtbl; - vtbl.reserve(cd->vtbl.dim); - if (!cd->isCPPclass()) - vtbl.push(nullptr); - for (size_t i = cd->vtblOffset(); i < cd->vtbl.dim; ++i) { - FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration(); - assert(fd); - vtbl.push(fd); - } - Type* first = cd->isCPPclass() ? nullptr : Type::typeinfoclass->type; - vtbl_type->setBody(buildVtblType(first, &vtbl)); - } - - return vtbl_type; -} - size_t IrTypeClass::getInterfaceIndex(ClassDeclaration *inter) { auto it = interfaceMap.find(inter); if (it == interfaceMap.end()) { diff --git a/ir/irtypeclass.h b/ir/irtypeclass.h index 829ad8379d..91633c35b0 100644 --- a/ir/irtypeclass.h +++ b/ir/irtypeclass.h @@ -37,16 +37,13 @@ public: llvm::Type *getMemoryLLType(); /// Returns the vtable type for this class. - llvm::StructType *getVtblType(bool notOpaque); + llvm::ArrayType *getVtblType() { return vtbl_type; } /// Get index to interface implementation. /// Returns the index of a specific interface implementation in this /// class or ~0 if not found. size_t getInterfaceIndex(ClassDeclaration *inter); - /// Returns the total number of pointers in the vtable. - unsigned getVtblSize() { return vtbl_size; } - /// Returns the number of interface implementations (vtables) in this /// class. unsigned getNumInterfaceVtbls() { return num_interface_vtbls; } @@ -61,10 +58,7 @@ protected: TypeClass *tc = nullptr; /// Vtable type. - llvm::StructType *vtbl_type = nullptr; - - /// Number of pointers in vtable. - unsigned vtbl_size = 0; + llvm::ArrayType *vtbl_type = nullptr; /// Number of interface implementations (vtables) in this class. unsigned num_interface_vtbls = 0; @@ -78,13 +72,6 @@ protected: ////////////////////////////////////////////////////////////////////////// - /// Builds a vtable type given the type of the first entry and an array - /// of all entries. - /// If first is nullptr for C++ interfaces, the vtbl_array will be added - /// as is without replacing the first entry. - std::vector buildVtblType(Type *first, - FuncDeclarations *vtbl_array); - /// Adds the data members for the given class to the type builder, including /// those inherited from base classes/interfaces. void addClassData(AggrTypeBuilder &builder, ClassDeclaration *currCd); diff --git a/tests/codegen/in_place_construct_asm.d b/tests/codegen/in_place_construct_asm.d index bd9c9706f1..dab0bb8365 100644 --- a/tests/codegen/in_place_construct_asm.d +++ b/tests/codegen/in_place_construct_asm.d @@ -1,6 +1,7 @@ // Tests in-place construction of structs returned by inline assembly (issue #1823). // Target Win64 for simplicity (e.g., 4x32-bit struct not returned in memory for non-Windows x64). +// REQUIRES: target_X86 // RUN: %ldc -mtriple=x86_64-pc-windows-msvc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll import ldc.llvmasm; diff --git a/tests/compilable/gh1741.d b/tests/compilable/gh1741.d new file mode 100644 index 0000000000..af01e182f8 --- /dev/null +++ b/tests/compilable/gh1741.d @@ -0,0 +1,13 @@ +// Explicitly target Linux x86_64. +// REQUIRES: target_X86 +// RUN: %ldc -mtriple=x86_64-pc-linux-gnu -c %s %S/inputs/gh1741b.d + +struct S +{ + C c; +} + +class C +{ + @property s() { return S(); } +} diff --git a/tests/compilable/inputs/gh1741b.d b/tests/compilable/inputs/gh1741b.d new file mode 100644 index 0000000000..4606cdd22a --- /dev/null +++ b/tests/compilable/inputs/gh1741b.d @@ -0,0 +1,3 @@ +import gh1741; + +S s;