@@ -1746,6 +1746,41 @@ DotVarExp::toElem (IRState *)
17461746 return error_mark_node;
17471747}
17481748
1749+ // Determine if type is an aggregate that contains or inherits an invariant.
1750+ static FuncDeclaration *
1751+ needsInvariant (Type *t)
1752+ {
1753+ if (global.params .useInvariants )
1754+ {
1755+ t = t->toBasetype ();
1756+
1757+ // If type is a struct, return its invariant.
1758+ if (t->ty == Tpointer && t->nextOf ()->ty == Tstruct)
1759+ {
1760+ StructDeclaration *sd = ((TypeStruct *) t->nextOf ())->sym ;
1761+ return sd->inv ;
1762+ }
1763+
1764+ // If type is a class, search all base classes for an invariant.
1765+ if (t->ty == Tclass)
1766+ {
1767+ ClassDeclaration *cd = ((TypeClass *) t)->sym ;
1768+
1769+ // Interfaces and C++ classes don't have invariants.
1770+ if (cd->isInterfaceDeclaration () || cd->isCPPclass ())
1771+ return NULL ;
1772+
1773+ for (; cd != NULL ; cd = cd->baseClass )
1774+ {
1775+ if (cd->inv )
1776+ return cd->inv ;
1777+ }
1778+ }
1779+ }
1780+
1781+ return NULL ;
1782+ }
1783+
17491784elem *
17501785AssertExp::toElem (IRState *)
17511786{
@@ -1784,7 +1819,6 @@ AssertExp::toElem (IRState *)
17841819 {
17851820 ClassDeclaration *cd = tb1->isClassHandle ();
17861821 tree arg = e1 ->toElem (NULL );
1787- tree invc = NULL_TREE;
17881822
17891823 if (cd->isCOMclass ())
17901824 {
@@ -1795,13 +1829,26 @@ AssertExp::toElem (IRState *)
17951829 else if (cd->isInterfaceDeclaration ())
17961830 arg = convert_expr (arg, tb1, build_object_type ());
17971831
1798- if (global.params .useInvariants && !cd->isCPPclass ())
1799- invc = build_libcall (LIBCALL_INVARIANT, 1 , &arg);
1832+ tree invc = build_libcall (LIBCALL_INVARIANT, 1 , &arg);
1833+ if (!needsInvariant (tb1))
1834+ {
1835+ // Wrap call to _d_invariant inside the following check:
1836+ // if (typeid(arg) != typeid(tb1))
1837+ // _d_invariant(arg);
1838+ tree tinfo = build_ctype (Type::typeinfoclass->type );
1839+ tree tidtype = tb1->getTypeInfo (NULL )->toElem (NULL );
1840+ tree tidarg = indirect_ref (build_pointer_type (tinfo), arg);
1841+ tidarg = indirect_ref (tinfo, tidarg);
1842+
1843+ invc = build3 (COND_EXPR, void_type_node,
1844+ build_boolop (EQ_EXPR, tidarg, tidtype),
1845+ void_node, invc);
1846+ }
18001847
18011848 // This does a null pointer check before calling _d_invariant
18021849 return build3 (COND_EXPR, void_type_node,
18031850 build_boolop (NE_EXPR, arg, null_pointer_node),
1804- invc ? invc : void_node , assert_call);
1851+ invc, assert_call);
18051852 }
18061853 else
18071854 {
@@ -1811,16 +1858,12 @@ AssertExp::toElem (IRState *)
18111858 tree invc = NULL_TREE;
18121859 tree e1_t = e1 ->toElem (NULL );
18131860
1814- if (global. params . useInvariants
1815- && tb1-> ty == Tpointer && tb1-> nextOf ()-> ty == Tstruct )
1861+ FuncDeclaration *inv = needsInvariant (tb1);
1862+ if (inv != NULL )
18161863 {
1817- FuncDeclaration *inv = ((TypeStruct *) tb1->nextOf ())->sym ->inv ;
1818- if (inv != NULL )
1819- {
1820- Expressions args;
1821- e1_t = maybe_make_temp (e1_t );
1822- invc = d_build_call (inv, e1_t , &args);
1823- }
1864+ Expressions args;
1865+ e1_t = maybe_make_temp (e1_t );
1866+ invc = d_build_call (inv, e1_t , &args);
18241867 }
18251868 result = build3 (COND_EXPR, void_type_node,
18261869 convert_for_condition (e1_t , e1 ->type ),
0 commit comments