This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH: Make __attribute__((cleanup)) work in C++


It was pointed out to me that __attribute__((cleanup)) didn't work in
C++.  There was no support for it at all in the C++ front end; this
patch adds it.  I brought over the testcases from the C testsuite,
with the exception of cleanup-7.c, which uses nested functions, which
aren't part of GNU C++.  

I also added a new cleanup-dtor.C to test the interaction of cleanup
functions and conventional C++ destructors.  This test checks that
cleanup function run before destructors, which I think is the only
choice: after the destructor runs, the object is gone.  Of course,
this is a pathological corner case; the primary use of
__attribute__((cleanup)) in C++ is for compatibility with C code.

Tested on x86_64-linux-gnu, applied on the mainline.

--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

2007-05-21  Mark Mitchell  <mark@codesourcery.com>

	* decl.c (cxx_maybe_build_cleanup): Handle
	__attribute__((cleanup)).

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.

Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 124907)
+++ gcc/cp/decl.c	(working copy)
@@ -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);
-
-  if (type != error_mark_node && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+  tree type;
+  tree attr;
+  tree cleanup;
+
+  /* Assume no cleanup is required.  */
+  cleanup = NULL_TREE;
+
+  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.  */
Index: gcc/testsuite/g++.dg/ext/cleanup-4.C
===================================================================
--- gcc/testsuite/g++.dg/ext/cleanup-4.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/cleanup-4.C	(revision 0)
@@ -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;
+}
Index: gcc/testsuite/g++.dg/ext/cleanup-8.C
===================================================================
--- gcc/testsuite/g++.dg/ext/cleanup-8.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/cleanup-8.C	(revision 0)
@@ -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 ();
+}
Index: gcc/testsuite/g++.dg/ext/cleanup-dtor.C
===================================================================
--- gcc/testsuite/g++.dg/ext/cleanup-dtor.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/cleanup-dtor.C	(revision 0)
@@ -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 ();
+}
Index: gcc/testsuite/g++.dg/ext/cleanup-10.C
===================================================================
--- gcc/testsuite/g++.dg/ext/cleanup-10.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/cleanup-10.C	(revision 0)
@@ -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 ();
+}
Index: gcc/testsuite/g++.dg/ext/cleanup-1.C
===================================================================
--- gcc/testsuite/g++.dg/ext/cleanup-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/cleanup-1.C	(revision 0)
@@ -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" } */
Index: gcc/testsuite/g++.dg/ext/cleanup-5.C
===================================================================
--- gcc/testsuite/g++.dg/ext/cleanup-5.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/cleanup-5.C	(revision 0)
@@ -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 ();
+}
Index: gcc/testsuite/g++.dg/ext/cleanup-9.C
===================================================================
--- gcc/testsuite/g++.dg/ext/cleanup-9.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/cleanup-9.C	(revision 0)
@@ -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 ();
+}
Index: gcc/testsuite/g++.dg/ext/cleanup-11.C
===================================================================
--- gcc/testsuite/g++.dg/ext/cleanup-11.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/cleanup-11.C	(revision 0)
@@ -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 ();
+}
Index: gcc/testsuite/g++.dg/ext/cleanup-2.C
===================================================================
--- gcc/testsuite/g++.dg/ext/cleanup-2.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/cleanup-2.C	(revision 0)
@@ -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 ();
+}
Index: gcc/testsuite/g++.dg/ext/cleanup-6.C
===================================================================
--- gcc/testsuite/g++.dg/ext/cleanup-6.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/cleanup-6.C	(revision 0)
@@ -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" } } */
Index: gcc/testsuite/g++.dg/ext/cleanup-3.C
===================================================================
--- gcc/testsuite/g++.dg/ext/cleanup-3.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/cleanup-3.C	(revision 0)
@@ -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;
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]