Hello,this patch adds an attribute to let the compiler know that a function never returns NULL. I saw some ECF_* flags, but the attribute seems sufficient. I considered using nonnull(0), but then it would have been confusing that the version of nonnull without arguments applies only to parameters and not the return value.
2013-10-08 Marc Glisse <marc.gli...@inria.fr> PR tree-optimization/20318 gcc/c-family/ * c-common.c (handle_returns_nonnull_attribute): New function. (c_common_attribute_table): Add returns_nonnull. gcc/ * doc/extend.texi (returns_nonnull): New function attribute. * fold-const.c (tree_expr_nonzero_warnv_p): Look for returns_nonnull attribute. * tree-vrp.c (gimple_stmt_nonzero_warnv_p): Likewise. (stmt_interesting_for_vrp): Accept all GIMPLE_CALL. gcc/testsuite/ * c-c++-common/pr20318.c: New file. * gcc.dg/tree-ssa/pr20318.c: New file. -- Marc Glisse
Index: c-family/c-common.c =================================================================== --- c-family/c-common.c (revision 203241) +++ c-family/c-common.c (working copy) @@ -364,20 +364,21 @@ static tree handle_warn_unused_result_at bool *); static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *); static tree handle_target_attribute (tree *, tree, tree, int, bool *); static tree handle_optimize_attribute (tree *, tree, tree, int, bool *); static tree ignore_attribute (tree *, tree, tree, int, bool *); static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *); static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); static tree handle_warn_unused_attribute (tree *, tree, tree, int, bool *); +static tree handle_returns_nonnull_attribute (tree *, tree, tree, int, bool *); static void check_function_nonnull (tree, int, tree *); static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT); static bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *); static int resort_field_decl_cmp (const void *, const void *); /* Reserved words. The third field is a mask: keywords are disabled if they match the mask. @@ -740,20 +741,22 @@ const struct attribute_spec c_common_att { "*tm regparm", 0, 0, false, true, true, ignore_attribute, false }, { "no_split_stack", 0, 0, true, false, false, handle_no_split_stack_attribute, false }, /* For internal use (marking of builtins and runtime functions) only. The name contains space to prevent its usage in source code. */ { "fn spec", 1, 1, false, true, true, handle_fnspec_attribute, false }, { "warn_unused", 0, 0, false, false, false, handle_warn_unused_attribute, false }, + { "returns_nonnull", 0, 0, false, true, true, + handle_returns_nonnull_attribute, false }, { NULL, 0, 0, false, false, false, NULL, false } }; /* Give the specifications for the format attributes, used by C and all descendants. */ const struct attribute_spec c_common_format_attribute_table[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, affects_type_identity } */ @@ -9041,20 +9044,37 @@ handle_no_split_stack_attribute (tree *n } else if (DECL_INITIAL (decl)) { error_at (DECL_SOURCE_LOCATION (decl), "can%'t set %qE attribute after definition", name); *no_add_attrs = true; } return NULL_TREE; } + +/* Handle a "returns_nonnull" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_returns_nonnull_attribute (tree *node, tree, tree, int, + bool *no_add_attrs) +{ + // Even without a prototype we still have a return type we can check. + if (TREE_CODE (TREE_TYPE (*node)) != POINTER_TYPE) + { + error ("returns_nonnull attribute on a function not returning a pointer"); + *no_add_attrs = true; + } + return NULL_TREE; +} + /* Check for valid arguments being passed to a function with FNTYPE. There are NARGS arguments in the array ARGARRAY. */ void check_function_arguments (const_tree fntype, int nargs, tree *argarray) { /* Check for null being passed in a pointer argument that must be non-null. We also need to do this if format checking is enabled. */ if (warn_nonnull) Index: doc/extend.texi =================================================================== --- doc/extend.texi (revision 203241) +++ doc/extend.texi (working copy) @@ -2126,21 +2126,22 @@ attributes when making a declaration. T attribute specification inside double parentheses. The following attributes are currently defined for functions on all targets: @code{aligned}, @code{alloc_size}, @code{noreturn}, @code{returns_twice}, @code{noinline}, @code{noclone}, @code{always_inline}, @code{flatten}, @code{pure}, @code{const}, @code{nothrow}, @code{sentinel}, @code{format}, @code{format_arg}, @code{no_instrument_function}, @code{no_split_stack}, @code{section}, @code{constructor}, @code{destructor}, @code{used}, @code{unused}, @code{deprecated}, @code{weak}, @code{malloc}, @code{alias}, @code{ifunc}, -@code{warn_unused_result}, @code{nonnull}, @code{gnu_inline}, +@code{warn_unused_result}, @code{nonnull}, +@code{returns_nonnull}, @code{gnu_inline}, @code{externally_visible}, @code{hot}, @code{cold}, @code{artificial}, @code{no_sanitize_address}, @code{no_address_safety_analysis}, @code{no_sanitize_undefined}, @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 for types (@pxref{Type Attributes}). GCC plugins may provide their own attributes. @@ -3302,20 +3303,34 @@ on the knowledge that certain function a If no argument index list is given to the @code{nonnull} attribute, all pointer arguments are marked as non-null. To illustrate, the following declaration is equivalent to the previous example: @smallexample extern void * my_memcpy (void *dest, const void *src, size_t len) __attribute__((nonnull)); @end smallexample +@item returns_nonnull (@var{arg-index}, @dots{}) +@cindex @code{returns_nonnull} function attribute +The @code{returns_nonnull} attribute specifies that the function +return value should be a non-null pointer. For instance, the declaration: + +@smallexample +extern void * +mymalloc (size_t len) __attribute__((returns_nonnull)); +@end smallexample + +@noindent +lets the compiler optimize callers based on the knowledge +that the return value will never be null. + @item noreturn @cindex @code{noreturn} function attribute A few standard library functions, such as @code{abort} and @code{exit}, cannot return. GCC knows this automatically. Some programs define their own functions that never return. You can declare them @code{noreturn} to tell the compiler this fact. For example, @smallexample @group void fatal () __attribute__ ((noreturn)); Index: fold-const.c =================================================================== --- fold-const.c (revision 203241) +++ fold-const.c (working copy) @@ -16222,20 +16222,24 @@ tree_expr_nonzero_warnv_p (tree t, bool strict_overflow_p); case CALL_EXPR: { tree fndecl = get_callee_fndecl (t); if (!fndecl) return false; if (flag_delete_null_pointer_checks && !flag_check_new && DECL_IS_OPERATOR_NEW (fndecl) && !TREE_NOTHROW (fndecl)) return true; + if (flag_delete_null_pointer_checks + && lookup_attribute ("returns_nonnull", + TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) + return true; return alloca_call_p (t); } default: break; } return false; } /* Return true when T is an address and is known to be nonzero. Index: testsuite/c-c++-common/pr20318.c =================================================================== --- testsuite/c-c++-common/pr20318.c (revision 0) +++ testsuite/c-c++-common/pr20318.c (working copy) @@ -0,0 +1,3 @@ +/* { dg-do compile } */ + +extern int f() __attribute__((returns_nonnull)); /* { dg-error "not returning a pointer" } */ Property changes on: testsuite/c-c++-common/pr20318.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision URL \ No newline at end of property Index: testsuite/gcc.dg/tree-ssa/pr20318.c =================================================================== --- testsuite/gcc.dg/tree-ssa/pr20318.c (revision 0) +++ testsuite/gcc.dg/tree-ssa/pr20318.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do compile { target { ! keeps_null_pointer_checks } } } */ +/* { dg-options "-O2 -fdump-tree-original -fdump-tree-vrp1" } */ + +extern int* f(int) __attribute__((returns_nonnull)); +extern void eliminate (); +void g () { + if (f (2) == 0) + eliminate (); +} +void h () { + int *p = f (2); + if (p == 0) + eliminate (); +} + +/* { dg-final { scan-tree-dump-times "== 0" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "Folding predicate\[^\\n\]*to 0" 1 "vrp1" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ +/* { dg-final { cleanup-tree-dump "vrp1" } } */ Property changes on: testsuite/gcc.dg/tree-ssa/pr20318.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision URL \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: tree-vrp.c =================================================================== --- tree-vrp.c (revision 203241) +++ tree-vrp.c (working copy) @@ -1031,40 +1031,44 @@ gimple_assign_nonzero_warnv_p (gimple st case GIMPLE_SINGLE_RHS: return tree_single_nonzero_warnv_p (gimple_assign_rhs1 (stmt), strict_overflow_p); case GIMPLE_INVALID_RHS: gcc_unreachable (); default: gcc_unreachable (); } } -/* Return true if STMT is know to to compute a non-zero value. +/* Return true if STMT is known to compute a non-zero value. If the return value is based on the assumption that signed overflow is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change *STRICT_OVERFLOW_P.*/ static bool gimple_stmt_nonzero_warnv_p (gimple stmt, bool *strict_overflow_p) { switch (gimple_code (stmt)) { case GIMPLE_ASSIGN: return gimple_assign_nonzero_warnv_p (stmt, strict_overflow_p); case GIMPLE_CALL: { tree fndecl = gimple_call_fndecl (stmt); if (!fndecl) return false; if (flag_delete_null_pointer_checks && !flag_check_new && DECL_IS_OPERATOR_NEW (fndecl) && !TREE_NOTHROW (fndecl)) return true; + if (flag_delete_null_pointer_checks && + lookup_attribute ("returns_nonnull", + TYPE_ATTRIBUTES (gimple_call_fntype (stmt)))) + return true; return gimple_alloca_call_p (stmt); } default: gcc_unreachable (); } } /* Like tree_expr_nonzero_warnv_p, but this function uses value ranges obtained so far. */ @@ -6489,24 +6493,21 @@ stmt_interesting_for_vrp (gimple stmt) else if (is_gimple_assign (stmt) || is_gimple_call (stmt)) { tree lhs = gimple_get_lhs (stmt); /* In general, assignments with virtual operands are not useful for deriving ranges, with the obvious exception of calls to builtin functions. */ if (lhs && TREE_CODE (lhs) == SSA_NAME && (INTEGRAL_TYPE_P (TREE_TYPE (lhs)) || POINTER_TYPE_P (TREE_TYPE (lhs))) - && ((is_gimple_call (stmt) - && gimple_call_fndecl (stmt) != NULL_TREE - && (DECL_BUILT_IN (gimple_call_fndecl (stmt)) - || DECL_IS_OPERATOR_NEW (gimple_call_fndecl (stmt)))) + && (is_gimple_call (stmt) || !gimple_vuse (stmt))) return true; } else if (gimple_code (stmt) == GIMPLE_COND || gimple_code (stmt) == GIMPLE_SWITCH) return true; return false; }