diff mbox series

[C] qualifiers of pointers to arrays in C2X [PR 98397]

Message ID 1608546487.5427.1.camel@med.uni-goettingen.de
State New
Headers show
Series [C] qualifiers of pointers to arrays in C2X [PR 98397] | expand

Commit Message

Uecker, Martin Dec. 21, 2020, 10:28 a.m. UTC
Here is a patch that adds the minor corrections needed for
qualifiers of pointers to arrays in C23.

-- Martin


C: Correct qualifiers for pointers to arrays according to C2X [PR98397]
    
2020-12-12  Martin Uecker  <muecker@gwdg.de>
    
gcc/c/
     PR c/98397
     * c-typeck.c (comp_target_types): Change pedwarn to pedwarn_c11
     for pointers to arrays with qualifiers.      
     (build_conditional_expr): For C23 don't lose qualifiers for pointers
     to arrays when the other pointer is a void pointer.
     (convert_for_assignment): For C23 don't pedwarn when converting from
     void* with qualifiers to a pointer to array with the same qualifiers.

gcc/testsuite/
     PR c/98397
     * gcc.dg/c2x-qual-1.c: New test.   
     * gcc.dg/c2x-qual-2.c: New test.

Comments

Joseph Myers Jan. 1, 2021, 12:01 a.m. UTC | #1
On Mon, 21 Dec 2020, Uecker, Martin wrote:

> diff --git a/gcc/testsuite/gcc.dg/c2x-qual-1.c b/gcc/testsuite/gcc.dg/c2x-qual-1.c
> new file mode 100644
> index 00000000000..058a840e04c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/c2x-qual-1.c
> @@ -0,0 +1,12 @@
> +/* Test that qualifiers are not lost in tertiary operator for pointers to arrays, PR98397 */
> +/* { dg-do compile } */
> +/* { dg-options "-std=gnu2x" } */
> +
> +void foo(void)
> +{
> +	const int (*u)[1];
> +	void *v;
> +	extern const void *vc;
> +	extern typeof(1 ? u : v) vc;
> +	extern typeof(1 ? v : u) vc;
> +}

I'd expect c2x-* tests to use -std=c2x not -std=gnu2x.  Tests needing 
-std=gnu2x can be gnu2x-* tests, but you should be able to test the types 
using _Generic without needing any gnu2x features.  c2x-* tests should 
also use -pedantic or -pedantic-errors unless they are specifically 
testing something that doesn't work with those options.

There should also be tests for cases where code is valid before C2x but 
invalid in C2x (assignment storing a pointer-to-qualified-array in void *, 
for example).

All the tests should have both c2x-* and c11-* variants so the testsuite 
verifies that the code is properly handled in C11 mode (warnings with 
-pedantic, errors with -pedantic-errors, in the cases that are invalid for 
C11 but valid for C2x).  There should also be -Wc11-c2x-compat tests with 
-std=c2x where appropriate.
Uecker, Martin Jan. 17, 2021, 8:18 p.m. UTC | #2
Am Freitag, den 01.01.2021, 00:01 +0000 schrieb Joseph Myers:
> 
> 
> I'd expect c2x-* tests to use -std=c2x not -std=gnu2x.  Tests needing 
> -std=gnu2x can be gnu2x-* tests, but you should be able to test the types 
> using _Generic without needing any gnu2x features.  c2x-* tests should 
> also use -pedantic or -pedantic-errors unless they are specifically 
> testing something that doesn't work with those options.
> 
> There should also be tests for cases where code is valid before C2x but 
> invalid in C2x (assignment storing a pointer-to-qualified-array in void *, 
> for example).
> 
> All the tests should have both c2x-* and c11-* variants so the testsuite 
> verifies that the code is properly handled in C11 mode (warnings with 
> -pedantic, errors with -pedantic-errors, in the cases that are invalid for 
> C11 but valid for C2x).  There should also be -Wc11-c2x-compat tests with 
> -std=c2x where appropriate.


Here is a revised version which adds some missing warnings 
and also fixed some error regarding which warnings got emitted.

I added tests for C2X that test with std=c2x and -pedantic-errors
with and without -Wc11-c2x-compat. In the conditional operator
I directly test for the type using _Generic and _Static_assert.
This test also exists for c11 testing for the old behavior.

I did not add tests for c11 for warnings because we already
had warnings before and the tests for these exist. (I removed 
-Wdiscarded-array-qualifiers from the old tests as this flag
is not needed.) Or should there be additional warnings
with -Wc11-c2x-compat for c11? But warning twice about
the same issue does not seem ideal...

More comments?

Best,
Martin


diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 67c0080a5ef..243790e7abf 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -1318,8 +1318,8 @@ comp_target_types (location_t location, tree ttl, tree ttr)
   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");
