re PR c/20318 (RFE: add attribute to specify that a function never returns NULL)
2013-10-09 Marc Glisse <marc.glisse@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. From-SVN: r203316
This commit is contained in:
parent
378f8976f2
commit
826cacfe24
|
@ -1,3 +1,12 @@
|
||||||
|
2013-10-09 Marc Glisse <marc.glisse@inria.fr>
|
||||||
|
|
||||||
|
PR tree-optimization/20318
|
||||||
|
* 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.
|
||||||
|
|
||||||
2013-10-09 Eric Botcazou <ebotcazou@adacore.com>
|
2013-10-09 Eric Botcazou <ebotcazou@adacore.com>
|
||||||
|
|
||||||
PR middle-end/58570
|
PR middle-end/58570
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
2013-10-09 Marc Glisse <marc.glisse@inria.fr>
|
||||||
|
|
||||||
|
PR tree-optimization/20318
|
||||||
|
* c-common.c (handle_returns_nonnull_attribute): New function.
|
||||||
|
(c_common_attribute_table): Add returns_nonnull.
|
||||||
|
|
||||||
2013-10-03 Marc Glisse <marc.glisse@inria.fr>
|
2013-10-03 Marc Glisse <marc.glisse@inria.fr>
|
||||||
|
|
||||||
PR c++/19476
|
PR c++/19476
|
||||||
|
|
|
@ -371,6 +371,7 @@ static tree ignore_attribute (tree *, tree, tree, int, bool *);
|
||||||
static tree handle_no_split_stack_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_fnspec_attribute (tree *, tree, tree, int, bool *);
|
||||||
static tree handle_warn_unused_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_function_nonnull (tree, int, tree *);
|
||||||
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
|
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
|
||||||
|
@ -747,6 +748,8 @@ const struct attribute_spec c_common_attribute_table[] =
|
||||||
handle_fnspec_attribute, false },
|
handle_fnspec_attribute, false },
|
||||||
{ "warn_unused", 0, 0, false, false, false,
|
{ "warn_unused", 0, 0, false, false, false,
|
||||||
handle_warn_unused_attribute, 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 }
|
{ NULL, 0, 0, false, false, false, NULL, false }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9048,6 +9051,23 @@ handle_no_split_stack_attribute (tree *node, tree name,
|
||||||
|
|
||||||
return NULL_TREE;
|
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.
|
/* Check for valid arguments being passed to a function with FNTYPE.
|
||||||
There are NARGS arguments in the array ARGARRAY. */
|
There are NARGS arguments in the array ARGARRAY. */
|
||||||
|
|
|
@ -2133,7 +2133,8 @@ attributes are currently defined for functions on all targets:
|
||||||
@code{section}, @code{constructor},
|
@code{section}, @code{constructor},
|
||||||
@code{destructor}, @code{used}, @code{unused}, @code{deprecated},
|
@code{destructor}, @code{used}, @code{unused}, @code{deprecated},
|
||||||
@code{weak}, @code{malloc}, @code{alias}, @code{ifunc},
|
@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{externally_visible}, @code{hot}, @code{cold}, @code{artificial},
|
||||||
@code{no_sanitize_address}, @code{no_address_safety_analysis},
|
@code{no_sanitize_address}, @code{no_address_safety_analysis},
|
||||||
@code{no_sanitize_undefined},
|
@code{no_sanitize_undefined},
|
||||||
|
@ -3309,6 +3310,20 @@ my_memcpy (void *dest, const void *src, size_t len)
|
||||||
__attribute__((nonnull));
|
__attribute__((nonnull));
|
||||||
@end smallexample
|
@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
|
@item noreturn
|
||||||
@cindex @code{noreturn} function attribute
|
@cindex @code{noreturn} function attribute
|
||||||
A few standard library functions, such as @code{abort} and @code{exit},
|
A few standard library functions, such as @code{abort} and @code{exit},
|
||||||
|
|
|
@ -16229,6 +16229,10 @@ tree_expr_nonzero_warnv_p (tree t, bool *strict_overflow_p)
|
||||||
&& DECL_IS_OPERATOR_NEW (fndecl)
|
&& DECL_IS_OPERATOR_NEW (fndecl)
|
||||||
&& !TREE_NOTHROW (fndecl))
|
&& !TREE_NOTHROW (fndecl))
|
||||||
return true;
|
return true;
|
||||||
|
if (flag_delete_null_pointer_checks
|
||||||
|
&& lookup_attribute ("returns_nonnull",
|
||||||
|
TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
|
||||||
|
return true;
|
||||||
return alloca_call_p (t);
|
return alloca_call_p (t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
2013-10-09 Marc Glisse <marc.glisse@inria.fr>
|
||||||
|
|
||||||
|
PR tree-optimization/20318
|
||||||
|
* c-c++-common/pr20318.c: New file.
|
||||||
|
* gcc.dg/tree-ssa/pr20318.c: New file.
|
||||||
|
|
||||||
2013-10-09 Eric Botcazou <ebotcazou@adacore.com>
|
2013-10-09 Eric Botcazou <ebotcazou@adacore.com>
|
||||||
|
|
||||||
* gcc.c-torture/execute/pr58570.c: New test.
|
* gcc.c-torture/execute/pr58570.c: New test.
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
|
||||||
|
extern int f() __attribute__((returns_nonnull)); /* { dg-error "not returning a pointer" } */
|
|
@ -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" } } */
|
|
@ -1038,7 +1038,7 @@ gimple_assign_nonzero_warnv_p (gimple stmt, bool *strict_overflow_p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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
|
If the return value is based on the assumption that signed overflow is
|
||||||
undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
|
undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
|
||||||
*STRICT_OVERFLOW_P.*/
|
*STRICT_OVERFLOW_P.*/
|
||||||
|
@ -1058,6 +1058,10 @@ gimple_stmt_nonzero_warnv_p (gimple stmt, bool *strict_overflow_p)
|
||||||
&& DECL_IS_OPERATOR_NEW (fndecl)
|
&& DECL_IS_OPERATOR_NEW (fndecl)
|
||||||
&& !TREE_NOTHROW (fndecl))
|
&& !TREE_NOTHROW (fndecl))
|
||||||
return true;
|
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);
|
return gimple_alloca_call_p (stmt);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -6536,10 +6540,7 @@ stmt_interesting_for_vrp (gimple stmt)
|
||||||
if (lhs && TREE_CODE (lhs) == SSA_NAME
|
if (lhs && TREE_CODE (lhs) == SSA_NAME
|
||||||
&& (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
|
&& (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
|
||||||
|| POINTER_TYPE_P (TREE_TYPE (lhs)))
|
|| POINTER_TYPE_P (TREE_TYPE (lhs)))
|
||||||
&& ((is_gimple_call (stmt)
|
&& (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))))
|
|
||||||
|| !gimple_vuse (stmt)))
|
|| !gimple_vuse (stmt)))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue