diff mbox

[v5] warning about const multidimensional array as function parameter

Message ID 20141208205102.5a16d801@lemur
State New
Headers show

Commit Message

Martin Uecker Dec. 9, 2014, 4:51 a.m. UTC
Another version of this patch. I fixed the formatting problems and 
the spurios use of OPT_Wdiscarded_array_qualifiers. I also added 
'-pedantic -Wdiscarded-array-qualifiers' to the dg-options in
'testsuite/gcc.dg/qual-component-1.c' and changed the expected 
warnings to the new ones. For some reason, the changes to this
file were missing in my previous versions. (scroll down to the
end for this file)

Thank you,
Martin


2014-12-08 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)
	* gcc.dg/qual-component-1.c: Change dg-options, dg-warnings

Comments

Joseph Myers Dec. 20, 2014, 12:29 a.m. UTC | #1
On Mon, 8 Dec 2014, Martin Uecker wrote:

> Another version of this patch. I fixed the formatting problems and 
> the spurios use of OPT_Wdiscarded_array_qualifiers. I also added 
> '-pedantic -Wdiscarded-array-qualifiers' to the dg-options in
> 'testsuite/gcc.dg/qual-component-1.c' and changed the expected 
> warnings to the new ones. For some reason, the changes to this
> file were missing in my previous versions. (scroll down to the
> end for this file)

Thanks, I've committed this patch.
diff mbox

Patch

Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(Revision 218476)
+++ 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");
 
