This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH v4] warning about const multidimensional array as function parameter
- From: Martin Uecker <uecker at eecs dot berkeley dot edu>
- To: Joseph Myers <joseph at codesourcery dot com>
- Cc: gcc Mailing List <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 10 Nov 2014 11:08:05 -0800
- Subject: [PATCH v4] warning about const multidimensional array as function parameter
- Authentication-results: sourceware.org; auth=none
- References: <20141025123245 dot 4ed09551 at lemur> <Pine dot LNX dot 4 dot 64 dot 1410271254470 dot 13536 at digraph dot polyomino dot org dot uk> <20141028231040 dot 38b1cbc0 at lemur> <Pine dot LNX dot 4 dot 64 dot 1410291623450 dot 21975 at digraph dot polyomino dot org dot uk> <20141106101820 dot 22ee3429 at lemur> <alpine dot DEB dot 2 dot 10 dot 1411062339490 dot 17254 at digraph dot polyomino dot org dot uk>
For completeness, this version adds the missing warning if the
'const' is lost in a conditional expression with a void* on the
other branch. The only code change relative to the previous
version is in c/c-typeck.c in build_conditional_expr (otherwise
I added the warnings to the testsuite and fixed some typos and
trailing whitespace errors).
I would rather have the 'const' propagate to the result
of the conditional expression as with regular pointers to
const, but I do not see an easy way to make the warnings
(or errors) which could result from this be dependent on
-Wdiscarded-array-qualifiers.
Joseph Myers <joseph@codesourcery.com>:
> On Thu, 6 Nov 2014, Martin Uecker wrote:
> > This patch implements a new proposed behaviour for
> > pointers to arrays with qualifiers in C.
> >
> > I found some time to work on this again, so here is another
> > revision. Main changes to the previous version of the patch:
> >
> > - add more test cases for cast from/to (const) void*
> > - correctly uses pedwarn/warning_at
>
> Thanks. I'll review this in more detail later, but I suspect it's quite
> close to being ready to go in once the paperwork has been processed.
Thank you. I got the form and have sent it back, but did not get
a reply yet.
Martin
2014-11-10 Martin Uecker <uecker@eecs.berkeley.edu>
* doc/invoke.texi: Document -Wdiscarded-array-qualifiers
* doc/extend.texi: Document new behavior for pointers to arrays with qualifies
c/
* c-typeck.c: New behavious for pointers to arrays with qualifiers
(common-pointer-type): For pointers to arrays take qualifiers from element type.
(build_conditional_expr): Add warnings for lost qualifiers.
(comp-target-types): Allow pointers to arrays with different qualifiers.
(convert-for-assignment): Adapt warnings for discarded qualifiers. Add
WARNING_FOR_QUALIFIERS macro and rename WARN_FOR_QUALIFIERS
to PEDWARN_FOR_QUALIFIERS.
c-family/
* c.opt (Wdiscarded-array-qualifiers): New option
testsuite/
* gcc.dg/Wwrite-strings-1.c: Change dg-warning
* gcc.dg/array-quals-1.c: Use -Wno-discarded-array-qualifiers
* gcc.dg/array-quals-2.c: Change dg-options, dg-warning
* gcc.dg/pointer-array-atomic.c: New test
* gcc.dg/pointer-array-quals-1.c: New test
* gcc.dg/pointer-array-quals-2.c: New test (-pedantic-errors)
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c (Revision 217273)
+++ gcc/c/c-typeck.c (Arbeitskopie)
@@ -673,12 +673,13 @@ common_pointer_type (tree t1, tree t2)
mv2 = TYPE_MAIN_VARIANT (pointed_to_2);
target = composite_type (mv1, mv2);
+ /* Strip array types to get correct qualifier for pointers to arrays */
+ quals1 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_1));
+ quals2 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_2));
+
/* For function types do not merge const qualifiers, but drop them
if used inconsistently. The middle-end uses these to mark const
and noreturn functions. */
- quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1);
- quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2);
-
if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE)
target_quals = (quals1 & quals2);
else
@@ -1224,6 +1225,7 @@ static int
comp_target_types (location_t location, tree ttl, tree ttr)
{
int val;
+ int val_ped;
tree mvl = TREE_TYPE (ttl);
tree mvr = TREE_TYPE (ttr);
addr_space_t asl = TYPE_ADDR_SPACE (mvl);
@@ -1235,19 +1237,32 @@ comp_target_types (location_t location, tree ttl,
if (!addr_space_superset (asl, asr, &as_common))
return 0;
- /* Do not lose qualifiers on element types of array types that are
- pointer targets by taking their TYPE_MAIN_VARIANT. */
- if (TREE_CODE (mvl) != ARRAY_TYPE)
- mvl = (TYPE_ATOMIC (mvl)
- ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC)
- : TYPE_MAIN_VARIANT (mvl));
- if (TREE_CODE (mvr) != ARRAY_TYPE)
- mvr = (TYPE_ATOMIC (mvr)
- ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
- : TYPE_MAIN_VARIANT (mvr));
+ /* For pedantic record result of comptypes on arrays before losing
+ qualifiers on the element type below. */
+ val_ped = 1;
+
+ if (TREE_CODE (mvl) == ARRAY_TYPE
+ && TREE_CODE (mvr) == ARRAY_TYPE)
+ val_ped = comptypes (mvl, mvr);
+
+ /* Qualifiers on element types of array types that are
+ pointer targets are lost by taking their TYPE_MAIN_VARIANT. */
+
+ mvl = (TYPE_ATOMIC (strip_array_types (mvl))
+ ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (mvl));
+
+ mvr = (TYPE_ATOMIC (strip_array_types (mvr))
+ ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (mvr));
+
enum_and_int_p = false;
val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p);
+ if (val == 1 && val_ped != 1)
+ pedwarn (location, OPT_Wpedantic, "pointers to arrays with different qualifiers "
+ "are incompatible in ISO C");
+
if (val == 2)
pedwarn (location, OPT_Wpedantic, "types are not quite compatible");
@@ -4603,6 +4618,14 @@ build_conditional_expr (location_t colon_loc, tree
else if (VOID_TYPE_P (TREE_TYPE (type1))
&& !TYPE_ATOMIC (TREE_TYPE (type1)))
{
+ if (OPT_Wdiscarded_array_qualifiers
+ && (TREE_CODE (TREE_TYPE (type2)) == ARRAY_TYPE)
+ && (TYPE_QUALS (strip_array_types (TREE_TYPE (type2)))
+ & ~TYPE_QUALS (TREE_TYPE (type1))))
+ warning_at(colon_loc, OPT_Wdiscarded_array_qualifiers,
+ "pointer to array loses qualifier "
+ "in conditional expression");
+
if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
pedwarn (colon_loc, OPT_Wpedantic,
"ISO C forbids conditional expr between "
@@ -4613,6 +4636,14 @@ build_conditional_expr (location_t colon_loc, tree
else if (VOID_TYPE_P (TREE_TYPE (type2))
&& !TYPE_ATOMIC (TREE_TYPE (type2)))
{
+ if (OPT_Wdiscarded_array_qualifiers
+ && (TREE_CODE (TREE_TYPE (type1)) == ARRAY_TYPE)
+ && (TYPE_QUALS (strip_array_types (TREE_TYPE (type1)))
+ & ~TYPE_QUALS (TREE_TYPE (type2))))
+ warning_at(colon_loc, OPT_Wdiscarded_array_qualifiers,
+ "pointer to array loses qualifier "
+ "in conditional expression");
+
if (TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
pedwarn (colon_loc, OPT_Wpedantic,
"ISO C forbids conditional expr between "
@@ -5655,7 +5686,7 @@ convert_for_assignment (location_t location, locat
/* This macro is used to emit diagnostics to ensure that all format
strings are complete sentences, visible to gettext and checked at
compile time. */
-#define WARN_FOR_ASSIGNMENT(LOCATION, PLOC, OPT, AR, AS, IN, RE) \
+#define PEDWARN_FOR_ASSIGNMENT(LOCATION, PLOC, OPT, AR, AS, IN, RE) \
do { \
switch (errtype) \
{ \
@@ -5682,10 +5713,9 @@ convert_for_assignment (location_t location, locat
/* This macro is used to emit diagnostics to ensure that all format
strings are complete sentences, visible to gettext and checked at
- compile time. It is the same as WARN_FOR_ASSIGNMENT but with an
+ compile time. It is the same as PEDWARN_FOR_ASSIGNMENT but with an
extra parameter to enumerate qualifiers. */
-
-#define WARN_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \
+#define PEDWARN_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \
do { \
switch (errtype) \
{ \
@@ -5710,6 +5740,35 @@ convert_for_assignment (location_t location, locat
} \
} while (0)
+ /* This macro is used to emit diagnostics to ensure that all format
+ strings are complete sentences, visible to gettext and checked at
+ compile time. It is the same as PEDWARN_FOR_QUALIFIERS but uses
+ warning_at instead of pedwarn. */
+#define WARNING_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \
+ do { \
+ switch (errtype) \
+ { \
+ case ic_argpass: \
+ if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS)) \
+ inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \
+ ? DECL_SOURCE_LOCATION (fundecl) : PLOC, \
+ "expected %qT but argument is of type %qT", \
+ type, rhstype); \
+ break; \
+ case ic_assign: \
+ warning_at (LOCATION, OPT, AS, QUALS); \
+ break; \
+ case ic_init: \
+ warning_at (LOCATION, OPT, IN, QUALS); \
+ break; \
+ case ic_return: \
+ warning_at (LOCATION, OPT, RE, QUALS); \
+ break; \
+ default: \
+ gcc_unreachable (); \
+ } \
+ } while (0)
+
if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
rhs = TREE_OPERAND (rhs, 0);
@@ -5752,15 +5811,15 @@ convert_for_assignment (location_t location, locat
&& TREE_CODE (type) == ENUMERAL_TYPE
&& TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type))
{
- WARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wc___compat,
- G_("enum conversion when passing argument "
- "%d of %qE is invalid in C++"),
- G_("enum conversion in assignment is "
- "invalid in C++"),
- G_("enum conversion in initialization is "
- "invalid in C++"),
- G_("enum conversion in return is "
- "invalid in C++"));
+ PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wc___compat,
+ G_("enum conversion when passing argument "
+ "%d of %qE is invalid in C++"),
+ G_("enum conversion in assignment is "
+ "invalid in C++"),
+ G_("enum conversion in initialization is "
+ "invalid in C++"),
+ G_("enum conversion in return is "
+ "invalid in C++"));
}
}
@@ -5915,34 +5974,34 @@ convert_for_assignment (location_t location, locat
vice-versa. */
if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
& ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
- WARN_FOR_QUALIFIERS (location, expr_loc,
- OPT_Wdiscarded_qualifiers,
- G_("passing argument %d of %qE "
- "makes %q#v qualified function "
- "pointer from unqualified"),
- G_("assignment makes %q#v qualified "
- "function pointer from "
- "unqualified"),
- G_("initialization makes %q#v qualified "
- "function pointer from "
- "unqualified"),
- G_("return makes %q#v qualified function "
- "pointer from unqualified"),
- TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
+ PEDWARN_FOR_QUALIFIERS (location, expr_loc,
+ OPT_Wdiscarded_qualifiers,
+ G_("passing argument %d of %qE "
+ "makes %q#v qualified function "
+ "pointer from unqualified"),
+ G_("assignment makes %q#v qualified "
+ "function pointer from "
+ "unqualified"),
+ G_("initialization makes %q#v qualified "
+ "function pointer from "
+ "unqualified"),
+ G_("return makes %q#v qualified function "
+ "pointer from unqualified"),
+ TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
}
else if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
& ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
- WARN_FOR_QUALIFIERS (location, expr_loc,
- OPT_Wdiscarded_qualifiers,
- G_("passing argument %d of %qE discards "
- "%qv qualifier from pointer target type"),
- G_("assignment discards %qv qualifier "
- "from pointer target type"),
- G_("initialization discards %qv qualifier "
- "from pointer target type"),
- G_("return discards %qv qualifier from "
- "pointer target type"),
- TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
+ PEDWARN_FOR_QUALIFIERS (location, expr_loc,
+ OPT_Wdiscarded_qualifiers,
+ G_("passing argument %d of %qE discards "
+ "%qv qualifier from pointer target type"),
+ G_("assignment discards %qv qualifier "
+ "from pointer target type"),
+ G_("initialization discards %qv qualifier "
+ "from pointer target type"),
+ G_("return discards %qv qualifier from "
+ "pointer target type"),
+ TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
memb = marginal_memb;
}
@@ -6090,42 +6149,70 @@ convert_for_assignment (location_t location, locat
== c_common_signed_type (mvr))
&& TYPE_ATOMIC (mvl) == TYPE_ATOMIC (mvr)))
{
- if (pedantic
+ /* Warn about loss of qualifers from pointers to arrays with
+ qualifiers on the element type. */
+ if (OPT_Wdiscarded_array_qualifiers
+ && (TREE_CODE (ttr) == ARRAY_TYPE))
+ {
+ ttr = strip_array_types (ttr);
+ ttl = strip_array_types (ttl);
+
+ if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
+ & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl))
+ WARNING_FOR_QUALIFIERS (location, expr_loc,
+ OPT_Wdiscarded_array_qualifiers,
+ G_("passing argument %d of %qE discards "
+ "%qv qualifier from pointer target type"),
+ G_("assignment discards %qv qualifier "
+ "from pointer target type"),
+ G_("initialization discards %qv qualifier "
+ "from pointer target type"),
+ G_("return discards %qv qualifier from "
+ "pointer target type"),
+ TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
+ }
+ else if (pedantic
&& ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
||
(VOID_TYPE_P (ttr)
&& !null_pointer_constant
&& TREE_CODE (ttl) == FUNCTION_TYPE)))
- WARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wpedantic,
- G_("ISO C forbids passing argument %d of "
- "%qE between function pointer "
- "and %<void *%>"),
- G_("ISO C forbids assignment between "
- "function pointer and %<void *%>"),
- G_("ISO C forbids initialization between "
- "function pointer and %<void *%>"),
- G_("ISO C forbids return between function "
- "pointer and %<void *%>"));
+ PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wpedantic,
+ G_("ISO C forbids passing argument %d of "
+ "%qE between function pointer "
+ "and %<void *%>"),
+ G_("ISO C forbids assignment between "
+ "function pointer and %<void *%>"),
+ G_("ISO C forbids initialization between "
+ "function pointer and %<void *%>"),
+ G_("ISO C forbids return between function "
+ "pointer and %<void *%>"));
/* Const and volatile mean something different for function types,
so the usual warnings are not appropriate. */
else if (TREE_CODE (ttr) != FUNCTION_TYPE
&& TREE_CODE (ttl) != FUNCTION_TYPE)
{
+ /* Don't warn about loss of qualifier for conversions from
+ qualified void* to pointers to arrays with corresponding
+ qualifier on the the element type. */
+ if (!pedantic)
+ ttl = strip_array_types (ttl);
+
/* Assignments between atomic and non-atomic objects are OK. */
- if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
+ if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
& ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl))
{
- WARN_FOR_QUALIFIERS (location, expr_loc,
- OPT_Wdiscarded_qualifiers,
- G_("passing argument %d of %qE discards "
- "%qv qualifier from pointer target type"),
- G_("assignment discards %qv qualifier "
- "from pointer target type"),
- G_("initialization discards %qv qualifier "
- "from pointer target type"),
- G_("return discards %qv qualifier from "
- "pointer target type"),
- TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
+ PEDWARN_FOR_QUALIFIERS (location, expr_loc,
+ OPT_Wdiscarded_qualifiers,
+ G_("passing argument %d of %qE discards "
+ "%qv qualifier from pointer target type"),
+ G_("assignment discards %qv qualifier "
+ "from pointer target type"),
+ G_("initialization discards %qv qualifier "
+ "from pointer target type"),
+ G_("return discards %qv qualifier from "
+ "pointer target type"),
+ TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
}
/* If this is not a case of ignoring a mismatch in signedness,
no warning. */
@@ -6134,15 +6221,15 @@ convert_for_assignment (location_t location, locat
;
/* If there is a mismatch, do warn. */
else if (warn_pointer_sign)
- WARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wpointer_sign,
- G_("pointer targets in passing argument "
- "%d of %qE differ in signedness"),
- G_("pointer targets in assignment "
- "differ in signedness"),
- G_("pointer targets in initialization "
- "differ in signedness"),
- G_("pointer targets in return differ "
- "in signedness"));
+ PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wpointer_sign,
+ G_("pointer targets in passing argument "
+ "%d of %qE differ in signedness"),
+ G_("pointer targets in assignment "
+ "differ in signedness"),
+ G_("pointer targets in initialization "
+ "differ in signedness"),
+ G_("pointer targets in return differ "
+ "in signedness"));
}
else if (TREE_CODE (ttl) == FUNCTION_TYPE
&& TREE_CODE (ttr) == FUNCTION_TYPE)
@@ -6153,31 +6240,31 @@ convert_for_assignment (location_t location, locat
where an ordinary one is wanted, but not vice-versa. */
if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
& ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
- WARN_FOR_QUALIFIERS (location, expr_loc,
- OPT_Wdiscarded_qualifiers,
- G_("passing argument %d of %qE makes "
- "%q#v qualified function pointer "
- "from unqualified"),
- G_("assignment makes %q#v qualified function "
- "pointer from unqualified"),
- G_("initialization makes %q#v qualified "
- "function pointer from unqualified"),
- G_("return makes %q#v qualified function "
- "pointer from unqualified"),
- TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
+ PEDWARN_FOR_QUALIFIERS (location, expr_loc,
+ OPT_Wdiscarded_qualifiers,
+ G_("passing argument %d of %qE makes "
+ "%q#v qualified function pointer "
+ "from unqualified"),
+ G_("assignment makes %q#v qualified function "
+ "pointer from unqualified"),
+ G_("initialization makes %q#v qualified "
+ "function pointer from unqualified"),
+ G_("return makes %q#v qualified function "
+ "pointer from unqualified"),
+ TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
}
}
else
/* Avoid warning about the volatile ObjC EH puts on decls. */
if (!objc_ok)
- WARN_FOR_ASSIGNMENT (location, expr_loc,
- OPT_Wincompatible_pointer_types,
- G_("passing argument %d of %qE from "
- "incompatible pointer type"),
- G_("assignment from incompatible pointer type"),
- G_("initialization from incompatible "
- "pointer type"),
- G_("return from incompatible pointer type"));
+ PEDWARN_FOR_ASSIGNMENT (location, expr_loc,
+ OPT_Wincompatible_pointer_types,
+ G_("passing argument %d of %qE from "
+ "incompatible pointer type"),
+ G_("assignment from incompatible pointer type"),
+ G_("initialization from incompatible "
+ "pointer type"),
+ G_("return from incompatible pointer type"));
return convert (type, rhs);
}
@@ -6194,31 +6281,31 @@ convert_for_assignment (location_t location, locat
or one that results from arithmetic, even including
a cast to integer type. */
if (!null_pointer_constant)
- WARN_FOR_ASSIGNMENT (location, expr_loc,
- OPT_Wint_conversion,
- G_("passing argument %d of %qE makes "
- "pointer from integer without a cast"),
- G_("assignment makes pointer from integer "
- "without a cast"),
- G_("initialization makes pointer from "
- "integer without a cast"),
- G_("return makes pointer from integer "
- "without a cast"));
+ PEDWARN_FOR_ASSIGNMENT (location, expr_loc,
+ OPT_Wint_conversion,
+ G_("passing argument %d of %qE makes "
+ "pointer from integer without a cast"),
+ G_("assignment makes pointer from integer "
+ "without a cast"),
+ G_("initialization makes pointer from "
+ "integer without a cast"),
+ G_("return makes pointer from integer "
+ "without a cast"));
return convert (type, rhs);
}
else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
{
- WARN_FOR_ASSIGNMENT (location, expr_loc,
- OPT_Wint_conversion,
- G_("passing argument %d of %qE makes integer "
- "from pointer without a cast"),
- G_("assignment makes integer from pointer "
- "without a cast"),
- G_("initialization makes integer from pointer "
- "without a cast"),
- G_("return makes integer from pointer "
- "without a cast"));
+ PEDWARN_FOR_ASSIGNMENT (location, expr_loc,
+ OPT_Wint_conversion,
+ G_("passing argument %d of %qE makes integer "
+ "from pointer without a cast"),
+ G_("assignment makes integer from pointer "
+ "without a cast"),
+ G_("initialization makes integer from pointer "
+ "without a cast"),
+ G_("return makes integer from pointer "
+ "without a cast"));
return convert (type, rhs);
}
else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE)
Index: gcc/c-family/c.opt
===================================================================
--- gcc/c-family/c.opt (Revision 217273)
+++ gcc/c-family/c.opt (Arbeitskopie)
@@ -387,6 +387,10 @@ Wdesignated-init
C ObjC Var(warn_designated_init) Init(1) Warning
Warn about positional initialization of structs requiring designated initializers
+Wdiscarded-array-qualifiers
+C ObjC Var(warn_discarded_array_qualifiers) Init(1) Warning
+Warn if qualifiers on arrays which are pointer targets are discarded
+
Wdiscarded-qualifiers
C ObjC Var(warn_discarded_qualifiers) Init(1) Warning
Warn if type qualifiers on pointers are discarded
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi (Revision 217273)
+++ gcc/doc/extend.texi (Arbeitskopie)
@@ -46,6 +46,7 @@ extensions, accepted by GCC in C90 mode and in C++
* Escaped Newlines:: Slightly looser rules for escaped newlines.
* Subscripting:: Any array can be subscripted, even if not an lvalue.
* Pointer Arith:: Arithmetic on @code{void}-pointers and function pointers.
+* Pointers to Arrays:: Pointers to arrays with qualifiers work as expected.
* Initializers:: Non-constant initializers.
* Compound Literals:: Compound literals give structures, unions
or arrays as values.
@@ -1782,6 +1783,27 @@ and on function types, and returns 1.
The option @option{-Wpointer-arith} requests a warning if these extensions
are used.
+@node Pointers to Arrays
+@section Pointers to arrays with qualifiers work as expected
+@cindex pointers to arrays
+@cindex const qualifier
+
+In GNU C, pointers to arrays with qualifiers work similar to pointers
+to other qualified types. For example, a value of type @code{int (*)[5]}
+can be used to initialize a variable of type @code{const int (*)[5]}.
+These types are incompatible in ISO C because the @code{const} qualifier
+is formally attached to the element type of the array and not the
+array itself.
+
+@smallexample
+extern void
+transpose (int N, int M, double out[M][N], const double in[N][M]);
+double x[3][2];
+double y[2][3];
+@r{@dots{}}
+transpose(3, 2, y, x);
+@end smallexample
+
@node Initializers
@section Non-Constant Initializers
@cindex initializers, non-constant
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi (Revision 217273)
+++ gcc/doc/invoke.texi (Arbeitskopie)
@@ -247,7 +247,8 @@ Objective-C and Objective-C++ Dialects}.
-Wchar-subscripts -Wclobbered -Wcomment -Wconditionally-supported @gol
-Wconversion -Wcoverage-mismatch -Wdate-time -Wdelete-incomplete -Wno-cpp @gol
-Wno-deprecated -Wno-deprecated-declarations -Wno-designated-init @gol
--Wdisabled-optimization -Wno-discarded-qualifiers @gol
+-Wdisabled-optimization @gol
+-Wno-discarded-qualifiers -Wno-discarded-array-qualifiers @gol
-Wno-div-by-zero -Wdouble-promotion -Wempty-body -Wenum-compare @gol
-Wno-endif-labels -Werror -Werror=* @gol
-Wfatal-errors -Wfloat-equal -Wformat -Wformat=2 @gol
@@ -4263,9 +4264,18 @@ This warning is enabled by @option{-Wall}.
@opindex Wdiscarded-qualifiers
Do not warn if type qualifiers on pointers are being discarded.
Typically, the compiler will warn if a @code{const char *} variable is
-passed to a function that takes @code{char *} parameter. This option
+passed to a function that takes a @code{char *} parameter. This option
can be used to suppress such a warning.
+@item -Wno-discarded-array-qualifiers @r{(C and Objective-C only)}
+@opindex Wno-discarded-array-qualifiers
+@opindex Wdiscarded-array-qualifiers
+Do not warn if type qualifiers on arrays which are pointer targets
+are being discarded. Typically, the compiler will warn if a
+@code{const int (*)[]} variable is passed to a function that
+takes a @code{int (*)[]} parameter. This option can be used to
+suppress such a warning.
+
@item -Wno-incompatible-pointer-types @r{(C and Objective-C only)}
@opindex Wno-incompatible-pointer-types
@opindex Wincompatible-pointer-types
Index: gcc/testsuite/gcc.dg/Wwrite-strings-1.c
===================================================================
--- gcc/testsuite/gcc.dg/Wwrite-strings-1.c (Revision 217273)
+++ gcc/testsuite/gcc.dg/Wwrite-strings-1.c (Arbeitskopie)
@@ -5,4 +5,4 @@
/* { dg-do compile } */
/* { dg-options "-Wwrite-strings" } */
typedef char T[1];
-T *p = &""; /* { dg-warning "initialization from incompatible pointer type" } */
+T *p = &""; /* { dg-warning "initialization discards 'const' qualifier from pointer target type" } */
Index: gcc/testsuite/gcc.dg/array-quals-1.c
===================================================================
--- gcc/testsuite/gcc.dg/array-quals-1.c (Revision 217273)
+++ gcc/testsuite/gcc.dg/array-quals-1.c (Arbeitskopie)
@@ -3,6 +3,7 @@
all should end up in a read-only section. PR c/12165. */
/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
/* { dg-do compile } */
+/* { dg-options "-Wno-discarded-array-qualifiers" } */
/* The MMIX port always switches to the .data section at the end of a file. */
/* { dg-final { scan-assembler-not "\\.data(?!\\.rel\\.ro)" { xfail powerpc*-*-aix* mmix-*-* x86_64-*-mingw* } } } */
static const int a[2] = { 1, 2 };
Index: gcc/testsuite/gcc.dg/array-quals-2.c
===================================================================
--- gcc/testsuite/gcc.dg/array-quals-2.c (Revision 217273)
+++ gcc/testsuite/gcc.dg/array-quals-2.c (Arbeitskopie)
@@ -3,7 +3,7 @@
lost in forming composite types. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-pedantic -Wno-discarded-array-qualifiers" } */
typedef const char T[1];
typedef const char T2[1];
typedef volatile char U[1];
@@ -10,5 +10,5 @@ typedef volatile char U[1];
T *p;
T2 *p2;
U *q;
-void *f(void) { return 1 ? p : q; } /* { dg-warning "pointer type mismatch in conditional expression" } */
+void *f(void) { return 1 ? p : q; } /* { dg-warning "pointers to arrays with different qualifiers" } */
T *g(void) { return 1 ? p : p2; }
Index: gcc/testsuite/gcc.dg/pointer-array-atomic.c
===================================================================
--- gcc/testsuite/gcc.dg/pointer-array-atomic.c (Revision 0)
+++ gcc/testsuite/gcc.dg/pointer-array-atomic.c (Arbeitskopie)
@@ -0,0 +1,59 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c11" } */
+/* Origin: Martin Uecker <uecker@eecs.berkeley.edu> */
+void tvoid(void* x);
+void transpose0(double* out, _Atomic double* in) { }
+void transpose1(double out[2][2], _Atomic double in[2][2]) { }
+void transpose2(double out[2][2][2], _Atomic double in[2][2][2]) { }
+// return
+int (*x2(_Atomic int x[3][3]))[3] { return x; } /* { dg-warning "return from incompatible pointer type" } */
+_Atomic int (*x3(int x[3][3]))[3] { return x; } /* { dg-warning "return from incompatible pointer type" } */
+void test(void)
+{
+ double x0[2];
+ double y0[2];
+ _Atomic double z0[4];
+ double x1[2][2];
+ double y1[2][2];
+ double o1[2][3];
+ _Atomic double z1[2][2];
+ double x2[2][2][2];
+ double y2[2][2][2];
+ double o2[2][2][3];
+ _Atomic double z2[2][2][2];
+ tvoid(z0);
+ tvoid(z1);
+ tvoid(z2);
+ // passing as arguments
+ transpose0(y0, x0); /* { dg-warning "passing argument 2 of 'transpose0' from incompatible pointer type" } */
+ transpose1(y1, o1); /* { dg-warning "passing argument 2 of 'transpose1' from incompatible pointer type" } */
+ transpose1(y1, x1); /* { dg-warning "passing argument 2 of 'transpose1' from incompatible pointer type" } */
+ transpose2(y2, o2); /* { dg-warning "passing argument 2 of 'transpose2' from incompatible pointer type" } */
+ transpose2(y2, x2); /* { dg-warning "passing argument 2 of 'transpose2' from incompatible pointer type" } */
+ // initialization
+ _Atomic double (*x0p) = x0; /* { dg-warning "initialization from incompatible pointer type" } */
+ _Atomic double (*x1p)[2] = x1; /* { dg-warning "initialization from incompatible pointer type" } */
+ _Atomic double (*x2p)[2][2] = x2; /* { dg-warning "initialization from incompatible pointer type" } */
+ // assignment
+ x0p = x0; /* { dg-warning "assignment from incompatible pointer type" } */
+ x1p = x1; /* { dg-warning "assignment from incompatible pointer type" } */
+ x2p = x2; /* { dg-warning "assignment from incompatible pointer type" } */
+ // subtraction
+ &(x0[1]) - &(z0[0]); /* { dg-error "invalid operands to binary" } */
+ &(x1[1]) - &(z1[0]); /* { dg-error "invalid operands to binary" } */
+ &(x2[1]) - &(z2[0]); /* { dg-error "invalid operands to binary" } */
+ // comparison
+ x0 == z0; /* { dg-warning "comparison of distinct pointer types lacks a cast" } */
+ x1 == z1; /* { dg-warning "comparison of distinct pointer types lacks a cast" } */
+ x2 == z2; /* { dg-warning "comparison of distinct pointer types lacks a cast" } */
+ x0 > z0; /* { dg-warning "comparison of distinct pointer types lacks a cast" } */
+ x1 > z1; /* { dg-warning "comparison of distinct pointer types lacks a cast" } */
+ x2 > z2; /* { dg-warning "comparison of distinct pointer types lacks a cast" } */
+ x0 < z0; /* { dg-warning "comparison of distinct pointer types lacks a cast" } */
+ x1 < z1; /* { dg-warning "comparison of distinct pointer types lacks a cast" } */
+ x2 < z2; /* { dg-warning "comparison of distinct pointer types lacks a cast" } */
+ // conditional expressions
+ (void)(1 ? x0 : z0); /* { dg-warning "pointer type mismatch in conditional expression" } */
+ (void)(1 ? x1 : z1); /* { dg-warning "pointer type mismatch in conditional expression" } */
+ (void)(1 ? x2 : z2); /* { dg-warning "pointer type mismatch in conditional expression" } */
+}
Index: gcc/testsuite/gcc.dg/pointer-array-quals-1.c
===================================================================
--- gcc/testsuite/gcc.dg/pointer-array-quals-1.c (Revision 0)
+++ gcc/testsuite/gcc.dg/pointer-array-quals-1.c (Arbeitskopie)
@@ -0,0 +1,105 @@
+/* { dg-do compile } */
+/* Origin: Martin Uecker <uecker@eecs.berkeley.edu> */
+/* { dg-options "-Wdiscarded-array-qualifiers" } */
+void tvoid(void* x);
+void transpose0(double* out, const double* in) { }
+void transpose1(double out[2][2], const double in[2][2]) { }
+void transpose2(double out[2][2][2], const double in[2][2][2]) { }
+// return
+int (*y2(const int x[3][3]))[3] { return x; } /* { dg-warning "return discards 'const' qualifier from pointer target type" } */
+const int (*y3(int x[3][3]))[3] { return x; }
+void test(void)
+{
+ double x0[2];
+ double y0[2];
+ const double z0[4];
+ double x1[2][2];
+ double y1[2][2];
+ double o1[2][3];
+ const double z1[2][2];
+ double x2[2][2][2];
+ double y2[2][2][2];
+ double o2[2][2][3];
+ const double z2[2][2][2];
+ // void pointers
+ tvoid(x0);
+ tvoid(x1);
+ tvoid(x2);
+ tvoid(z0); /* { dg-warning "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+ tvoid(z1); /* { dg-warning "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+ tvoid(z2); /* { dg-warning "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+ void* p;
+ const void* pc;
+ p = x0;
+ p = x1;
+ p = x2;
+ p = z0; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ p = z1; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ p = z2; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ pc = x0;
+ pc = x1;
+ pc = x2;
+ pc = z0;
+ pc = z1;
+ pc = z2;
+ transpose0(pc, p); /* { dg-warning "passing argument 1 of 'transpose0' discards 'const' qualifier from pointer target type" } */
+ transpose1(pc, p); /* { dg-warning "passing argument 1 of 'transpose1' discards 'const' qualifier from pointer target type" } */
+ transpose2(pc, p); /* { dg-warning "passing argument 1 of 'transpose2' discards 'const' qualifier from pointer target type" } */
+ transpose0(p, pc);
+ transpose1(p, pc);
+ transpose2(p, pc);
+ // passing as arguments
+ transpose0(y0, x0);
+ transpose1(y1, x1);
+ transpose2(y2, x2);
+ // initialization
+ const double (*u0p) = x0;
+ const double (*u1p)[2] = x1;
+ const double (*u2p)[2][2] = x2;
+ double (*v0p) = z0; /* { dg-warning "initialization discards 'const' qualifier from pointer target type" } */
+ double (*v1p)[2] = z1; /* { dg-warning "initialization discards 'const' qualifier from pointer target type" } */
+ double (*v2p)[2][2] = z2; /* { dg-warning "initialization discards 'const' qualifier from pointer target type" } */
+ // subtraction
+ &(x0[1]) - &(z0[0]);
+ &(x1[1]) - &(z1[0]);
+ &(x2[1]) - &(z2[0]);
+ // comparison
+ x0 == z0;
+ x1 == z1;
+ x2 == z2;
+ x0 < z0;
+ x1 < z1;
+ x2 < z2;
+ x0 > z0;
+ x1 > z1;
+ x2 > z2;
+ // assignment
+ u0p = x0;
+ u1p = x1;
+ u2p = x2;
+ v0p = z0; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ v1p = z1; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ v2p = z2; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ // conditional expressions
+ (void)(1 ? x0 : z0);
+ (void)(1 ? x1 : z1);
+ (void)(1 ? x2 : z2);
+ (void)(1 ? x0 : x1); /* { dg-warning "pointer type mismatch in conditional expression" } */
+ (void)(1 ? x1 : x2); /* { dg-warning "pointer type mismatch in conditional expression" } */
+ (void)(1 ? x2 : x0); /* { dg-warning "pointer type mismatch in conditional expression" } */
+ v0p = (1 ? z0 : v0p); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ v1p = (1 ? z1 : v1p); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ v2p = (1 ? z2 : v2p); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ v0p = (1 ? x0 : u0p); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ v1p = (1 ? x1 : u1p); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ v2p = (1 ? x2 : u2p); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ (1 ? x0 : z0)[0] = 1; /* { dg-error "assignment of read-only location" } */
+ (1 ? x1 : z1)[0][0] = 1; /* { dg-error "assignment of read-only location" } */
+ (1 ? x2 : z2)[0][0][0] = 1; /* { dg-error "assignment of read-only location" } */
+ v0p = (1 ? p : z0); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ v1p = (1 ? p : z1); /* { dg-warning "pointer to array loses qualifier in conditional expression" } */
+ v2p = (1 ? p : z2); /* { dg-warning "pointer to array loses qualifier in conditional expression" } */
+ v0p = (1 ? pc : x0); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ v1p = (1 ? pc : x1); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ v2p = (1 ? pc : x2); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+}
Index: gcc/testsuite/gcc.dg/pointer-array-quals-2.c
===================================================================
--- gcc/testsuite/gcc.dg/pointer-array-quals-2.c (Revision 0)
+++ gcc/testsuite/gcc.dg/pointer-array-quals-2.c (Arbeitskopie)
@@ -0,0 +1,101 @@
+/* { dg-do compile } */
+/* { dg-options "-Wdiscarded-array-qualifiers -pedantic-errors" } */
+/* Origin: Martin Uecker <uecker@eecs.berkeley.edu> */
+void tvoid(void* x);
+void transpose0(double* out, const double* in) { }
+void transpose1(double out[2][2], const double in[2][2]) { }
+void transpose2(double out[2][2][2], const double in[2][2][2]) { }
+// return
+int (*x2(const int x[3][3]))[3] { return x; } /* { dg-error "pointers to arrays with different qualifiers|return discards" } */
+const int (*x3(int x[3][3]))[3] { return x; } /* { dg-error "pointers to arrays with different qualifiers" } */
+void test(void)
+{
+ double x0[2];
+ double y0[2];
+ const double z0[4];
+ double x1[2][2];
+ double y1[2][2];
+ double o1[2][3];
+ const double z1[2][2];
+ double x2[2][2][2];
+ double y2[2][2][2];
+ double o2[2][2][3];
+ const double z2[2][2][2];
+ // void pointers
+ tvoid(z0); /* { dg-error "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+ tvoid(z1); /* { dg-warning "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+ tvoid(z2); /* { dg-warning "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+ void* p;
+ const void* pc;
+ p = x0;
+ p = x1;
+ p = x2;
+ p = z0; /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+ p = z1; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ p = z2; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+ pc = x0;
+ pc = x1;
+ pc = x2;
+ pc = z0;
+ pc = z1;
+ pc = z2;
+ transpose0(pc, p); /* { dg-error "passing argument 1 of 'transpose0' discards 'const' qualifier from pointer target type" } */
+ transpose1(pc, p); /* { dg-error "passing argument 1 of 'transpose1' discards 'const' qualifier from pointer target type" } */
+ transpose2(pc, p); /* { dg-error "passing argument 1 of 'transpose2' discards 'const' qualifier from pointer target type" } */
+ transpose0(p, pc);
+ transpose1(p, pc); /* { dg-error "passing argument 2 of 'transpose1' discards 'const' qualifier from pointer target type" } */
+ transpose2(p, pc); /* { dg-error "passing argument 2 of 'transpose2' discards 'const' qualifier from pointer target type" } */
+ // passing as arguments
+ transpose0(y0, x0);
+ transpose1(y1, o1); /* { dg-error "passing argument 2 of 'transpose1' from incompatible pointer type" } */
+ transpose1(y1, x1); /* { dg-error "pointers to arrays with different qualifiers" } */
+ transpose2(y2, o2); /* { dg-error "passing argument 2 of 'transpose2' from incompatible pointer type" } */
+ transpose2(y2, x2); /* { dg-error "pointers to arrays with different qualifiers" } */
+ // initialization
+ const double (*x0p) = x0;
+ const double (*x1p)[2] = x1; /* { dg-error "pointers to arrays with different qualifiers" } */
+ const double (*x2p)[2][2] = x2; /* { dg-error "pointers to arrays with different qualifiers" } */
+ double (*v0p) = z0; /* { dg-error "initialization discards 'const' qualifier from pointer target type" } */
+ double (*v1p)[2] = z1; /* { dg-error "pointers to arrays with different qualifiers|initialization discards" } */
+ double (*v2p)[2][2] = z2; /* { dg-error "pointers to arrays with different qualifiers|initialization discards" } */
+ // assignment
+ x0p = x0;
+ x1p = x1; /* { dg-error "pointers to arrays with different qualifiers" } */
+ x2p = x2; /* { dg-error "pointers to arrays with different qualifiers" } */
+ // subtraction
+ &(x0[1]) - &(z0[0]);
+ &(x1[1]) - &(z1[0]); /* { dg-error "pointers to arrays with different qualifiers" } */
+ &(x2[1]) - &(z2[0]); /* { dg-error "pointers to arrays with different qualifiers" } */
+ // comparison
+ x0 == z0;
+ x1 == z1; /* { dg-error "pointers to arrays with different qualifiers" } */
+ x2 == z2; /* { dg-error "pointers to arrays with different qualifiers" } */
+ x0 < z0;
+ x1 < z1; /* { dg-error "pointers to arrays with different qualifiers" } */
+ x2 < z2; /* { dg-error "pointers to arrays with different qualifiers" } */
+ x0 > z0;
+ x1 > z1; /* { dg-error "pointers to arrays with different qualifiers" } */
+ x2 > z2; /* { dg-error "pointers to arrays with different qualifiers" } */
+ // conditional expressions
+ (void)(1 ? x0 : z0);
+ (void)(1 ? x1 : z1); /* { dg-error "pointers to arrays with different qualifiers" } */
+ (void)(1 ? x2 : z2); /* { dg-error "pointers to arrays with different qualifiers" } */
+ (void)(1 ? x0 : x1); /* { dg-error "pointer type mismatch in conditional expression" } */
+ (void)(1 ? x1 : x2); /* { dg-error "pointer type mismatch in conditional expression" } */
+ (void)(1 ? x2 : x0); /* { dg-error "pointer type mismatch in conditional expression" } */
+ v0p = (1 ? z0 : v0p); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+ v1p = (1 ? z1 : v1p); /* { dg-error "pointers to arrays with different qualifiers|assignment discards" } */
+ v2p = (1 ? z2 : v2p); /* { dg-error "pointers to arrays with different qualifiers|assignment discards" } */
+ v0p = (1 ? x0 : x0p); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+ v1p = (1 ? x1 : x1p); /* { dg-error "pointers to arrays with different qualifiers|assignment discards" } */
+ v2p = (1 ? x2 : x2p); /* { dg-error "pointers to arrays with different qualifiers|assignment discards" } */
+ (1 ? x0 : z0)[0] = 1; /* { dg-error "assignment of read-only location" } */
+ (1 ? x1 : z1)[0][0] = 1; /* { dg-error "assignment of read-only location|pointers to arrays" } */
+ (1 ? x2 : z2)[0][0][0] = 1; /* { dg-error "assignment of read-only location|pointers to arrays" } */
+ v0p = (1 ? p : z0); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+ v1p = (1 ? p : z1);
+ v2p = (1 ? p : z2);
+ v0p = (1 ? pc : x0); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+ v1p = (1 ? pc : x1); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+ v2p = (1 ? pc : x2); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+}