------- Comment #4 from jakub at gcc dot gnu dot org 2008-06-02 20:15 ------- Here is a testcase that can be run, unfortunately during the simplification the incorrect behavior changed from the stack pointer increasing in each iteration by 16 bytes into decreasing in each iteration by 4 bytes. That's wrong too of course.
// { dg-options "-Os -fasynchronous-unwind-tables -fpic -fno-inline" } extern "C" { struct FILE; extern FILE *stderr; extern int fprintf (FILE *, const char *, ...); struct R { int r1; unsigned short r2[1]; }; int bar1 (unsigned short *, int, short) throw (); void bar2 (R *) throw (); void bar3 (R **, const unsigned short *, int) throw (); void bar4 (R **, const char *) throw (); } struct S { R *s; struct T { }; S (R *x, T *) { s = x; } ~S () { bar2 (s); } S &operator= (const S &x); S &operator+= (const S &x); S sfn1 (const S &x) const; friend S operator+ (const S &x1, const S &x2); static S sfn2 (int i) { unsigned short q[33]; R *p = 0; bar3 (&p, q, bar1 (q, i, 10)); return S (p, (T *) 0); } static S sfn3 (const char *x) { R *p = 0; bar4 (&p, x); return S (p, (T *) 0); } }; struct U { }; template <class C> unsigned char operator >>= (const U &, C &); struct V; struct W { V *w; unsigned char is () const; }; template <class T> struct X : public W { inline ~X (); X (); X (const W &); T *operator -> () const; }; struct E { E (); E (const S &, const X <V> &); E (E const &); ~E (); E &operator = (E const &); }; struct V { virtual void release () throw (); }; template <class T> X <T>::~X () { if (w) w->release (); } struct Y { virtual U yfn1 (const S &); }; struct Z; X <V> baz1 (const S &) throw (E); X <Z> baz2 (const X <Z> &) throw (E); template <typename T> X<T>::X () { w = __null; } template <typename T> X<T>::X (W const &) { w = __null; } U Y::yfn1 (const S &) { throw 12; } Y y; template <typename T> T *X<T>::operator -> () const { return &y; } X <V> baz1 (const S &) throw (E) { return X<V> (); } E::E () { } E::~E () { } X <Z> baz2 (const X <Z> &) throw (E) { throw E (); } int bar1 (unsigned short *, int, short) throw () { asm volatile ("" : : : "memory"); return 0; } void bar2 (R *) throw () { asm volatile ("" : : : "memory"); } void bar3 (R **, const unsigned short *, int) throw () { asm volatile ("" : : : "memory"); } void bar4 (R **, const char *) throw () { asm volatile ("" : : : "memory"); } unsigned char W::is () const { return 1; } S &S::operator += (const S &) { return *this; } template <class C> unsigned char operator >>= (const U &, C &) { throw 1; } template X<Y>::X (); template X<Z>::X (); template unsigned char operator >>= (const U &, X<Z> &); template X<Y>::X (W const &); template Y *X<Y>::operator-> () const; X <Z> foo () throw () { X <Z> a; X <Y> b; try { b = X <Y> (baz1 (S::sfn3 ("defg"))); } catch (E &) { } if (b.is ()) { for (int n = 0; n < 10; n++) { S c = S::sfn3 ("abcd"); c += S::sfn2 (n); X <Z> d; try { fprintf (stderr, "trying %d\n", n); if ((b->yfn1 (c) >>= d)) if (d.is ()) { fprintf (stderr, "failure1 on %d\n", n); a = baz2 (d); if (a.is ()) break; } fprintf (stderr, "failure2 on %d\n", n); } catch (...) { void *p; asm volatile ("movl %%esp, %0" : "=r" (p)); fprintf (stderr, "caught %d %p\n", n, p); } } } return a; } int main () { foo (); return 0; } -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36419