From: jakub Date: Sun, 23 Sep 2007 09:39:39 +0000 (+0000) Subject: * expr.c (expand_expr_real_1) : Use get_callee_fndecl X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=commitdiff_plain;h=10fc867f364ae606d1373d9290cdaf2278011643 * expr.c (expand_expr_real_1) : Use get_callee_fndecl instead of checking CALL_EXPR_FN directly to test for builtins. If error or warning attributes are present, print error resp. warning. * c-common.c (handle_error_attribute): New function. (c_common_attribute_table): Add error and warning attributes. * doc/extend.texi: Document error and warning attributes. * gcc.dg/va-arg-pack-len-1.c: Use error and warning attributes. * gcc.dg/va-arg-pack-len-2.c: New test. * g++.dg/ext/va-arg-pack-len-1.C: Use error and warning attributes. * g++.dg/ext/va-arg-pack-len-2.C: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@128687 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f8ea8a1fd0a..cfad806a99b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,14 @@ 2007-09-23 Jakub Jelinek + * expr.c (expand_expr_real_1) : Use get_callee_fndecl + instead of checking CALL_EXPR_FN directly to test for builtins. + If error or warning attributes are present, print + error resp. warning. + * c-common.c (handle_error_attribute): New function. + (c_common_attribute_table): Add error and warning + attributes. + * doc/extend.texi: Document error and warning attributes. + * tree.h (block_nonartificial_location): New prototype. * tree.c (block_nonartificial_location): New function. * dwarf2out.c (gen_subprogram_die): Add DW_AT_artificial diff --git a/gcc/c-common.c b/gcc/c-common.c index 3b5f477f5f9..8ebc92007ca 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -518,6 +518,7 @@ static tree handle_always_inline_attribute (tree *, tree, tree, int, static tree handle_gnu_inline_attribute (tree *, tree, tree, int, bool *); static tree handle_artificial_attribute (tree *, tree, tree, int, bool *); static tree handle_flatten_attribute (tree *, tree, tree, int, bool *); +static tree handle_error_attribute (tree *, tree, tree, int, bool *); static tree handle_used_attribute (tree *, tree, tree, int, bool *); static tree handle_unused_attribute (tree *, tree, tree, int, bool *); static tree handle_externally_visible_attribute (tree *, tree, tree, int, @@ -663,6 +664,10 @@ const struct attribute_spec c_common_attribute_table[] = handle_cold_attribute }, { "hot", 0, 0, true, false, false, handle_hot_attribute }, + { "warning", 1, 1, true, false, false, + handle_error_attribute }, + { "error", 1, 1, true, false, false, + handle_error_attribute }, { NULL, 0, 0, false, false, false, NULL } }; @@ -4923,6 +4928,26 @@ handle_flatten_attribute (tree *node, tree name, return NULL_TREE; } +/* Handle a "warning" or "error" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_error_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL + || TREE_CODE (TREE_VALUE (args)) == STRING_CST) + /* Do nothing else, just set the attribute. We'll get at + it later with lookup_attribute. */ + ; + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} /* Handle a "used" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index de3a1211c73..a4f7a3a68ce 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -1803,7 +1803,8 @@ attributes are currently defined for functions on all targets: @code{destructor}, @code{used}, @code{unused}, @code{deprecated}, @code{weak}, @code{malloc}, @code{alias}, @code{warn_unused_result}, @code{nonnull}, @code{gnu_inline}, @code{externally_visible}, -@code{hot}, @code{cold} and @code{artificial}. +@code{hot}, @code{cold}, @code{artificial}, @code{error} +and @code{warning}. Several other attributes are defined for functions on particular target systems. Other attributes, including @code{section} are supported for variables declarations (@pxref{Variable Attributes}) and @@ -1941,6 +1942,30 @@ Whether the function itself is considered for inlining depends on its size and the current inlining parameters. The @code{flatten} attribute only works reliably in unit-at-a-time mode. +@item error ("@var{message}") +@cindex @code{error} function attribute +If this attribute is used on a function declaration and a call to such a function +is not eliminated through dead code elimination or other optimizations, an error +which will include @var{message} will be diagnosed. This is useful +for compile time checking, especially together with @code{__builtin_constant_p} +and inline functions where checking the inline function arguments is not +possible through @code{extern char [(condition) ? 1 : -1];} tricks. +While it is possible to leave the function undefined and thus invoke +a link failure, when using this attribute the problem will be diagnosed +earlier and with exact location of the call even in presence of inline +functions or when not emitting debugging information. + +@item warning ("@var{message}") +@cindex @code{warning} function attribute +If this attribute is used on a function declaration and a call to such a function +is not eliminated through dead code elimination or other optimizations, a warning +which will include @var{message} will be diagnosed. This is useful +for compile time checking, especially together with @code{__builtin_constant_p} +and inline functions. While it is possible to define the function with +a message in @code{.gnu.warning*} section, when using this attribute the problem +will be diagnosed earlier and with exact location of the call even in presence +of inline functions or when not emitting debugging information. + @item cdecl @cindex functions that do pop the argument stack on the 386 @opindex mrtd diff --git a/gcc/expr.c b/gcc/expr.c index c7b29b53c94..afd01acb4aa 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -8002,21 +8002,32 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, inlining. */ if (CALL_EXPR_VA_ARG_PACK (exp)) error ("invalid use of %<__builtin_va_arg_pack ()%>"); - /* Check for a built-in function. */ - if (TREE_CODE (CALL_EXPR_FN (exp)) == ADDR_EXPR - && (TREE_CODE (TREE_OPERAND (CALL_EXPR_FN (exp), 0)) - == FUNCTION_DECL) - && DECL_BUILT_IN (TREE_OPERAND (CALL_EXPR_FN (exp), 0))) - { - if (DECL_BUILT_IN_CLASS (TREE_OPERAND (CALL_EXPR_FN (exp), 0)) - == BUILT_IN_FRONTEND) - return lang_hooks.expand_expr (exp, original_target, - tmode, modifier, - alt_rtl); - else - return expand_builtin (exp, target, subtarget, tmode, ignore); - } - + { + tree fndecl = get_callee_fndecl (exp), attr; + + if (fndecl + && (attr = lookup_attribute ("error", + DECL_ATTRIBUTES (fndecl))) != NULL) + error ("call to %qs declared with attribute error: %s", + lang_hooks.decl_printable_name (fndecl, 1), + TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)))); + if (fndecl + && (attr = lookup_attribute ("warning", + DECL_ATTRIBUTES (fndecl))) != NULL) + warning (0, "call to %qs declared with attribute warning: %s", + lang_hooks.decl_printable_name (fndecl, 1), + TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)))); + + /* Check for a built-in function. */ + if (fndecl && DECL_BUILT_IN (fndecl)) + { + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_FRONTEND) + return lang_hooks.expand_expr (exp, original_target, + tmode, modifier, alt_rtl); + else + return expand_builtin (exp, target, subtarget, tmode, ignore); + } + } return expand_call (exp, target, ignore); case NON_LVALUE_EXPR: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a6d166095a3..294cf33e11d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,12 @@ 2007-09-23 Jakub Jelinek + * gcc.dg/va-arg-pack-len-1.c: Use error and warning + attributes. + * gcc.dg/va-arg-pack-len-2.c: New test. + * g++.dg/ext/va-arg-pack-len-1.C: Use error and warning + attributes. + * g++.dg/ext/va-arg-pack-len-2.C: New test. + PR middle-end/28755 * gcc.dg/pr28755.c: New test. diff --git a/gcc/testsuite/g++.dg/ext/va-arg-pack-len-1.C b/gcc/testsuite/g++.dg/ext/va-arg-pack-len-1.C index 36104cf840b..d3c84091b8f 100644 --- a/gcc/testsuite/g++.dg/ext/va-arg-pack-len-1.C +++ b/gcc/testsuite/g++.dg/ext/va-arg-pack-len-1.C @@ -3,8 +3,10 @@ #include -extern "C" int warn_open_missing_mode (void); -extern "C" int warn_open_too_many_arguments (void); +extern "C" int error_open_missing_mode (void) + __attribute__((__error__ ("open with O_CREAT needs 3 arguments, only 2 were given"))); +extern "C" int warn_open_too_many_arguments (void) + __attribute__((__warning__ ("open called with more than 3 arguments"))); extern "C" void abort (void); char expected_char; @@ -83,7 +85,7 @@ myopen (const char *path, int oflag, ...) { if ((oflag & 0x40) != 0 && __builtin_va_arg_pack_len () < 1) { - warn_open_missing_mode (); + error_open_missing_mode (); return myopen2 (path, oflag); } return myopenva (path, oflag, __builtin_va_arg_pack ()); diff --git a/gcc/testsuite/g++.dg/ext/va-arg-pack-len-2.C b/gcc/testsuite/g++.dg/ext/va-arg-pack-len-2.C new file mode 100644 index 00000000000..0d369bdc9cb --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/va-arg-pack-len-2.C @@ -0,0 +1,42 @@ +// { dg-do compile } +// { dg-options "-O2" } + +#include + +extern int error_open_missing_mode (void) + __attribute__((__error__ ("open with O_CREAT needs 3 arguments, only 2 were given"))); +extern int warn_open_too_many_arguments (void) + __attribute__((__warning__ ("open called with more than 3 arguments"))); + +extern int myopen2 (const char *path, int oflag); +extern int myopenva (const char *path, int oflag, ...); + +extern inline __attribute__((always_inline, gnu_inline)) int +myopen (const char *path, int oflag, ...) +{ + if (__builtin_va_arg_pack_len () > 1) + warn_open_too_many_arguments (); // { dg-warning "called with more than 3" } + + if (__builtin_constant_p (oflag)) + { + if ((oflag & 0x40) != 0 && __builtin_va_arg_pack_len () < 1) + { + error_open_missing_mode (); // { dg-error "needs 3 arguments, only 2 were given" } + return myopen2 (path, oflag); + } + return myopenva (path, oflag, __builtin_va_arg_pack ()); + } + + if (__builtin_va_arg_pack_len () < 1) + return myopen2 (path, oflag); + + return myopenva (path, oflag, __builtin_va_arg_pack ()); +} + +int +main (void) +{ + myopen ("h", 0x43); + myopen ("i", 0x43, 0644, 0655); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/va-arg-pack-len-1.c b/gcc/testsuite/gcc.dg/va-arg-pack-len-1.c index 7df63800688..409c3458508 100644 --- a/gcc/testsuite/gcc.dg/va-arg-pack-len-1.c +++ b/gcc/testsuite/gcc.dg/va-arg-pack-len-1.c @@ -3,8 +3,10 @@ #include -extern int warn_open_missing_mode (void); -extern int warn_open_too_many_arguments (void); +extern int error_open_missing_mode (void) + __attribute__((__error__ ("open with O_CREAT needs 3 arguments, only 2 were given"))); +extern int warn_open_too_many_arguments (void) + __attribute__((__warning__ ("open called with more than 3 arguments"))); extern void abort (void); char expected_char; @@ -83,7 +85,7 @@ myopen (const char *path, int oflag, ...) { if ((oflag & 0x40) != 0 && __builtin_va_arg_pack_len () < 1) { - warn_open_missing_mode (); + error_open_missing_mode (); return myopen2 (path, oflag); } return myopenva (path, oflag, __builtin_va_arg_pack ()); diff --git a/gcc/testsuite/gcc.dg/va-arg-pack-len-2.c b/gcc/testsuite/gcc.dg/va-arg-pack-len-2.c new file mode 100644 index 00000000000..c3fa856fdaa --- /dev/null +++ b/gcc/testsuite/gcc.dg/va-arg-pack-len-2.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include + +extern int error_open_missing_mode (void) + __attribute__((__error__ ("open with O_CREAT needs 3 arguments, only 2 were given"))); +extern int warn_open_too_many_arguments (void) + __attribute__((__warning__ ("open called with more than 3 arguments"))); + +extern int myopen2 (const char *path, int oflag); +extern int myopenva (const char *path, int oflag, ...); + +extern inline __attribute__((always_inline, gnu_inline)) int +myopen (const char *path, int oflag, ...) +{ + if (__builtin_va_arg_pack_len () > 1) + warn_open_too_many_arguments (); /* { dg-warning "called with more than 3" } */ + + if (__builtin_constant_p (oflag)) + { + if ((oflag & 0x40) != 0 && __builtin_va_arg_pack_len () < 1) + { + error_open_missing_mode (); /* { dg-error "needs 3 arguments, only 2 were given" } */ + return myopen2 (path, oflag); + } + return myopenva (path, oflag, __builtin_va_arg_pack ()); + } + + if (__builtin_va_arg_pack_len () < 1) + return myopen2 (path, oflag); + + return myopenva (path, oflag, __builtin_va_arg_pack ()); +} + +int +main (void) +{ + myopen ("h", 0x43); + myopen ("i", 0x43, 0644, 0655); + return 0; +}