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

Commit

Permalink
Only call class invariant if one provably exists in any base classes
Browse files Browse the repository at this point in the history
  • Loading branch information
ibuclaw committed Aug 12, 2015
1 parent 78c3891 commit d8a8854
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 13 deletions.
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
68 changes: 55 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,25 @@ 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))
{
// Add check for:
// if (arg.classinfo == typeid(tb1)
tree tinfo1 = build_ctype(Type::typeinfoclass->type);
tree tinfo2 = tb1->getTypeInfo(NULL)->toElem(NULL);
tree classinfo = indirect_ref(build_pointer_type(tinfo1), arg);
classinfo = indirect_ref(tinfo1, classinfo);

invc = build3(COND_EXPR, void_type_node,
build_boolop(EQ_EXPR, classinfo, tinfo2),
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 +1857,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

0 comments on commit d8a8854

Please sign in to comment.