+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
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;
}
\f
/* When a stmt has been parsed, this function is called. */
+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
--- /dev/null
+/* { 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" } */
--- /dev/null
+/* { 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 ();
+}
--- /dev/null
+/* { 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 ();
+}
--- /dev/null
+/* { 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 ();
+}
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* 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 ();
+}
--- /dev/null
+/* { 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" } } */
--- /dev/null
+/* { 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 ();
+}
--- /dev/null
+/* { 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 ();
+}
--- /dev/null
+// 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 ();
+}