Hello,
I would like to add support for new attribute: nonzero.
Nonzero attribute works the same way as nonnull but instead of checking for
NULL, it checks for integer or enum with value 0.
Nonzero attribute would issue warnings with new compiler flag
-Wnonzero and -Wnonzero-compare.
Nonzero could be useful when user wants to make sure that for example enum
with value of 0 is not used or flag argument is not set to 0.
For example compiling following code with "gcc -Wnonzero -Wnonzero-compare
foo.c"
#include
enum bar{NONE, SOME};
void foo(int d, enum bar b) __attribute__ ((nonzero (1, 2)));
void foo(int d, enum bar b) {
printf("%d\n", d == 0);
printf("%d\n", b == NONE);
}
int main() {
foo(0, NONE);
}
Would give the following error
foo.c: In function 'main':
foo.c:11:9: warning: zero argument where nonzero required (argument 1)
[-Wnonzero]
11 | foo(0, NONE);
| ^~~
foo.c:11:9: warning: zero argument where nonzero required (argument 2)
[-Wnonzero]
foo.c: In function 'foo':
foo.c:6:9: warning: 'nonzero' argument 'd' compared to 0 [-Wnonzero-compare]
6 | printf("%d\n", d == 0);
| ^~
foo.c:7:9: warning: 'nonzero' argument 'b' compared to 0 [-Wnonzero-compare]
7 | printf("%d\n", b == NONE);
| ^
I attached a diff of my POC implementation. It's basically a copied and modified
version of nonnull attribute. The diff is fairly big and doesn't contain any
tests.
I'm more than happy to figure out tests for it if people think that supporting
nonzero attribute is a good idea.
This is my first time working with GCC so please let me know if there's any
mistakes!
Best wishes,
Miika Alikirri
---
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 5d05e8e0dc8..ae5db84cdfa 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1360,6 +1360,7 @@ OBJS = \
gimple-ssa-evrp-analyze.o \
gimple-ssa-isolate-paths.o \
gimple-ssa-nonnull-compare.o \
+ gimple-ssa-nonzero-compare.o \
gimple-ssa-split-paths.o \
gimple-ssa-store-merging.o \
gimple-ssa-strength-reduction.o \
diff --git a/gcc/builtin-attrs.def b/gcc/builtin-attrs.def
index 3239311b5a4..04db95d27ff 100644
--- a/gcc/builtin-attrs.def
+++ b/gcc/builtin-attrs.def
@@ -98,6 +98,7 @@ DEF_ATTR_IDENT (ATTR_FORMAT, "format")
DEF_ATTR_IDENT (ATTR_FORMAT_ARG, "format_arg")
DEF_ATTR_IDENT (ATTR_MALLOC, "malloc")
DEF_ATTR_IDENT (ATTR_NONNULL, "nonnull")
+DEF_ATTR_IDENT (ATTR_NONZERO, "nonzero")
DEF_ATTR_IDENT (ATTR_NORETURN, "noreturn")
DEF_ATTR_IDENT (ATTR_NOTHROW, "nothrow")
DEF_ATTR_IDENT (ATTR_LEAF, "leaf")
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index ac936d5..b76e56b14b9 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -119,6 +119,7 @@ static tree handle_novops_attribute (tree *, tree, tree,
int, bool *);
static tree handle_vector_size_attribute (tree *, tree, tree, int,
bool *);
static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
+static tree handle_nonzero_attribute (tree *, tree, tree, int, bool *);
static tree handle_nonstring_attribute (tree *, tree, tree, int, bool *);
static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *);
@@ -379,6 +380,8 @@ const struct attribute_spec c_common_attribute_table[] =
handle_tls_model_attribute, NULL },
{ "nonnull",0, -1, false, true, true, false,
handle_nonnull_attribute, NULL },
+ { "nonzero",0, -1, false, true, true, false,
+ handle_nonzero_attribute, NULL },
{ "nonstring", 0, 0, true, false, false, false,
handle_nonstring_attribute, NULL },
{ "nothrow",0, 0, true, false, false, false,
@@ -3754,6 +3757,55 @@ handle_nonnull_attribute (tree *node, tree name,
return NULL_TREE;
}
+/* Handle the "nonzero" attribute. */
+
+static tree
+handle_nonzero_attribute (tree *node, tree name,
+ tree args, int ARG_UNUSED (flags),
+ bool *no_add_attrs)
+{
+ tree type = *node;
+
+ /* If no arguments are specified, all int arguments should be
+ non-zero. Verify a full prototype is given so that the arguments
+ will have the correct types when we actually check them later.
+ Avoid diagnosing type-generic built-ins since those have no
+ prototype. */
+ if (!args)
+{
+ if (!prototype_p (type)
+ && (!TYPE_ATTRIBUTES (type)
+ || !lookup_attribute ("type generic", TYPE_ATTRIBUTES (type
+ {
+ error ("%qE attribute without arguments on a non-prototype",
+name);
+ *no_add_attrs = true;
+ }
+ return NULL_TR