+    pedwarn_c11 (location, OPT_Wpedantic, "pointers to arrays with different qualifiers "
+					  "are incompatible in ISO C before C2X");
 
   if (val == 2)
     pedwarn (location, OPT_Wpedantic, "types are not quite compatible");
@@ -5331,39 +5331,39 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
 		    "used in conditional expression");
 	  return error_mark_node;
 	}
-      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)
+      else if ((VOID_TYPE_P (TREE_TYPE (type1))
+		&& !TYPE_ATOMIC (TREE_TYPE (type1)))
+	       || (VOID_TYPE_P (TREE_TYPE (type2))
+		   && !TYPE_ATOMIC (TREE_TYPE (type2))))
+	{
+	  tree t1 = TREE_TYPE (type1);
+	  tree t2 = TREE_TYPE (type2);
+	  if (!VOID_TYPE_P (t1))
+	   {
+	     /* roles are swapped */
+	     t1 = t2;
+	     t2 = TREE_TYPE (type1);
+	   }
+	  tree t2_stripped = strip_array_types (t2);
+	  if ((TREE_CODE (t2) == ARRAY_TYPE)
+	      && (TYPE_QUALS (t2_stripped) & ~TYPE_QUALS (t1)))
+	    {
+	      if (!flag_isoc2x)
+		warning_at (colon_loc, OPT_Wdiscarded_array_qualifiers,
+			    "pointer to array loses qualifier "
+			    "in conditional expression");
+	      else if (warn_c11_c2x_compat > 0)
+		warning_at (colon_loc, OPT_Wc11_c2x_compat,
+			    "pointer to array does not lose qualifier in C2X "
+			    "in conditional expression");
+	    }
+	  if (TREE_CODE (t2) == FUNCTION_TYPE)
 	    pedwarn (colon_loc, OPT_Wpedantic,
 		     "ISO C forbids conditional expr between "
 		     "%<void *%> and function pointer");
-	  result_type = build_pointer_type (qualify_type (TREE_TYPE (type1),
-							  TREE_TYPE (type2)));
-	}
-      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 "
-		     "%<void *%> and function pointer");
-	  result_type = build_pointer_type (qualify_type (TREE_TYPE (type2),
-							  TREE_TYPE (type1)));
+	  if (flag_isoc2x)
+	    t2 = t2_stripped;
+	  result_type = build_pointer_type (qualify_type (t1, t2));
 	}
       /* Objective-C pointer comparisons are a bit more lenient.  */
       else if (objc_have_common_type (type1, type2, -3, NULL_TREE))
@@ -7316,15 +7316,16 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	  else if (TREE_CODE (ttr) != FUNCTION_TYPE
 		   && TREE_CODE (ttl) != FUNCTION_TYPE)
 	    {
+	       /* Assignments between atomic and non-atomic objects are OK.  */
+	       bool warn_quals_ped = TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
+				     & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl);
+	       bool warn_quals = TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
+				 & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (strip_array_types (ttl));
+
 	      /* 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))
+	      if (warn_quals || (warn_quals_ped && pedantic && !flag_isoc2x))
 		{
 		  PEDWARN_FOR_QUALIFIERS (location, expr_loc,
 				          OPT_Wdiscarded_qualifiers,
@@ -7338,6 +7339,10 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 					     "pointer target type"),
 				          TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
 		}
+	      else if (warn_quals_ped && pedantic && flag_isoc2x && (warn_c11_c2x_compat > 0))
+		pedwarn (expr_loc, OPT_Wc11_c2x_compat,
+				   "array with qualifier on the element is not qualified before
C2X");
+
 	      /* If this is not a case of ignoring a mismatch in signedness,
 		 no warning.  */
 	      else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
