@@ -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,25 @@ 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+ // Add check for:
1836+ // if (arg.classinfo == typeid(tb1)
1837+ tree tinfo1 = build_ctype (Type::typeinfoclass->type );
1838+ tree tinfo2 = tb1->getTypeInfo (NULL )->toElem (NULL );
1839+ tree classinfo = indirect_ref (build_pointer_type (tinfo1), arg);
1840+ classinfo = indirect_ref (tinfo1, classinfo);
1841+
1842+ invc = build3 (COND_EXPR, void_type_node,
1843+ build_boolop (EQ_EXPR, classinfo, tinfo2),
1844+ void_node, invc);
1845+ }
18001846
18011847 // This does a null pointer check before calling _d_invariant
18021848 return build3 (COND_EXPR, void_type_node,
18031849 build_boolop (NE_EXPR, arg, null_pointer_node),
1804- invc ? invc : void_node , assert_call);
1850+ invc, assert_call);
18051851 }
18061852 else
18071853 {
@@ -1811,16 +1857,12 @@ AssertExp::toElem (IRState *)
18111857 tree invc = NULL_TREE;
18121858 tree e1_t = e1 ->toElem (NULL );
18131859
1814- if (global. params . useInvariants
1815- && tb1-> ty == Tpointer && tb1-> nextOf ()-> ty == Tstruct )
1860+ FuncDeclaration *inv = needsInvariant (tb1);
1861+ if (inv != NULL )
18161862 {
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- }
1863+ Expressions args;
1864+ e1_t = maybe_make_temp (e1_t );
1865+ invc = d_build_call (inv, e1_t , &args);
18241866 }
18251867 result = build3 (COND_EXPR, void_type_node,
18261868 convert_for_condition (e1_t , e1 ->type ),
0 commit comments