Skip to content

Commit

Permalink
Add some support for classes without TypeInfos (#2765)
Browse files Browse the repository at this point in the history
For -betterC and/or a minimal object.d without TypeInfo:

* Skip TypeInfo emission for classes and interfaces.
* Emit null as first vtable member.

Makes dmd-testsuite's {compilable,runnable}/minimal2.d work.
  • Loading branch information
kinke committed Jul 10, 2018
1 parent 6148b8a commit 494bc8b
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 27 deletions.
5 changes: 0 additions & 5 deletions gen/classes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,6 @@ void DtoResolveClass(ClassDeclaration *cd) {
getIrField(vd, true);
}

// emit the interfaceInfosZ symbol if necessary
if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) {
irAggr->getInterfaceArraySymbol(); // initializer is applied when it's built
}

// interface only emit typeinfo and classinfo
if (cd->isInterfaceDeclaration()) {
irAggr->initializeInterface();
Expand Down
25 changes: 14 additions & 11 deletions gen/declarations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,13 @@ class CodegenVisitor : public Visitor {
}

// Emit TypeInfo.
DtoTypeInfoOf(decl->type, /*base=*/false);

// Declare __InterfaceZ.
IrAggr *ir = getIrAggr(decl);
llvm::GlobalVariable *interfaceZ = ir->getClassInfoSymbol();
// Only define if not speculative.
if (!isSpeculativeType(decl->type)) {
defineGlobal(interfaceZ, ir->getClassInfoInit(), decl);
if (global.params.useTypeInfo && Type::dtypeinfo) {
IrAggr *ir = getIrAggr(decl);
llvm::GlobalVariable *interfaceZ = ir->getClassInfoSymbol();
// Only define if not speculative.
if (!isSpeculativeType(decl->type)) {
defineGlobal(interfaceZ, ir->getClassInfoInit(), decl);
}
}
}
}
Expand Down Expand Up @@ -196,9 +195,13 @@ class CodegenVisitor : public Visitor {

ir->defineInterfaceVtbls();

llvm::GlobalVariable *classZ = ir->getClassInfoSymbol();
if (!isSpeculativeType(decl->type)) {
defineGlobal(classZ, ir->getClassInfoInit(), decl);
// Emit TypeInfo.
if (global.params.useTypeInfo && Type::dtypeinfo) {
llvm::GlobalVariable *classZ = ir->getClassInfoSymbol();
// Only define if not speculative.
if (!isSpeculativeType(decl->type)) {
defineGlobal(classZ, ir->getClassInfoInit(), decl);
}
}
}
}
Expand Down
30 changes: 20 additions & 10 deletions ir/irclass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,13 @@ LLConstant *IrAggr::getVtblInit() {
// start with the classinfo
llvm::Constant *c;
if (!cd->isCPPclass()) {
c = getClassInfoSymbol();
c = DtoBitCast(c, voidPtrType);
if (global.params.useTypeInfo && Type::dtypeinfo) {
c = getClassInfoSymbol();
c = DtoBitCast(c, voidPtrType);
} else {
// use null if there are no TypeInfos
c = llvm::Constant::getNullValue(voidPtrType);
}
constants.push_back(c);
}

Expand Down Expand Up @@ -312,16 +317,21 @@ void IrAggr::defineInterfaceVtbl(BaseClass *b, bool new_instance,
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),
DtoConstSize_t(interfaces_index)};
if (global.params.useTypeInfo && Type::dtypeinfo) {
// index into the interfaces array
llvm::Constant *idxs[2] = {DtoConstSize_t(0),
DtoConstSize_t(interfaces_index)};

llvm::GlobalVariable *interfaceInfosZ = getInterfaceArraySymbol();
llvm::Constant *c = llvm::ConstantExpr::getGetElementPtr(
isaPointer(interfaceInfosZ)->getElementType(),
interfaceInfosZ, idxs, true);
llvm::GlobalVariable *interfaceInfosZ = getInterfaceArraySymbol();
llvm::Constant *c = llvm::ConstantExpr::getGetElementPtr(
isaPointer(interfaceInfosZ)->getElementType(), interfaceInfosZ, idxs,
true);

constants.push_back(DtoBitCast(c, voidPtrTy));
constants.push_back(DtoBitCast(c, voidPtrTy));
} else {
// use null if there are no TypeInfos
constants.push_back(llvm::Constant::getNullValue(voidPtrTy));
}
}

// add virtual function pointers
Expand Down
29 changes: 29 additions & 0 deletions tests/baremetal/classes.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Use classes with virtual functions.

// -betterC for C assert.
// RUN: %ldc -betterC %baremetal_args -run %s

class A
{
int x;
bool isB() { return false; }
}

class B : A
{
override bool isB() { return true; }
}

__gshared A a = new A();
__gshared B b = new B();

extern(C) int main()
{
A obj = a;
assert(!obj.isB());

obj = b;
assert(obj.isB());

return 0;
}
2 changes: 1 addition & 1 deletion tests/d2/dmd-testsuite

0 comments on commit 494bc8b

Please sign in to comment.