diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/cp/decl.c | 63 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/cleanup-1.C | 36 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/cleanup-10.C | 117 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/cleanup-11.C | 117 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/cleanup-2.C | 22 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/cleanup-3.C | 45 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/cleanup-4.C | 39 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/cleanup-5.C | 54 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/cleanup-6.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/cleanup-8.C | 100 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/cleanup-9.C | 104 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/cleanup-dtor.C | 28 |
14 files changed, 747 insertions, 11 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6486ec0..e6b4f45 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2007-05-21 Mark Mitchell <mark@codesourcery.com> + + * decl.c (cxx_maybe_build_cleanup): Handle + __attribute__((cleanup)). + 2007-05-19 Manuel Lopez-Ibanez <manu@gcc.gnu.org> * cvt.c (cp_convert_and_check): Don't check warnings if the diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 9b62658..c76568a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -11636,39 +11636,80 @@ complete_vars (tree type) complete_type_check_abstract (type); } -/* If DECL is of a type which needs a cleanup, build that cleanup - here. */ +/* If DECL is of a type which needs a cleanup, build and return an + expression to perform that cleanup here. Return NULL_TREE if no + cleanup need be done. */ tree cxx_maybe_build_cleanup (tree decl) { - tree type = TREE_TYPE (decl); + tree type; + tree attr; + tree cleanup; + + /* Assume no cleanup is required. */ + cleanup = NULL_TREE; - if (type != error_mark_node && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) + if (error_operand_p (decl)) + return cleanup; + + /* Handle "__attribute__((cleanup))". We run the cleanup function + before the destructor since the destructor is what actually + terminates the lifetime of the object. */ + attr = lookup_attribute ("cleanup", DECL_ATTRIBUTES (decl)); + if (attr) + { + tree id; + tree fn; + tree arg; + + /* Get the name specified by the user for the cleanup function. */ + id = TREE_VALUE (TREE_VALUE (attr)); + /* Look up the name to find the cleanup function to call. It is + important to use lookup_name here because that is what is + used in c-common.c:handle_cleanup_attribute when performing + initial checks on the attribute. Note that those checks + include ensuring that the function found is not an overloaded + function, or an object with an overloaded call operator, + etc.; we can rely on the fact that the functionfound is an + ordinary FUNCTION_DECL. */ + fn = lookup_name (id); + arg = build_address (decl); + mark_used (decl); + cleanup = build_function_call (fn, build_tree_list (NULL_TREE, + arg)); + } + /* Handle ordinary C++ destructors. */ + type = TREE_TYPE (decl); + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) { int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR; - tree rval; bool has_vbases = (TREE_CODE (type) == RECORD_TYPE && CLASSTYPE_VBASECLASSES (type)); + tree addr; + tree call; if (TREE_CODE (type) == ARRAY_TYPE) - rval = decl; + addr = decl; else { cxx_mark_addressable (decl); - rval = build_unary_op (ADDR_EXPR, decl, 0); + addr = build_unary_op (ADDR_EXPR, decl, 0); } /* Optimize for space over speed here. */ if (!has_vbases || flag_expensive_optimizations) flags |= LOOKUP_NONVIRTUAL; - rval = build_delete (TREE_TYPE (rval), rval, + call = build_delete (TREE_TYPE (addr), addr, sfk_complete_destructor, flags, 0); - - return rval; + if (cleanup) + cleanup = build_compound_expr (cleanup, call); + else + cleanup = call; } - return NULL_TREE; + + return cleanup; } /* When a stmt has been parsed, this function is called. */ 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 (); +} |