@@ -4609,6 +4624,13 @@  build_conditional_expr (location_t colon_loc, tree
       else if (VOID_TYPE_P (TREE_TYPE (type1))
 	       && !TYPE_ATOMIC (TREE_TYPE (type1)))
 	{
+	  if ((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 "
@@ -4619,6 +4641,13 @@  build_conditional_expr (location_t colon_loc, tree
       else if (VOID_TYPE_P (TREE_TYPE (type2))
 	       && !TYPE_ATOMIC (TREE_TYPE (type2)))
 	{
+	  if ((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 "
@@ -5661,7 +5690,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)                                                     \
       {                                                                  \
@@ -5688,10 +5717,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)                                                     \
       {                                                                  \
@@ -5716,6 +5744,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);
 
@@ -5758,15 +5815,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++"));
 	}
     }
 
@@ -5921,34 +5978,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;
 	    }
@@ -6096,42 +6153,69 @@  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 (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 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)
 		  & ~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.  */
@@ -6140,15 +6224,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)
@@ -6159,31 +6243,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);
     }
@@ -6200,31 +6284,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 218476)
+++ gcc/c-family/c.opt	(Arbeitskopie)
@@ -383,6 +383,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 218476)
+++ 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.
@@ -1784,6 +1785,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 218476)
+++ 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
@@ -4282,9 +4283,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 218476)
+++ 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 218476)
+++ 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 218476)
+++ 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,60 @@ 
+/* { 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); /* { 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,102 @@ 
+/* { 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); /* { 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-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" } */
+}
+
Index: gcc/testsuite/gcc.dg/qual-component-1.c
===================================================================
--- gcc/testsuite/gcc.dg/qual-component-1.c	(Revision 218476)
+++ gcc/testsuite/gcc.dg/qual-component-1.c	(Arbeitskopie)
@@ -3,7 +3,7 @@ 
    union.  Bug 27697 from Frank Victor Fischer.  */
 /* Origin: Joseph Myers <joseph@codesourcery.com> */
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-pedantic -Wdiscarded-array-qualifiers" } */
 
 struct s {
   int a;
@@ -110,12 +110,12 @@  g (void)
     int (*b)[1] = &v1.b;
     int (*c)[2][3] = &v1.c;
     int (*cc)[3] = v1.c;
-    const int (*ff)[3] = v1.c; /* { dg-warning "initialization from incompatible pointer type" } */
+    const int (*ff)[3] = v1.c; /* { dg-warning "pointers to arrays with different qualifiers" } */
     a = &v1.a;
     b = &v1.b;
     c = &v1.c;
     cc = v1.c;
-    ff = v1.c; /* { dg-warning "assignment from incompatible pointer type" } */
+    ff = v1.c; /* { dg-warning "pointers to arrays with different qualifiers" } */
   }
   {
     const int *d = &v1.d;
@@ -122,12 +122,12 @@  g (void)
     const int (*e)[1] = &v1.e;
     const int (*f)[2][3] = &v1.f;
     const int (*ff)[3] = v1.f;
-    int (*cc)[3] = v1.f; /* { dg-warning "initialization from incompatible pointer type" } */
+    int (*cc)[3] = v1.f; /* { dg-warning "pointers to arrays with different qualifiers|initialization discards" } */
     d = &v1.d;
     e = &v1.e;
     f = &v1.f;
     ff = v1.f;
-    cc = v1.f; /* { dg-warning "assignment from incompatible pointer type" } */
+    cc = v1.f; /* { dg-warning "pointers to arrays with different qualifiers|assignment discards" } */
   }
 
   {
@@ -135,12 +135,12 @@  g (void)
     int (*b)[1] = &v2->b;
     int (*c)[2][3] = &v2->c;
     int (*cc)[3] = v2->c;
-    const int (*ff)[3] = v2->c; /* { dg-warning "initialization from incompatible pointer type" } */
+    const int (*ff)[3] = v2->c; /* { dg-warning "pointers to arrays with different qualifiers" } */
     a = &v2->a;
     b = &v2->b;
     c = &v2->c;
     cc = v2->c;
-    ff = v2->c; /* { dg-warning "assignment from incompatible pointer type" } */
+    ff = v2->c; /* { dg-warning "pointers to arrays with different qualifiers" } */
   }
   {
     const int *d = &v2->d;
@@ -147,12 +147,12 @@  g (void)
     const int (*e)[1] = &v2->e;
     const int (*f)[2][3] = &v2->f;
     const int (*ff)[3] = v2->f;
-    int (*cc)[3] = v2->f; /* { dg-warning "initialization from incompatible pointer type" } */
+    int (*cc)[3] = v2->f; /* { dg-warning "pointers to arrays with different qualifiers|initialization discards" } */
     d = &v2->d;
     e = &v2->e;
     f = &v2->f;
     ff = v2->f;
-    cc = v2->f; /* { dg-warning "assignment from incompatible pointer type" } */
+    cc = v2->f; /* { dg-warning "pointers to arrays with different qualifiers|assignment discards" } */
   }
 
   {
@@ -160,12 +160,12 @@  g (void)
     const int (*e)[1] = &v3->b;
     const int (*f)[2][3] = &v3->c;
     const int (*ff)[3] = v3->c;
-    int (*cc)[3] = v3->c; /* { dg-warning "initialization from incompatible pointer type" } */
+    int (*cc)[3] = v3->c; /* { dg-warning "pointers to arrays with different qualifiers|initialization discards" } */
     d = &v3->a;
     e = &v3->b;
     f = &v3->c;
     ff = v3->c;
-    cc = v3->c; /* { dg-warning "assignment from incompatible pointer type" } */
+    cc = v3->c; /* { dg-warning "pointers to arrays with different qualifiers|assignment discards" } */
   }
   {
     const int *d = &v3->d;
@@ -172,12 +172,12 @@  g (void)
     const int (*e)[1] = &v3->e;
     const int (*f)[2][3] = &v3->f;
     const int (*ff)[3] = v3->f;
-    int (*cc)[3] = v3->f; /* { dg-warning "initialization from incompatible pointer type" } */
+    int (*cc)[3] = v3->f; /* { dg-warning "pointers to arrays with different qualifiers|initialization discards" } */
     d = &v3->d;
     e = &v3->e;
     f = &v3->f;
     ff = v3->f;
-    cc = v3->f; /* { dg-warning "assignment from incompatible pointer type" } */
+    cc = v3->f; /* { dg-warning "pointers to arrays with different qualifiers|assignment discards" } */
   }
 
   {
@@ -185,12 +185,12 @@  g (void)
     const int (*e)[1] = &v4.b;
     const int (*f)[2][3] = &v4.c;
     const int (*ff)[3] = v4.c;
-    int (*cc)[3] = v4.c; /* { dg-warning "initialization from incompatible pointer type" } */
+    int (*cc)[3] = v4.c; /* { dg-warning "pointers to arrays with different qualifiers|initialization discards" } */
     d = &v4.a;
     e = &v4.b;
     f = &v4.c;
     ff = v4.c;
-    cc = v4.c; /* { dg-warning "assignment from incompatible pointer type" } */
+    cc = v4.c; /* { dg-warning "pointers to arrays with different qualifiers|assignment discards" } */
   }
   {
     const int *d = &v4.d;
@@ -197,12 +197,12 @@  g (void)
     const int (*e)[1] = &v4.e;
     const int (*f)[2][3] = &v4.f;
     const int (*ff)[3] = v4.f;
-    int (*cc)[3] = v4.f; /* { dg-warning "initialization from incompatible pointer type" } */
+    int (*cc)[3] = v4.f; /* { dg-warning "pointers to arrays with different qualifiers|initialization discards" } */
     d = &v4.d;
     e = &v4.e;
     f = &v4.f;
     ff = v4.f;
-    cc = v4.f; /* { dg-warning "assignment from incompatible pointer type" } */
+    cc = v4.f; /* { dg-warning "pointers to arrays with different qualifiers|assignment discards" } */
   }
 
   {
@@ -210,12 +210,12 @@  g (void)
     const int (*e)[1] = &v5.x.b;
     const int (*f)[2][3] = &v5.x.c;
     const int (*ff)[3] = v5.x.c;
-    int (*cc)[3] = v5.x.c; /* { dg-warning "initialization from incompatible pointer type" } */
+    int (*cc)[3] = v5.x.c; /* { dg-warning "pointers to arrays with different qualifiers|initialization discards" } */
     d = &v5.x.a;
     e = &v5.x.b;
     f = &v5.x.c;
     ff = v5.x.c;
-    cc = v5.x.c; /* { dg-warning "assignment from incompatible pointer type" } */
+    cc = v5.x.c; /* { dg-warning "pointers to arrays with different qualifiers|assignment discards" } */
   }
   {
     const int *d = &v5.x.d;
@@ -222,11 +222,11 @@  g (void)
     const int (*e)[1] = &v5.x.e;
     const int (*f)[2][3] = &v5.x.f;
     const int (*ff)[3] = v5.x.f;
-    int (*cc)[3] = v5.x.f; /* { dg-warning "initialization from incompatible pointer type" } */
+    int (*cc)[3] = v5.x.f; /* { dg-warning "pointers to arrays with different qualifiers|initialization discards" } */
     d = &v5.x.d;
     e = &v5.x.e;
     f = &v5.x.f;
     ff = v5.x.f;
-    cc = v5.x.f; /* { dg-warning "assignment from incompatible pointer type" } */
+    cc = v5.x.f; /* { dg-warning "pointers to arrays with different qualifiers|assignment discards" } */
   }
 }