aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2007-05-21 23:47:29 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2007-05-21 23:47:29 +0000
commit5c1131547ba8afe1ca639d012b96c63d3e94767e (patch)
tree53be7e6a464964a2a2ab76a9407d12f76ef6def8 /gcc/testsuite
parent0b4cafec04e60b7a06ee01ddc752c516ddb250c7 (diff)
downloadgcc-5c1131547ba8afe1ca639d012b96c63d3e94767e.zip
gcc-5c1131547ba8afe1ca639d012b96c63d3e94767e.tar.gz
gcc-5c1131547ba8afe1ca639d012b96c63d3e94767e.tar.bz2
decl.c (cxx_maybe_build_cleanup): Handle __attribute__((cleanup)).
* decl.c (cxx_maybe_build_cleanup): Handle __attribute__((cleanup)). * g++.dg/ext/cleanup-1.C: New test. * g++.dg/ext/cleanup-2.C: Likewise. * g++.dg/ext/cleanup-3.C: Likewise. * g++.dg/ext/cleanup-4.C: Likewise. * g++.dg/ext/cleanup-5.C: Likewise. * g++.dg/ext/cleanup-6.C: Likewise. * g++.dg/ext/cleanup-8.C: Likewise. * g++.dg/ext/cleanup-9.C: Likewise. * g++.dg/ext/cleanup-10.C: Likewise. * g++.dg/ext/cleanup-11.C: Likewise. * g++.dg/ext/cleanup-dtor.C: Likewise. From-SVN: r124930
Diffstat (limited to 'gcc/testsuite')
-rw-r--r--gcc/testsuite/ChangeLog14
-rw-r--r--gcc/testsuite/g++.dg/ext/cleanup-1.C36
-rw-r--r--gcc/testsuite/g++.dg/ext/cleanup-10.C117
-rw-r--r--gcc/testsuite/g++.dg/ext/cleanup-11.C117
-rw-r--r--gcc/testsuite/g++.dg/ext/cleanup-2.C22
-rw-r--r--gcc/testsuite/g++.dg/ext/cleanup-3.C45
-rw-r--r--gcc/testsuite/g++.dg/ext/cleanup-4.C39
-rw-r--r--gcc/testsuite/g++.dg/ext/cleanup-5.C54
-rw-r--r--gcc/testsuite/g++.dg/ext/cleanup-6.C14
-rw-r--r--gcc/testsuite/g++.dg/ext/cleanup-8.C100
-rw-r--r--gcc/testsuite/g++.dg/ext/cleanup-9.C104
-rw-r--r--gcc/testsuite/g++.dg/ext/cleanup-dtor.C28
12 files changed, 690 insertions, 0 deletions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e46cf78..c37b343 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,17 @@
+2007-05-21 Mark Mitchell <mark@codesourcery.com>
+
+ * g++.dg/ext/cleanup-1.C: New test.
+ * g++.dg/ext/cleanup-2.C: Likewise.
+ * g++.dg/ext/cleanup-3.C: Likewise.
+ * g++.dg/ext/cleanup-4.C: Likewise.
+ * g++.dg/ext/cleanup-5.C: Likewise.
+ * g++.dg/ext/cleanup-6.C: Likewise.
+ * g++.dg/ext/cleanup-8.C: Likewise.
+ * g++.dg/ext/cleanup-9.C: Likewise.
+ * g++.dg/ext/cleanup-10.C: Likewise.
+ * g++.dg/ext/cleanup-11.C: Likewise.
+ * g++.dg/ext/cleanup-dtor.C: Likewise.
+
2007-05-21 Andrew Pinski <andrew_pinski@playstation.sony.com>
PR middle-end/31995
diff --git a/gcc/testsuite/g++.dg/ext/cleanup-1.C b/gcc/testsuite/g++.dg/ext/cleanup-1.C
new file mode 100644
index 0000000..383c64e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/cleanup-1.C
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+/* Validate expected warnings and errors. */
+
+#define U __attribute__((unused))
+#define C(x) __attribute__((cleanup(x)))
+
+static int f1(void *x U) { return 0; }
+static void f2() { } /* { dg-error "too many arguments" } */
+static void f3(void) { } /* { dg-error "too many arguments" } */
+static void f4(void *x U) { }
+static void f5(int *x U) { }
+static void f6(double *x U) { }
+static void f7(const int *x U) { }
+static void f8(const int *x U, int y U) { } /* { dg-error "too few arguments" } */
+static void f9(int x U) { }
+
+void test(void)
+{
+ int o1 C(f1);
+ int o2 C(f2); /* { dg-error "at this point" } */
+ int o3 C(f3); /* { dg-error "at this point" } */
+ int o4 C(f4);
+ int o5 C(f5);
+ int o6 C(f6); /* { dg-error "cannot convert" } */
+ int o7 C(f7);
+ int o8 C(f8); /* { dg-error "at this point" } */
+ int o9 C(f9); /* { dg-error "conversion" } */
+ int o10 U C(undef); /* { dg-error "not a function" } */
+ int o11 U C(o1); /* { dg-error "not a function" } */
+ int o12 U C("f1"); /* { dg-error "not an identifier" } */
+ static int o13 U C(f1); /* { dg-warning "attribute ignored" } */
+}
+
+int o14 C(f1); /* { dg-warning "attribute ignored" } */
+void t15(int o U C(f1)) {} /* { dg-warning "attribute ignored" } */
diff --git a/gcc/testsuite/g++.dg/ext/cleanup-10.C b/gcc/testsuite/g++.dg/ext/cleanup-10.C
new file mode 100644
index 0000000..c0c6971
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/cleanup-10.C
@@ -0,0 +1,117 @@
+/* { dg-do run { target hppa*-*-hpux* *-*-linux* powerpc*-*-darwin* } } */
+/* { dg-options "-fexceptions -fnon-call-exceptions -O2" } */
+/* Verify that cleanups work with exception handling through signal frames
+ on alternate stack. */
+
+#include <unwind.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+
+static _Unwind_Reason_Code
+force_unwind_stop (int version, _Unwind_Action actions,
+ _Unwind_Exception_Class exc_class,
+ struct _Unwind_Exception *exc_obj,
+ struct _Unwind_Context *context,
+ void *stop_parameter)
+{
+ if (actions & _UA_END_OF_STACK)
+ abort ();
+ return _URC_NO_REASON;
+}
+
+static void force_unwind ()
+{
+ struct _Unwind_Exception *exc
+ = (struct _Unwind_Exception *) malloc (sizeof (*exc));
+ memset (&exc->exception_class, 0, sizeof (exc->exception_class));
+ exc->exception_cleanup = 0;
+
+#ifndef __USING_SJLJ_EXCEPTIONS__
+ _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
+#else
+ _Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
+#endif
+
+ abort ();
+}
+
+int count;
+char *null;
+
+static void counter (void *p __attribute__((unused)))
+{
+ ++count;
+}
+
+static void handler (void *p __attribute__((unused)))
+{
+ if (count != 2)
+ abort ();
+ exit (0);
+}
+
+static int __attribute__((noinline)) fn5 ()
+{
+ char dummy __attribute__((cleanup (counter)));
+ force_unwind ();
+ return 0;
+}
+
+static void fn4 (int sig, siginfo_t *info, void *ctx)
+{
+ char dummy __attribute__((cleanup (counter)));
+ fn5 ();
+ null = NULL;
+}
+
+static void fn3 ()
+{
+ abort ();
+}
+
+static int __attribute__((noinline)) fn2 ()
+{
+ *null = 0;
+ fn3 ();
+ return 0;
+}
+
+static int __attribute__((noinline)) fn1 ()
+{
+ stack_t ss;
+ struct sigaction s;
+
+ ss.ss_size = 4 * sysconf (_SC_PAGESIZE);
+ if (ss.ss_size < SIGSTKSZ)
+ ss.ss_size = SIGSTKSZ;
+ ss.ss_sp = malloc (ss.ss_size);
+ if (ss.ss_sp == NULL)
+ exit (1);
+ ss.ss_flags = 0;
+ if (sigaltstack (&ss, NULL) < 0)
+ exit (1);
+
+ sigemptyset (&s.sa_mask);
+ s.sa_sigaction = fn4;
+ s.sa_flags = SA_RESETHAND | SA_ONSTACK;
+ sigaction (SIGSEGV, &s, NULL);
+ sigaction (SIGBUS, &s, NULL);
+ fn2 ();
+ return 0;
+}
+
+static int __attribute__((noinline)) fn0 ()
+{
+ char dummy __attribute__((cleanup (handler)));
+ fn1 ();
+ null = 0;
+ return 0;
+}
+
+int main()
+{
+ fn0 ();
+ abort ();
+}
diff --git a/gcc/testsuite/g++.dg/ext/cleanup-11.C b/gcc/testsuite/g++.dg/ext/cleanup-11.C
new file mode 100644
index 0000000..06c6569
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/cleanup-11.C
@@ -0,0 +1,117 @@
+/* { dg-do run { target hppa*-*-hpux* *-*-linux* powerpc*-*-darwin* } } */
+/* { dg-options "-fexceptions -fnon-call-exceptions -O2" } */
+/* Verify that cleanups work with exception handling through realtime signal
+ frames on alternate stack. */
+
+#include <unwind.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+
+static _Unwind_Reason_Code
+force_unwind_stop (int version, _Unwind_Action actions,
+ _Unwind_Exception_Class exc_class,
+ struct _Unwind_Exception *exc_obj,
+ struct _Unwind_Context *context,
+ void *stop_parameter)
+{
+ if (actions & _UA_END_OF_STACK)
+ abort ();
+ return _URC_NO_REASON;
+}
+
+static void force_unwind ()
+{
+ struct _Unwind_Exception *exc
+ = (struct _Unwind_Exception*) malloc (sizeof (*exc));
+ memset (&exc->exception_class, 0, sizeof (exc->exception_class));
+ exc->exception_cleanup = 0;
+
+#ifndef __USING_SJLJ_EXCEPTIONS__
+ _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
+#else
+ _Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
+#endif
+
+ abort ();
+}
+
+int count;
+char *null;
+
+static void counter (void *p __attribute__((unused)))
+{
+ ++count;
+}
+
+static void handler (void *p __attribute__((unused)))
+{
+ if (count != 2)
+ abort ();
+ exit (0);
+}
+
+static int __attribute__((noinline)) fn5 ()
+{
+ char dummy __attribute__((cleanup (counter)));
+ force_unwind ();
+ return 0;
+}
+
+static void fn4 (int sig, siginfo_t *info, void *ctx)
+{
+ char dummy __attribute__((cleanup (counter)));
+ fn5 ();
+ null = NULL;
+}
+
+static void fn3 ()
+{
+ abort ();
+}
+
+static int __attribute__((noinline)) fn2 ()
+{
+ *null = 0;
+ fn3 ();
+ return 0;
+}
+
+static int __attribute__((noinline)) fn1 ()
+{
+ stack_t ss;
+ struct sigaction s;
+
+ ss.ss_size = 4 * sysconf (_SC_PAGESIZE);
+ if (ss.ss_size < SIGSTKSZ)
+ ss.ss_size = SIGSTKSZ;
+ ss.ss_sp = malloc (ss.ss_size);
+ if (ss.ss_sp == NULL)
+ exit (1);
+ ss.ss_flags = 0;
+ if (sigaltstack (&ss, NULL) < 0)
+ exit (1);
+
+ sigemptyset (&s.sa_mask);
+ s.sa_sigaction = fn4;
+ s.sa_flags = SA_RESETHAND | SA_ONSTACK | SA_SIGINFO;
+ sigaction (SIGSEGV, &s, NULL);
+ sigaction (SIGBUS, &s, NULL);
+ fn2 ();
+ return 0;
+}
+
+static int __attribute__((noinline)) fn0 ()
+{
+ char dummy __attribute__((cleanup (handler)));
+ fn1 ();
+ null = 0;
+ return 0;
+}
+
+int main()
+{
+ fn0 ();
+ abort ();
+}
diff --git a/gcc/testsuite/g++.dg/ext/cleanup-2.C b/gcc/testsuite/g++.dg/ext/cleanup-2.C
new file mode 100644
index 0000000..d9033b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/cleanup-2.C
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+/* Verify that cleanup works in the most basic of ways. */
+
+extern "C" void exit(int);
+extern "C" void abort(void);
+
+static void handler(void *p __attribute__((unused)))
+{
+ exit (0);
+}
+
+static void doit(void)
+{
+ int x __attribute__((cleanup (handler)));
+}
+
+int main()
+{
+ doit ();
+ abort ();
+}
diff --git a/gcc/testsuite/g++.dg/ext/cleanup-3.C b/gcc/testsuite/g++.dg/ext/cleanup-3.C
new file mode 100644
index 0000000..5367c49
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/cleanup-3.C
@@ -0,0 +1,45 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+/* Verify that the cleanup handler receives the proper contents
+ of the variable. */
+
+extern "C" void exit(int);
+extern "C" void abort(void);
+
+static int expected;
+
+static void
+handler(int *p)
+{
+ if (*p != expected)
+ abort ();
+}
+
+static void __attribute__((noinline))
+bar(void)
+{
+}
+
+static void doit(int x, int y)
+{
+ int r __attribute__((cleanup (handler)));
+ if (x < y)
+ {
+ r = 0;
+ return;
+ }
+
+ bar();
+ r = x + y;
+}
+
+int main()
+{
+ expected = 0;
+ doit (1, 2);
+
+ expected = 3;
+ doit (2, 1);
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/ext/cleanup-4.C b/gcc/testsuite/g++.dg/ext/cleanup-4.C
new file mode 100644
index 0000000..ae9a6e4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/cleanup-4.C
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+/* Verify cleanup execution on non-trivial exit from a block. */
+
+extern "C" void exit(int);
+extern "C" void abort(void);
+
+static int counter;
+
+static void
+handler(int *p)
+{
+ counter += *p;
+}
+
+static void __attribute__((noinline))
+bar(void)
+{
+}
+
+static void doit(int n, int n2)
+{
+ int i;
+ for (i = 0; i < n; ++i)
+ {
+ int dummy __attribute__((cleanup (handler))) = i;
+ if (i == n2)
+ break;
+ bar();
+ }
+}
+
+int main()
+{
+ doit (10, 6);
+ if (counter != 0 + 1 + 2 + 3 + 4 + 5 + 6)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/ext/cleanup-5.C b/gcc/testsuite/g++.dg/ext/cleanup-5.C
new file mode 100644
index 0000000..db4c2bb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/cleanup-5.C
@@ -0,0 +1,54 @@
+/* HP-UX libunwind.so doesn't provide _UA_END_OF_STACK */
+/* { dg-do run } */
+/* { dg-options "-fexceptions" } */
+/* { dg-skip-if "" { "ia64-*-hpux11.*" } { "*" } { "" } } */
+/* Verify that cleanups work with exception handling. */
+
+#include <unwind.h>
+#include <stdlib.h>
+#include <string.h>
+
+static _Unwind_Reason_Code
+force_unwind_stop (int version, _Unwind_Action actions,
+ _Unwind_Exception_Class exc_class,
+ struct _Unwind_Exception *exc_obj,
+ struct _Unwind_Context *context,
+ void *stop_parameter)
+{
+ if (actions & _UA_END_OF_STACK)
+ abort ();
+ return _URC_NO_REASON;
+}
+
+static void force_unwind ()
+{
+ struct _Unwind_Exception *exc
+ = (struct _Unwind_Exception *) malloc (sizeof (*exc));
+ memset (&exc->exception_class, 0, sizeof (exc->exception_class));
+ exc->exception_cleanup = 0;
+
+#ifndef __USING_SJLJ_EXCEPTIONS__
+ _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
+#else
+ _Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
+#endif
+
+ abort ();
+}
+
+static void handler (void *p __attribute__((unused)))
+{
+ exit (0);
+}
+
+static void doit ()
+{
+ char dummy __attribute__((cleanup (handler)));
+ force_unwind ();
+}
+
+int main()
+{
+ doit ();
+ abort ();
+}
diff --git a/gcc/testsuite/g++.dg/ext/cleanup-6.C b/gcc/testsuite/g++.dg/ext/cleanup-6.C
new file mode 100644
index 0000000..4e3d538
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/cleanup-6.C
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+/* Verify that a cleanup marked "inline" gets inlined. */
+
+static inline void xyzzy(void *p __attribute__((unused)))
+{
+}
+
+void doit(void)
+{
+ int x __attribute__((cleanup (xyzzy)));
+}
+
+/* { dg-final { scan-assembler-not "xyzzy" } } */
diff --git a/gcc/testsuite/g++.dg/ext/cleanup-8.C b/gcc/testsuite/g++.dg/ext/cleanup-8.C
new file mode 100644
index 0000000..ece12e8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/cleanup-8.C
@@ -0,0 +1,100 @@
+/* { dg-do run { target hppa*-*-hpux* *-*-linux* powerpc*-*-darwin* } } */
+/* { dg-options "-fexceptions -fnon-call-exceptions -O2" } */
+/* Verify that cleanups work with exception handling through signal
+ frames. */
+
+#include <unwind.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+
+static _Unwind_Reason_Code
+force_unwind_stop (int version, _Unwind_Action actions,
+ _Unwind_Exception_Class exc_class,
+ struct _Unwind_Exception *exc_obj,
+ struct _Unwind_Context *context,
+ void *stop_parameter)
+{
+ if (actions & _UA_END_OF_STACK)
+ abort ();
+ return _URC_NO_REASON;
+}
+
+static void force_unwind ()
+{
+ struct _Unwind_Exception *exc
+ = (struct _Unwind_Exception *) malloc (sizeof (*exc));
+ memset (&exc->exception_class, 0, sizeof (exc->exception_class));
+ exc->exception_cleanup = 0;
+
+#ifndef __USING_SJLJ_EXCEPTIONS__
+ _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
+#else
+ _Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
+#endif
+
+ abort ();
+}
+
+int count;
+char *null;
+
+static void counter (void *p __attribute__((unused)))
+{
+ ++count;
+}
+
+static void handler (void *p __attribute__((unused)))
+{
+ if (count != 2)
+ abort ();
+ exit (0);
+}
+
+static int __attribute__((noinline)) fn5 ()
+{
+ char dummy __attribute__((cleanup (counter)));
+ force_unwind ();
+ return 0;
+}
+
+static void fn4 (int sig)
+{
+ char dummy __attribute__((cleanup (counter)));
+ fn5 ();
+ null = NULL;
+}
+
+static void fn3 ()
+{
+ abort ();
+}
+
+static int __attribute__((noinline)) fn2 ()
+{
+ *null = 0;
+ fn3 ();
+ return 0;
+}
+
+static int __attribute__((noinline)) fn1 ()
+{
+ signal (SIGSEGV, fn4);
+ signal (SIGBUS, fn4);
+ fn2 ();
+ return 0;
+}
+
+static int __attribute__((noinline)) fn0 ()
+{
+ char dummy __attribute__((cleanup (handler)));
+ fn1 ();
+ null = 0;
+ return 0;
+}
+
+int main()
+{
+ fn0 ();
+ abort ();
+}
diff --git a/gcc/testsuite/g++.dg/ext/cleanup-9.C b/gcc/testsuite/g++.dg/ext/cleanup-9.C
new file mode 100644
index 0000000..59a9735
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/cleanup-9.C
@@ -0,0 +1,104 @@
+/* { dg-do run { target hppa*-*-hpux* *-*-linux* powerpc*-*-darwin* } } */
+/* { dg-options "-fexceptions -fnon-call-exceptions -O2" } */
+/* Verify that cleanups work with exception handling through realtime
+ signal frames. */
+
+#include <unwind.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+
+static _Unwind_Reason_Code
+force_unwind_stop (int version, _Unwind_Action actions,
+ _Unwind_Exception_Class exc_class,
+ struct _Unwind_Exception *exc_obj,
+ struct _Unwind_Context *context,
+ void *stop_parameter)
+{
+ if (actions & _UA_END_OF_STACK)
+ abort ();
+ return _URC_NO_REASON;
+}
+
+static void force_unwind ()
+{
+ struct _Unwind_Exception *exc
+ = (struct _Unwind_Exception *) malloc (sizeof (*exc));
+ memset (&exc->exception_class, 0, sizeof (exc->exception_class));
+ exc->exception_cleanup = 0;
+
+#ifndef __USING_SJLJ_EXCEPTIONS__
+ _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
+#else
+ _Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
+#endif
+
+ abort ();
+}
+
+int count;
+char *null;
+
+static void counter (void *p __attribute__((unused)))
+{
+ ++count;
+}
+
+static void handler (void *p __attribute__((unused)))
+{
+ if (count != 2)
+ abort ();
+ exit (0);
+}
+
+static int __attribute__((noinline)) fn5 ()
+{
+ char dummy __attribute__((cleanup (counter)));
+ force_unwind ();
+ return 0;
+}
+
+static void fn4 (int sig, siginfo_t *info, void *ctx)
+{
+ char dummy __attribute__((cleanup (counter)));
+ fn5 ();
+ null = NULL;
+}
+
+static void fn3 ()
+{
+ abort ();
+}
+
+static int __attribute__((noinline)) fn2 ()
+{
+ *null = 0;
+ fn3 ();
+ return 0;
+}
+
+static int __attribute__((noinline)) fn1 ()
+{
+ struct sigaction s;
+ sigemptyset (&s.sa_mask);
+ s.sa_sigaction = fn4;
+ s.sa_flags = SA_RESETHAND | SA_SIGINFO;
+ sigaction (SIGSEGV, &s, NULL);
+ sigaction (SIGBUS, &s, NULL);
+ fn2 ();
+ return 0;
+}
+
+static int __attribute__((noinline)) fn0 ()
+{
+ char dummy __attribute__((cleanup (handler)));
+ fn1 ();
+ null = 0;
+ return 0;
+}
+
+int main()
+{
+ fn0 ();
+ abort ();
+}
diff --git a/gcc/testsuite/g++.dg/ext/cleanup-dtor.C b/gcc/testsuite/g++.dg/ext/cleanup-dtor.C
new file mode 100644
index 0000000..58da646
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/cleanup-dtor.C
@@ -0,0 +1,28 @@
+// Check that destructors are run after cleanup functions.
+// { dg-do run }
+
+extern "C" void abort ();
+
+int i;
+
+struct S {
+ ~S() {
+ if (i != 1)
+ abort ();
+ i = 2;
+ }
+};
+
+void f(void *) {
+ if (i != 0)
+ abort ();
+ i = 1;
+}
+
+int main () {
+ {
+ S s __attribute__((cleanup (f)));
+ }
+ if (i != 2)
+ abort ();
+}