diff --git a/gcc/testsuite/gcc.dg/c11-qual-1.c b/gcc/testsuite/gcc.dg/c11-qual-1.c
new file mode 100644
index 00000000000..f731e068830
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-qual-1.c
@@ -0,0 +1,11 @@
+/* Test that qualifiers are lost in tertiary operator for pointers to arrays before C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors -Wno-discarded-array-qualifiers" } */
+
+void foo(void)
+{
+	const int (*u)[1];
+	void *v;
+	_Static_assert(_Generic(1 ? u : v, const void*: 0, void*: 1), "qualifier not lost");
+	_Static_assert(_Generic(1 ? v : u, const void*: 0, void*: 1), "qualifier not lost");
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-1.c b/gcc/testsuite/gcc.dg/c2x-qual-1.c
new file mode 100644
index 00000000000..d53dc214f91
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-1.c
@@ -0,0 +1,11 @@
+/* Test related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+void foo(void)
+{
+	const int (*u)[1];
+	void *v;
+	_Static_assert(_Generic(1 ? u : v, const void*: 1, void*: 0), "lost qualifier");
+	_Static_assert(_Generic(1 ? v : u, const void*: 1, void*: 0), "lost qualifier");
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-2.c b/gcc/testsuite/gcc.dg/c2x-qual-2.c
new file mode 100644
index 00000000000..3304410bb96
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-2.c
@@ -0,0 +1,12 @@
+/* Test related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors -Wc11-c2x-compat" } */
+
+void foo(void)
+{
+	const int (*u)[1];
+	void *v;
+	_Static_assert(_Generic(1 ? u : v, const void*: 1, void*: 0), "lost qualifier");	/*
{ dg-warning "pointer to array does not lose qualifier in C2X" } */
+	_Static_assert(_Generic(1 ? v : u, const void*: 1, void*: 0), "lost qualifier");	/*
{ dg-warning "pointer to array does not lose qualifier in C2X" } */
+
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-3.c b/gcc/testsuite/gcc.dg/c2x-qual-3.c
new file mode 100644
index 00000000000..58fe16fed94
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-3.c
@@ -0,0 +1,9 @@
+/* Test related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+void f(void)
+{
+	int (*x)[3];
+	const int (*p)[3] = x;
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-4.c b/gcc/testsuite/gcc.dg/c2x-qual-4.c
new file mode 100644
index 00000000000..e04668eb752
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-4.c
@@ -0,0 +1,9 @@
+/* Test related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors -Wc11-c2x-compat" } */
+
+void f(void)
+{
+	int (*x)[3];
+	const int (*p)[3] = x; /* { dg-warning "pointers to arrays with different qualifiers are
incompatible in ISO C before C2X"  } */
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-5.c b/gcc/testsuite/gcc.dg/c2x-qual-5.c
new file mode 100644
index 00000000000..4647d0b0dfe
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-5.c
@@ -0,0 +1,9 @@
+/* Test related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+void f(void)
+{
+	const void* x;
+	const int (*p)[3] = x;
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-6.c b/gcc/testsuite/gcc.dg/c2x-qual-6.c
new file mode 100644
index 00000000000..dca50ac014f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-6.c
@@ -0,0 +1,9 @@
+/* Test related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors -Wc11-c2x-compat" } */
+
+void f(void)
+{
+	const void* x;
+	const int (*p)[3] = x; /* { dg-error "array with qualifier on the element is not qualified
before C2X" } */
+}
diff --git a/gcc/testsuite/gcc.dg/pointer-array-quals-1.c b/gcc/testsuite/gcc.dg/pointer-array-
quals-1.c
index 921a37e9e0d..498ab223162 100644
--- a/gcc/testsuite/gcc.dg/pointer-array-quals-1.c
+++ b/gcc/testsuite/gcc.dg/pointer-array-quals-1.c
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* Origin: Martin Uecker <uecker@eecs.berkeley.edu> */
-/* { dg-options "-Wdiscarded-array-qualifiers" } */
+/* { dg-options "" } */
 void tvoid(void* x);
 void transpose0(double* out, const double* in) { }
 void transpose1(double out[2][2], const double in[2][2]) { }
diff --git a/gcc/testsuite/gcc.dg/pointer-array-quals-2.c b/gcc/testsuite/gcc.dg/pointer-array-
quals-2.c
index 30689c7312d..4c95d8a3a78 100644
--- a/gcc/testsuite/gcc.dg/pointer-array-quals-2.c
+++ b/gcc/testsuite/gcc.dg/pointer-array-quals-2.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-Wdiscarded-array-qualifiers -pedantic-errors" } */
+/* { dg-options "-pedantic-errors" } */
 /* Origin: Martin Uecker <uecker@eecs.berkeley.edu> */
 void tvoid(void* x);
 void transpose0(double* out, const double* in) { }
Joseph Myers Jan. 18, 2021, 9:48 p.m. UTC | #3
On Sun, 17 Jan 2021, Uecker, Martin wrote:

> I did not add tests for c11 for warnings because we already
> had warnings before and the tests for these exist. (I removed 
> -Wdiscarded-array-qualifiers from the old tests as this flag
> is not needed.) Or should there be additional warnings
> with -Wc11-c2x-compat for c11? But warning twice about
> the same issue does not seem ideal...

If something is already warned about by default in C11 mode, 
-Wc11-c2x-compat doesn't need to produce extra warnings.

> +	int (*x)[3];
> +	const int (*p)[3] = x; /* { dg-warning "pointers to arrays with different qualifiers are
> incompatible in ISO C before C2X"  } */

"incompatible" doesn't seem the right wording for the diagnostic.  The 
types are incompatible (i.e. not compatible types) regardless of standard 
version; the issue in this case is the rules for assignment.

> diff --git a/gcc/testsuite/gcc.dg/c2x-qual-6.c b/gcc/testsuite/gcc.dg/c2x-qual-6.c
> new file mode 100644
> index 00000000000..dca50ac014f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/c2x-qual-6.c
> @@ -0,0 +1,9 @@
> +/* Test related to qualifiers and pointers to arrays in C2X, PR98397 */
> +/* { dg-do compile } */
> +/* { dg-options "-std=c2x -pedantic-errors -Wc11-c2x-compat" } */
> +
> +void f(void)
> +{
> +	const void* x;
> +	const int (*p)[3] = x; /* { dg-error "array with qualifier on the element is not qualified
> before C2X" } */

This is showing a bug in the compiler implementation.  In C2X mode, this 
message should be a warning not a pedwarn because the code is not a 
constraint violation.  -Wc11-c2x-compat should produce a warning 
(independent of -pedantic), but -pedantic-errors should not turn it into 
an error.
diff mbox series

Patch

diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index f68cb01529b..46a66e96db5 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -1318,8 +1318,8 @@  comp_target_types (location_t location, tree ttl, tree ttr)
   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");
+    pedwarn_c11 (location, OPT_Wpedantic, "pointers to arrays with different qualifiers "
+					  "are incompatible in ISO C before C2X");
 
   if (val == 2)
     pedwarn (location, OPT_Wpedantic, "types are not quite compatible");
@@ -5331,39 +5331,32 @@  build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
 		    "used in conditional expression");
 	  return error_mark_node;
 	}
-      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))))
+      else if ((VOID_TYPE_P (TREE_TYPE (type1))
+		&& !TYPE_ATOMIC (TREE_TYPE (type1)))
+	       || (VOID_TYPE_P (TREE_TYPE (type2))
+		   && !TYPE_ATOMIC (TREE_TYPE (type2))))
+	{
+	  tree t1 = TREE_TYPE (type1);
+	  tree t2 = TREE_TYPE (type2);
+	  if (!VOID_TYPE_P (t1))
+	   {
+	     /* roles are swapped */
+	     t1 = t2;
+	     t2 = TREE_TYPE (type1);
+	   }
+	  tree t2_stripped = strip_array_types (t2);
+	  if (flag_isoc2x)
+	    t2 = t2_stripped;
+	  else if ((TREE_CODE (t2) == ARRAY_TYPE)
+		   && (TYPE_QUALS (t2_stripped) & ~TYPE_QUALS (t1)))
 	    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 "
-		     "%<void *%> and function pointer");
-	  result_type = build_pointer_type (qualify_type (TREE_TYPE (type1),
-							  TREE_TYPE (type2)));
-	}
-      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)
+	  if (TREE_CODE (t2) == FUNCTION_TYPE)
 	    pedwarn (colon_loc, OPT_Wpedantic,
 		     "ISO C forbids conditional expr between "
 		     "%<void *%> and function pointer");
