Skip to content
This repository was archived by the owner on Jun 20, 2019. It is now read-only.

Only call class invariant if one provably exists in any base classes #132

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions gcc/d/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
2015-08-12 Iain Buclaw <[email protected]>

(needsInvariant): New function.
(AssertExp::toElem): Check if there are any invariants found in the
class object's vtable, and only call the invariant if the classinfo
doesn't match at runtime.

2015-08-10 Iain Buclaw <[email protected]>

* d-elem.cc(HaltExp::toElem): Use __builtin_trap to halt execution,
Expand Down
69 changes: 56 additions & 13 deletions gcc/d/d-elem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1746,6 +1746,41 @@ DotVarExp::toElem (IRState *)
return error_mark_node;
}

// Determine if type is an aggregate that contains or inherits an invariant.
static FuncDeclaration *
needsInvariant(Type *t)
{
if (global.params.useInvariants)
{
t = t->toBasetype();

// If type is a struct, return its invariant.
if (t->ty == Tpointer && t->nextOf()->ty == Tstruct)
{
StructDeclaration *sd = ((TypeStruct *) t->nextOf())->sym;
return sd->inv;
}

// If type is a class, search all base classes for an invariant.
if (t->ty == Tclass)
{
ClassDeclaration *cd = ((TypeClass *) t)->sym;

// Interfaces and C++ classes don't have invariants.
if (cd->isInterfaceDeclaration() || cd->isCPPclass())
return NULL;

for (; cd != NULL; cd = cd->baseClass)
{
if (cd->inv)
return cd->inv;
}
}
}

return NULL;
}

elem *
AssertExp::toElem (IRState *)
{
Expand Down Expand Up @@ -1784,7 +1819,6 @@ AssertExp::toElem (IRState *)
{
ClassDeclaration *cd = tb1->isClassHandle();
tree arg = e1->toElem(NULL);
tree invc = NULL_TREE;

if (cd->isCOMclass())
{
Expand All @@ -1795,13 +1829,26 @@ AssertExp::toElem (IRState *)
else if (cd->isInterfaceDeclaration())
arg = convert_expr (arg, tb1, build_object_type());

if (global.params.useInvariants && !cd->isCPPclass())
invc = build_libcall (LIBCALL_INVARIANT, 1, &arg);
tree invc = build_libcall (LIBCALL_INVARIANT, 1, &arg);
if (!needsInvariant(tb1))
{
// Wrap call to _d_invariant inside the following check:
// if (typeid(arg) != typeid(tb1))
// _d_invariant(arg);
tree tinfo = build_ctype(Type::typeinfoclass->type);
tree tidtype = tb1->getTypeInfo(NULL)->toElem(NULL);
tree tidarg = indirect_ref(build_pointer_type(tinfo), arg);
tidarg = indirect_ref(tinfo, tidarg);

invc = build3(COND_EXPR, void_type_node,
build_boolop(EQ_EXPR, tidarg, tidtype),
void_node, invc);
}

// This does a null pointer check before calling _d_invariant
return build3 (COND_EXPR, void_type_node,
build_boolop (NE_EXPR, arg, null_pointer_node),
invc ? invc : void_node, assert_call);
invc, assert_call);
}
else
{
Expand All @@ -1811,16 +1858,12 @@ AssertExp::toElem (IRState *)
tree invc = NULL_TREE;
tree e1_t = e1->toElem(NULL);

if (global.params.useInvariants
&& tb1->ty == Tpointer && tb1->nextOf()->ty == Tstruct)
FuncDeclaration *inv = needsInvariant(tb1);
if (inv != NULL)
{
FuncDeclaration *inv = ((TypeStruct *) tb1->nextOf())->sym->inv;
if (inv != NULL)
{
Expressions args;
e1_t = maybe_make_temp (e1_t);
invc = d_build_call (inv, e1_t, &args);
}
Expressions args;
e1_t = maybe_make_temp (e1_t);
invc = d_build_call (inv, e1_t, &args);
}
result = build3 (COND_EXPR, void_type_node,
convert_for_condition (e1_t, e1->type),
Expand Down