Commit 5c113154 by Mark Mitchell Committed by Mark Mitchell

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
parent 0b4cafec
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
......
......@@ -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;
if (type != error_mark_node && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
/* 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. */
......
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
/* { 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" } */
/* { 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 ();
}
/* { 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 ();
}
/* { 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 ();
}
/* { 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;
}
/* { 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;
}
/* 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 ();
}
/* { 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" } } */
/* { 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 ();
}
/* { 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 ();
}
// 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 ();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment