Attribute nonstring is currently only allowed on arrays and
pointers to plain char, but -Wstringop-truncation triggers
even for strncpy calls whose arguments are arrays of signed
or unsigned char (with or without a cast to char*).

To help deal with -Wstringop-truncation in the Linux kernel
it was suggested to me that it would be useful to be able
to make use of the attribute on all three narrow char types.
Apparently, there are enough calls to strncpy in the Linux
kernel with arguments of the other char types that trigger
the new warning, and the warning is considered sufficiently
useful that making use of the attribute to suppress
the warning rather than changing it ignore the other
two char types is preferable.

The attached patch relaxes the restriction and lets GCC
accept attribute nonstring on all three narrow character
types as well as their qualified forms.

Tested on x86_64-linux.

Martin
PR tree-optimization/84725 - enable attribute nonstring for all narrow character types

gcc/c-family/ChangeLog:

	PR tree-optimization/84725
	* c-attribs.c (handle_nonstring_attribute): Allow attribute nonstring
	with all three narrow character types, including their qualified forms.

gcc/testsuite/ChangeLog:

	PR tree-optimization/84725
	* c-c++-common/Wstringop-truncation-4.c: New test.
	* c-c++-common/attr-nonstring-5.c: New test.

Index: gcc/c-family/c-attribs.c
===================================================================
--- gcc/c-family/c-attribs.c	(revision 258259)
+++ gcc/c-family/c-attribs.c	(working copy)
@@ -3194,8 +3194,13 @@ handle_nonstring_attribute (tree *node, tree name,
 
       if (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
 	{
+	  /* Accept the attribute on arrays and pointers to all three
+	     narrow character types.  */
 	  tree eltype = TREE_TYPE (type);
-	  if (eltype == char_type_node)
+	  eltype = TYPE_MAIN_VARIANT (eltype);
+	  if (eltype == char_type_node
+	      || eltype == signed_char_type_node
+	      || eltype == unsigned_char_type_node)
 	    return NULL_TREE;
 	}
 
Index: gcc/testsuite/c-c++-common/Wstringop-truncation-4.c
===================================================================
--- gcc/testsuite/c-c++-common/Wstringop-truncation-4.c	(nonexistent)
+++ gcc/testsuite/c-c++-common/Wstringop-truncation-4.c	(working copy)
@@ -0,0 +1,125 @@
+/* PR middle-end/84725 - enable attribute nonstring for all narrow character
+   types
+   Verify that -Wstringop-truncation is issued for uses of arrays and
+   pointers to qualified forms of characters of all three types.
+   { dg-do compile }
+   { dg-options "-O -Wall -Wstringop-truncation" } */
+
+#if __cplusplus
+extern "C"
+#endif
+char* strncpy (char*, const char*, __SIZE_TYPE__);
+
+#define S "1234"
+
+struct Arrays
+{
+  char a[4];
+  signed char b[4];
+  unsigned char c[4];
+};
+
+void test_arrays (struct Arrays *p, const char *s)
+{
+  strncpy (p->a, s, sizeof p->a);
+  strncpy ((char*)p->b, s, sizeof p->b);
+  strncpy ((char*)p->c, s, sizeof p->c);
+}
+
+struct Pointers
+{
+  char *p;
+  signed char *q;
+  unsigned char *r;
+};
+
+void test_pointers (struct Pointers *p)
+{
+  strncpy (p->p, S, sizeof S - 1);
+  strncpy ((char*)p->q, S, sizeof S - 1);
+  strncpy ((char*)p->r, S, sizeof S - 1);
+}
+
+struct ConstArrays
+{
+  const char a[4];
+  const signed char b[4];
+  const unsigned char c[4];
+};
+
+void test_const_arrays (struct ConstArrays *p, const char *s)
+{
+  strncpy (p->a, s, sizeof p->a);
+  strncpy ((char*)p->b, s, sizeof p->b);
+  strncpy ((char*)p->c, s, sizeof p->c);
+}
+
+struct ConstPointers
+{
+  const char *p;
+  const signed char *q;
+  const unsigned char *r;
+};
+
+void test_const_pointers (struct ConstPointers *p)
+{
+  strncpy (p->p, S, sizeof S - 1);          /* { dg-warning [\\\[-Wstringop-truncation" } */
+  strncpy ((char*)p->q, S, sizeof S - 1);   /* { dg-warning [\\\[-Wstringop-truncation" } */
+  strncpy ((char*)p->r, S, sizeof S - 1);   /* { dg-warning [\\\[-Wstringop-truncation" } */
+}
+
+struct VolatileArrays
+{
+  volatile char a[4];
+  volatile signed char b[4];
+  volatile unsigned char c[4];
+};
+
+void test_volatile_arrays (struct VolatileArrays *p, const char *s)
+{
+  strncpy (p->a, s, sizeof p->a);           /* { dg-warning [\\\[-Wstringop-truncation" } */
+  strncpy ((char*)p->b, s, sizeof p->b);    /* { dg-warning [\\\[-Wstringop-truncation" } */
+  strncpy ((char*)p->c, s, sizeof p->c);    /* { dg-warning [\\\[-Wstringop-truncation" } */
+}
+
+struct VolatilePointers
+{
+  volatile char *p;
+  volatile signed char *q;
+  volatile unsigned char *r;
+};
+
+void test_volatile_pointers (struct VolatilePointers *p)
+{
+  strncpy (p->p, S, sizeof S - 1);          /* { dg-warning [\\\[-Wstringop-truncation" } */
+  strncpy ((char*)p->q, S, sizeof S - 1);   /* { dg-warning [\\\[-Wstringop-truncation" } */
+  strncpy ((char*)p->r, S, sizeof S - 1);   /* { dg-warning [\\\[-Wstringop-truncation" } */
+}
+
+struct ConstVolatileArrays
+{
+  const volatile char a[4];
+  const volatile signed char b[4];
+  const volatile unsigned char c[4];
+};
+
+void test_const_volatile_arrays (struct ConstVolatileArrays *p, const char *s)
+{
+  strncpy (p->a, s, sizeof p->a);           /* { dg-warning [\\\[-Wstringop-truncation" } */
+  strncpy ((char*)p->b, s, sizeof p->b);    /* { dg-warning [\\\[-Wstringop-truncation" } */
+  strncpy ((char*)p->c, s, sizeof p->c);    /* { dg-warning [\\\[-Wstringop-truncation" } */
+}
+
+struct ConstVolatilePointers
+{
+  const volatile char *p;
+  const volatile signed char *q;
+  const volatile unsigned char *r;
+};
+
+void test_const_volatile_pointers (struct ConstVolatilePointers *p)
+{
+  strncpy (p->p, S, sizeof S - 1);          /* { dg-warning [\\\[-Wstringop-truncation" } */
+  strncpy ((char*)p->q, S, sizeof S - 1);   /* { dg-warning [\\\[-Wstringop-truncation" } */
+  strncpy ((char*)p->r, S, sizeof S - 1);   /* { dg-warning [\\\[-Wstringop-truncation" } */
+}
Index: gcc/testsuite/c-c++-common/attr-nonstring-5.c
===================================================================
--- gcc/testsuite/c-c++-common/attr-nonstring-5.c	(nonexistent)
+++ gcc/testsuite/c-c++-common/attr-nonstring-5.c	(working copy)
@@ -0,0 +1,131 @@
+/* PR middle-end/84725 - enable attribute nonstring for all narrow character
+   types
+   Verify that using attribute nonstring with all three narrow character
+   types is accepted and using arrays and pointers to characters of all
+   three types (including their qualified forms) declared with the
+   attributes doesn't trigger -Wstringop-truncation warnings.
+   { dg-do compile }
+   { dg-options "-O -Wall -Wstringop-truncation" } */
+
+#if __cplusplus
+extern "C"
+#endif
+char* strncpy (char*, const char*, __SIZE_TYPE__);
+
+#define NONSTR __attribute__ ((nonstring))
+
+#define S "1234"
+
+struct Arrays
+{
+  char NONSTR a[4];
+  signed char NONSTR b[4];
+  unsigned char NONSTR c[4];
+};
+
+void test_arrays (struct Arrays *p, const char *s)
+{
+  strncpy (p->a, s, sizeof p->a);
+  strncpy ((char*)p->b, s, sizeof p->b);
+  strncpy ((char*)p->c, s, sizeof p->c);
+}
+
+struct Pointers
+{
+  char NONSTR *p;
+  signed char NONSTR *q;
+  unsigned char NONSTR *r;
+};
+
+void test_pointers (struct Pointers *p)
+{
+  strncpy (p->p, S, sizeof S - 1);
+  strncpy ((char*)p->q, S, sizeof S - 1);
+  strncpy ((char*)p->r, S, sizeof S - 1);
+}
+
+struct ConstArrays
+{
+  const char NONSTR a[4];
+  const signed char NONSTR b[4];
+  const unsigned char NONSTR c[4];
+};
+
+void test_const_arrays (struct ConstArrays *p, const char *s)
+{
+  strncpy ((char*)p->a, s, sizeof p->a);
+  strncpy ((char*)p->b, s, sizeof p->b);
+  strncpy ((char*)p->c, s, sizeof p->c);
+}
+
+struct ConstPointers
+{
+  const char NONSTR *p;
+  const signed char NONSTR *q;
+  const unsigned char NONSTR *r;
+};
+
+void test_const_pointers (struct ConstPointers *p)
+{
+  strncpy ((char*)p->p, S, sizeof S - 1);
+  strncpy ((char*)p->q, S, sizeof S - 1);
+  strncpy ((char*)p->r, S, sizeof S - 1);
+}
+
+struct VolatileArrays
+{
+  volatile char NONSTR a[4];
+  volatile signed char NONSTR b[4];
+  volatile unsigned char NONSTR c[4];
+};
+
+void test_volatile_arrays (struct VolatileArrays *p, const char *s)
+{
+  strncpy ((char*)p->a, s, sizeof p->a);
+  strncpy ((char*)p->b, s, sizeof p->b);
+  strncpy ((char*)p->c, s, sizeof p->c);
+}
+
+struct VolatilePointers
+{
+  volatile char NONSTR *p;
+  volatile signed char NONSTR *q;
+  volatile unsigned char NONSTR *r;
+};
+
+void test_volatile_pointers (struct VolatilePointers *p)
+{
+  strncpy ((char*)p->p, S, sizeof S - 1);
+  strncpy ((char*)p->q, S, sizeof S - 1);
+  strncpy ((char*)p->r, S, sizeof S - 1);
+}
+
+struct ConstVolatileArrays
+{
+  const volatile char NONSTR a[4];
+  const volatile signed char NONSTR b[4];
+  const volatile unsigned char NONSTR c[4];
+};
+
+void test_const_volatile_arrays (struct ConstVolatileArrays *p, const char *s)
+{
+  strncpy ((char*)p->a, s, sizeof p->a);
+  strncpy ((char*)p->b, s, sizeof p->b);
+  strncpy ((char*)p->c, s, sizeof p->c);
+}
+
+struct ConstVolatilePointers
+{
+  const volatile char NONSTR *p;
+  const volatile signed char NONSTR *q;
+  const volatile unsigned char NONSTR *r;
+};
+
+void test_const_volatile_pointers (struct ConstVolatilePointers *p)
+{
+  strncpy ((char*)p->p, S, sizeof S - 1);
+  strncpy ((char*)p->q, S, sizeof S - 1);
+  strncpy ((char*)p->r, S, sizeof S - 1);
+}
+
+/* { dg-prune-output "-Wdiscarded-qualifiers" } */

Reply via email to