diff mbox

[v3] warning about const multidimensional array as function parameter

Message ID 20141106101820.22ee3429@lemur
State New
Headers show

Commit Message

Martin Uecker Nov. 6, 2014, 6:18 p.m. UTC
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


previous versions (see v1 for a description of the main idea):
v2: https://gcc.gnu.org/ml/gcc/2014-10/msg00243.html
v1: https://gcc.gnu.org/ml/gcc/2014-10/msg00224.html



On Wed, 29 Oct 2014 16:43:16 +0000
"Joseph S. Myers" <joseph@codesourcery.com>:
> On Tue, 28 Oct 2014, Martin Uecker wrote:

> > Note that there is now a semantic (and not only diagnostic) change.
> > Without this patch
> > 
> > const int a[1];
> > int b[1];
> > (x ? &a : &b)
> > 
> > would return a 'void*' and a warning about pointer type mismatch.
> > With this patch the conditional has type 'const int (*)[1]'.
> 
> I believe that is safe (in that that conditional expression isn't valid in 
> ISO C).  What wouldn't be safe is making a conditional expression between 
> void * and const int (*)[] have type const void * instead of void *.

Yes, the cases which are changed in the patch should all
be illegal in ISO C. 

On the other hand, not changing the case you mention means that
there is still inconsistent behaviour even with the patch:
 
void* v;
const int (*i)[1];
int (*ip)[1] = (1 ? v : i);	// const is lost in conditional

const int (*i2);
int (*ip2) = (1 ? v : i2);	// const is not lost -> warning

Maybe I should at least add a warning for the first case where the 
'const' is lost already in the conditional?


> WARN_FOR_QUALIFIERS uses pedwarn.  That means this is not safe, because 
> pedwarns become errors with -pedantic-errors, but this includes cases that 
> are valid in ISO C and so must not become errors with -pedantic-errors 
> (such as converting const int (*)[] to void *).

Ok. I added a new macro WARNING_FOR_QUALIFIERS and renamed the others
to PEDWARN_FOR_* . The full logic to make this work correctly turned
out to be quite simple. 

The behaviour can be summarized like this:

p2ca = pointer to const array
p2cv = pointer to const void
...

lq = loss of qualifier
ip = incompatible pointer 
'!' error with -pedantic-errors
'*' can be deactivated with a new option

conversion    old  new   new+pedantic
p2ca -> p2a : ip! | lq* | ip! + lq*
p2a  -> p2ca: ip! |     | ip!
p2v  -> p2a :     |     | 
p2v -> p2ca :     |     |
p2cv -> p2a : lq! | lq! | lq!
p2cv -> p2ca: lq! |     | lq!
p2a -> p2v  :     |     | 
p2a -> p2cv :     |     |
p2ca -> p2v :     | lq* | lq*
p2ca -> p2cv:     |     |




2014-10-28 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.
        (comp-target-types): Allow pointers to arrays with different qualifiers.
        (convert-for-assignment): Change 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)

Comments

Joseph Myers Nov. 6, 2014, 11:40 p.m. UTC | #1
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.
diff mbox

Patch

Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(Revision 217175)
+++ 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 loosing 
+     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");
 
@@ -5655,7 +5670,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 +5697,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 +5724,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 +5795,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 +5958,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 +6133,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 +6205,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 +6224,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 +6265,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 217175)
+++ 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 217175)
+++ 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 217175)
+++ 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 217175)
+++ 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 217175)
+++ 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 217175)
+++ 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,106 @@ 
+/* { 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);
+	v2p = (1 ? p : z2);
+	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" } */
+}