While looking at PR c/16351, I noticed that all tests proposed for -Wnull-attribute (https://gcc.gnu.org/ml/gcc-patches/2014-01/msg01715.html) could be warned from the FEs by simply extending the existing Wnonnull.
Bootstrapped and regression tested on x86_64-linux-gnu. OK? gcc/ChangeLog: 2015-07-22 Manuel López-Ibáñez <m...@gcc.gnu.org> PR c/16351 * doc/invoke.texi (Wnonnull): Document behavior for returns_nonnull. gcc/testsuite/ChangeLog: 2015-07-22 Manuel López-Ibáñez <m...@gcc.gnu.org> PR c/16351 * c-c++-common/wnonnull-1.c: New test. gcc/cp/ChangeLog: 2015-07-22 Manuel López-Ibáñez <m...@gcc.gnu.org> PR c/16351 * typeck.c (check_return_expr): Call maybe_warn_returns_nonnull. gcc/c-family/ChangeLog: 2015-07-22 Manuel López-Ibáñez <m...@gcc.gnu.org> PR c/16351 * c-common.c (maybe_warn_returns_nonnull): New. * c-common.h (maybe_warn_returns_nonnull): Declare. gcc/c/ChangeLog: 2015-07-22 Manuel López-Ibáñez <m...@gcc.gnu.org> PR c/16351 * c-typeck.c (c_finish_return): Call maybe_warn_returns_nonnull.
Index: gcc/doc/invoke.texi =================================================================== --- gcc/doc/invoke.texi (revision 225868) +++ gcc/doc/invoke.texi (working copy) @@ -3709,11 +3709,13 @@ formats that may yield only a two-digit @item -Wnonnull @opindex Wnonnull @opindex Wno-nonnull Warn about passing a null pointer for arguments marked as -requiring a non-null value by the @code{nonnull} function attribute. +requiring a non-null value by the @code{nonnull} function attribute +or returning a null pointer from a function declared with the attribute +@code{returns_nonnull}. @option{-Wnonnull} is included in @option{-Wall} and @option{-Wformat}. It can be disabled with the @option{-Wno-nonnull} option. @item -Winit-self @r{(C, C++, Objective-C and Objective-C++ only)} Index: gcc/c-family/c-common.c =================================================================== --- gcc/c-family/c-common.c (revision 225868) +++ gcc/c-family/c-common.c (working copy) @@ -9508,10 +9508,22 @@ check_nonnull_arg (void * ARG_UNUSED (ct if (integer_zerop (param)) warning (OPT_Wnonnull, "null argument where non-null required " "(argument %lu)", (unsigned long) param_num); } +/* Possibly warn if RETVAL is a null pointer and FNDECL is declared + with attribute returns_nonnull. LOC is the location of RETVAL. */ + +void +maybe_warn_returns_nonnull (location_t loc, tree fndecl, tree retval) +{ + if (integer_zerop (retval) + && lookup_attribute ("returns_nonnull", + TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) + warning_at (loc, OPT_Wnonnull, "null return value where non-null required"); +} + /* Helper for nonnull attribute handling; fetch the operand number from the attribute argument list. */ static bool get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp) Index: gcc/c-family/c-common.h =================================================================== --- gcc/c-family/c-common.h (revision 225868) +++ gcc/c-family/c-common.h (working copy) @@ -1049,10 +1049,11 @@ extern void do_warn_double_promotion (tr extern void set_underlying_type (tree); extern void record_types_used_by_current_var_decl (tree); extern void record_locally_defined_typedef (tree); extern void maybe_record_typedef_use (tree); extern void maybe_warn_unused_local_typedefs (void); +extern void maybe_warn_returns_nonnull (location_t, tree, tree); extern void maybe_warn_bool_compare (location_t, enum tree_code, tree, tree); extern vec<tree, va_gc> *make_tree_vector (void); extern void release_tree_vector (vec<tree, va_gc> *); extern vec<tree, va_gc> *make_tree_vector_single (tree); extern vec<tree, va_gc> *make_tree_vector_from_list (tree); Index: gcc/c/c-typeck.c =================================================================== --- gcc/c/c-typeck.c (revision 225868) +++ gcc/c/c-typeck.c (working copy) @@ -9372,10 +9372,11 @@ c_finish_return (location_t loc, tree re { semantic_type = TREE_TYPE (retval); retval = TREE_OPERAND (retval, 0); } retval = c_fully_fold (retval, false, NULL); + maybe_warn_returns_nonnull (loc, current_function_decl, retval); if (semantic_type) retval = build1 (EXCESS_PRECISION_EXPR, semantic_type, retval); } if (!retval) Index: gcc/testsuite/c-c++-common/wnonnull-1.c =================================================================== --- gcc/testsuite/c-c++-common/wnonnull-1.c (revision 0) +++ gcc/testsuite/c-c++-common/wnonnull-1.c (revision 0) @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-Wnonnull" } */ + + +extern void foo(void *) __attribute__ ((__nonnull__ (1))); + +int z; +int y; + +void +com (int a) +{ + foo (a == 42 ? &z : (void *) 0); /* { dg-warning "null" } */ +} + +void +bar (void) +{ + foo ((void *)0); /* { dg-warning "null" } */ +} + +int * foo_r(int a) __attribute__((returns_nonnull)); +int * bar_r(void) __attribute__((returns_nonnull)); + +int * +foo_r(int a) +{ + switch (a) + { + case 0: + return &z; + default: + return (int *)0; /* { dg-warning "null" } */ + } +} + +int * +bar_r (void) +{ + return 0; /* { dg-warning "null" } */ +} + Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c (revision 225868) +++ gcc/cp/typeck.c (working copy) @@ -8702,10 +8702,12 @@ check_return_expr (tree retval, bool *no /* We don't need to do any conversions when there's nothing being returned. */ if (!retval) return NULL_TREE; + maybe_warn_returns_nonnull (input_location, current_function_decl, retval); + /* Do any required conversions. */ if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl)) /* No conversions are required. */ ; else