-	  result_type = build_pointer_type (qualify_type (TREE_TYPE (type2),
-							  TREE_TYPE (type1)));
+	  result_type = build_pointer_type (qualify_type (t1, t2));
 	}
       /* Objective-C pointer comparisons are a bit more lenient.  */
       else if (objc_have_common_type (type1, type2, -3, NULL_TREE))
@@ -7319,7 +7312,7 @@  convert_for_assignment (location_t location, location_t expr_loc, tree 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)
+	      if (flag_isoc2x || !pedantic)
 	        ttl = strip_array_types (ttl);
 
 	      /* Assignments between atomic and non-atomic objects are OK.  */
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-1.c b/gcc/testsuite/gcc.dg/c2x-qual-1.c
new file mode 100644
index 00000000000..058a840e04c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-1.c
@@ -0,0 +1,12 @@ 
+/* Test that qualifiers are not lost in tertiary operator for pointers to arrays, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu2x" } */
+
+void foo(void)
+{
+	const int (*u)[1];
+	void *v;
+	extern const void *vc;
+	extern typeof(1 ? u : v) vc;
+	extern typeof(1 ? v : u) vc;
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-2.c b/gcc/testsuite/gcc.dg/c2x-qual-2.c
new file mode 100644
index 00000000000..68b897226d3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-2.c
@@ -0,0 +1,12 @@ 
+/* Test that there are no warnings about lost qualifiers for pointers to arrays
+   with pedantic for C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu2x -pedantic" } */
+
+void foo(void)
+{
+	const void *w;
+	const int (*u)[1] = w;
+	void *v;
+	(1 ? u : v);
+}