public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C PATCH] qualifiers of pointers to arrays in C2X [PR 98397]
@ 2021-05-24  6:05 Uecker, Martin
  2021-06-11 19:25 ` Uecker, Martin
  2021-08-12 16:58 ` Joseph Myers
  0 siblings, 2 replies; 9+ messages in thread
From: Uecker, Martin @ 2021-05-24  6:05 UTC (permalink / raw)
  To: gcc-patches; +Cc: joseph


Hi Joseph,

I found some time to update this patch. The only real change
of the patch is the qualifier in the conditional expression for
pointer to arrays in C2X. All the rest are the warnings,
which were wrong in the last version.

I hope I got this correct this time in combination with
-pedantic-errors and -Wc11-c2x-compat. 

Martin


2021-05-16  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. Update warnings.
     (convert_for_assignment): Update warnings for C2X when converting from
     void* with qualifiers to a pointer to array with the same qualifiers.

gcc/testsuite/
     PR c/98397
     * gcc.dg/c11-qual-1.c: New test.
     * gcc.dg/c2x-qual-1.c: New test.
     * gcc.dg/c2x-qual-2.c: New test.
     * gcc.dg/c2x-qual-3.c: New test.
     * gcc.dg/c2x-qual-4.c: New test.
     * gcc.dg/c2x-qual-5.c: New test.
     * gcc.dg/c2x-qual-6.c: New test.
     * gcc.dg/pointer-array-quals-1.c: Remove unnecessary flag.
     * gcc.dg/pointer-array-quals-2.c: Remove unnecessary flag.


diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index fc64ef96fb8..5b13656c090 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -1328,8 +1328,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, "invalid use of pointers to arrays with different qualifiers "
+					  "in ISO C before C2X");
 
   if (val == 2)
     pedwarn (location, OPT_Wpedantic, "types are not quite compatible");
@@ -5396,39 +5396,40 @@ 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 loses qualifier "
+			    "in conditional expression in ISO C before C2X");
+	    }
+	  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)));
+	  /* for array, use qualifiers of element type */
+	  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))
@@ -6786,27 +6787,40 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 
   /* 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_ASSIGNMENT but with an
-     extra parameter to enumerate qualifiers.  */
-#define PEDWARN_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \
+     compile time.  It can be called with 'pedwarn' or 'warning_at'.  */
+#define WARNING_FOR_QUALIFIERS(PEDWARN, LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \
   do {                                                                   \
     switch (errtype)                                                     \
       {                                                                  \
       case ic_argpass:                                                   \
-	{								\
-	auto_diagnostic_group d;						\
-	if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS))		\
-	  inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);	\
-	}								\
+	{								 \
+	  auto_diagnostic_group d;					 \
+	  if (PEDWARN) {						 \
+	    if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS))          \
+	      inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);  \
+	  } else {							 \
+	    if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS))	 \
+	      inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);  \
+	  }								 \
+	}								 \
         break;                                                           \
       case ic_assign:                                                    \
-        pedwarn (LOCATION, OPT, AS, QUALS);				 \
+	if (PEDWARN)							 \
+	  pedwarn (LOCATION, OPT, AS, QUALS);                            \
+	else								 \
+	  warning_at (LOCATION, OPT, AS, QUALS);                         \
         break;                                                           \
       case ic_init:                                                      \
-        pedwarn (LOCATION, OPT, IN, QUALS);				 \
+	if (PEDWARN)							 \
+	  pedwarn (LOCATION, OPT, IN, QUALS);                            \
+	else								 \
+	  warning_at (LOCATION, OPT, IN, QUALS);                         \
         break;                                                           \
       case ic_return:                                                    \
-        pedwarn (LOCATION, OPT, RE, QUALS);				 \
+	if (PEDWARN)							 \
+	  pedwarn (LOCATION, OPT, RE, QUALS);                            \
+	else								 \
+	  warning_at (LOCATION, OPT, RE, QUALS);                         \
         break;                                                           \
       default:                                                           \
         gcc_unreachable ();                                              \
@@ -6815,32 +6829,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 
   /* 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:                                                   \
-	{								\
-	  auto_diagnostic_group d;						\
-	  if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS))	\
-	    inform_for_arg (fundecl, (PLOC), parmnum, 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)
+     compile time.  It is the same as PEDWARN_FOR_ASSIGNMENT but with an
+     extra parameter to enumerate qualifiers.  */
+#define PEDWARN_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \
+   WARNING_FOR_QUALIFIERS (true, LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS)
+
 
   if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
     rhs = TREE_OPERAND (rhs, 0);
@@ -7348,17 +7341,18 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 
 	      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 "
+		WARNING_FOR_QUALIFIERS (flag_isoc2x,
+					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 "
+					G_("assignment discards %qv qualifier "
 					   "from pointer target type"),
-				        G_("initialization discards %qv qualifier "
+					G_("initialization discards %qv qualifier "
 					   "from pointer target type"),
-				        G_("return discards %qv qualifier from "
+					G_("return discards %qv qualifier from "
 					   "pointer target type"),
-                                        TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
+					TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
             }
           else if (pedantic
 	      && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
@@ -7381,28 +7375,31 @@ 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);
+		 qualifier on the element type (except for pedantic before C23). */
+	      if (warn_quals || (warn_quals_ped && pedantic && !flag_isoc2x))
+		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));
+	      else if (warn_quals_ped)
+		pedwarn_c11 (location, OPT_Wc11_c2x_compat,
+			     "array with qualifier on the element is not qualified before C2X");
 
-	      /* 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))
-		{
-		  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.  */
 	      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..4d33db1907d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-1.c
@@ -0,0 +1,30 @@
+/* Tests related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+/* test that qualifiers are preserved in tertiary operator for pointers to arrays in C2X */
+
+void f(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");
+}
+
+/* test that assignment of unqualified to qualified pointers works as expected */
+
+void g(void)
+{
+	int (*x)[3];
+	const int (*p)[3] = x;
+}
+
+/* test that assignment of qualified void pointers works as expected */
+
+void h(void)
+{
+	const void* x;
+	const int (*p)[3] = x;
+}
+
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..f60a5b18faa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-2.c
@@ -0,0 +1,30 @@
+/* Tests related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wc11-c2x-compat" } */
+
+/* test that qualifiers are preserved in tertiary operator for pointers to arrays in C2X */
+
+void f(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 loses qualifier in conditional" } */
+	_Static_assert(_Generic(1 ? v : u, const void*: 1, void*: 0), "lost qualifier");	/* { dg-warning "pointer to array loses qualifier in conditional" } */
+}
+
+/* test that assignment of unqualified to qualified pointers works as expected */
+
+void g(void)
+{
+	int (*x)[3];
+	const int (*p)[3] = x; /* { dg-warning "arrays with different qualifiers"  } */
+}
+
+/* test that assignment of qualified void pointers works as expected */
+
+void h(void)
+{
+	const void* x;
+	const int (*p)[3] = x; /* { dg-warning "array with qualifier on the element is not qualified before 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..31896fcb1a1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-3.c
@@ -0,0 +1,30 @@
+/* Tests related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wc11-c2x-compat -pedantic-errors" } */
+
+/* test that qualifiers are preserved in tertiary operator for pointers to arrays in C2X */
+
+void f(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 loses qualifier in conditional" } */
+	_Static_assert(_Generic(1 ? v : u, const void*: 1, void*: 0), "lost qualifier");	/* { dg-warning "pointer to array loses qualifier in conditional" } */
+}
+
+/* test that assignment of unqualified to qualified pointers works as expected */
+
+void g(void)
+{
+	int (*x)[3];
+	const int (*p)[3] = x; /* { dg-warning "arrays with different qualifiers"  } */
+}
+
+/* test that assignment of qualified void pointers works as expected */
+
+void h(void)
+{
+	const void* x;
+	const int (*p)[3] = x; /* { dg-warning "array with qualifier on the element is not qualified before C2X" } */
+}
+
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..93b4723dcd6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-4.c
@@ -0,0 +1,105 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2x" } */
+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 "assignment discards 'const' qualifier from pointer target type" } */
+	v2p = (1 ? p : z2); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+	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" } */
+}
+
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..0801fa0eed5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-5.c
@@ -0,0 +1,101 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+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 "return discards" } */
+const int (*x3(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(z0); /* { dg-error "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+	tvoid(z1); /* { dg-error "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+	tvoid(z2); /* { dg-error "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-error "assignment discards 'const' qualifier from pointer target type" } */
+	p = z2; /* { dg-error "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);
+	transpose2(p, pc);
+	// passing as arguments
+	transpose0(y0, x0);
+	transpose1(y1, o1); /* { dg-error "passing argument 2 of 'transpose1' from incompatible pointer type" } */
+	transpose1(y1, x1);
+	transpose2(y2, o2); /* { dg-error "passing argument 2 of 'transpose2' from incompatible pointer type" } */
+	transpose2(y2, x2);
+	// initialization
+	const double (*x0p) = x0;
+	const double (*x1p)[2] = x1;
+	const double (*x2p)[2][2] = x2;
+	double (*v0p) = z0; /* { dg-error "initialization discards 'const' qualifier from pointer target type" } */
+	double (*v1p)[2] = z1; /* { dg-error "initialization discards" } */
+	double (*v2p)[2][2] = z2; /* { dg-error "initialization discards" } */
+	// assignment
+	x0p = x0;
+	x1p = x1;
+	x2p = x2;
+	// 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;
+	// conditional expressions
+	(void)(1 ? x0 : z0);
+	(void)(1 ? x1 : z1);
+	(void)(1 ? x2 : z2);
+	(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 "assignment discards" } */
+	v2p = (1 ? z2 : v2p); /* { dg-error "assignment discards" } */
+	v0p = (1 ? x0 : x0p); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+	v1p = (1 ? x1 : x1p); /* { dg-error "assignment discards" } */
+	v2p = (1 ? x2 : x2p); /* { dg-error "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" } */
+	(1 ? x2 : z2)[0][0][0] = 1; /* { dg-error "assignment of read-only location" } */
+	v0p = (1 ? p : z0); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+	v1p = (1 ? p : z1); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+	v2p = (1 ? p : z2); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+	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" } */
+}
+
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..9c91e206e30
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-qual-6.c
@@ -0,0 +1,114 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wc11-c2x-compat -pedantic-errors" } */
+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-warning "before C2X" } */
+						/* { dg-error "return discards" "" { target *-*-* } .-1 } */
+const int (*x3(int x[3][3]))[3] { return x; }	/* { dg-warning "before C2X" } */
+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-error "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+	tvoid(z2); /* { dg-error "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-error "assignment discards 'const' qualifier from pointer target type" } */
+	p = z2; /* { dg-error "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-warning "before C2X" } */
+	transpose2(p, pc); /* { dg-warning "before C2X" } */
+	// passing as arguments
+	transpose0(y0, x0);
+	transpose1(y1, o1); /* { dg-error "passing argument 2 of 'transpose1' from incompatible pointer type" } */
+	transpose1(y1, x1); /* { dg-warning "before C2X" } */
+	transpose2(y2, o2); /* { dg-error "passing argument 2 of 'transpose2' from incompatible pointer type" } */
+	transpose2(y2, x2); /* { dg-warning "before C2X" } */
+	// initialization
+	const double (*x0p) = x0;
+	const double (*x1p)[2] = x1; /* { dg-warning "before C2X" } */
+	const double (*x2p)[2][2] = x2; /* { dg-warning "before C2X" } */
+	double (*v0p) = z0; /* { dg-error "initialization discards 'const' qualifier from pointer target type" } */
+	double (*v1p)[2] = z1; /* { dg-warning "before C2X" } */
+				/* { dg-error "initialization discards" "" { target *-*-* } .-1 } */
+	double (*v2p)[2][2] = z2; /* { dg-warning "before C2X" } */
+				/* { dg-error "initialization discards" "" { target *-*-* } .-1 } */
+				
+	// assignment
+	x0p = x0;
+	x1p = x1; /* { dg-warning "before C2X" } */
+	x2p = x2; /* { dg-warning "before C2X" } */
+
+	// subtraction
+	&(x0[1]) - &(z0[0]);
+	&(x1[1]) - &(z1[0]); /* { dg-warning "before C2X" } */
+	&(x2[1]) - &(z2[0]); /* { dg-warning "before C2X" } */
+	// comparison
+	x0 == z0;
+	x1 == z1; /* { dg-warning "before C2X" } */
+	x2 == z2; /* { dg-warning "before C2X" } */
+	x0 < z0;
+	x1 < z1; /* { dg-warning "before C2X" } */
+	x2 < z2; /* { dg-warning "before C2X" } */
+	x0 > z0;
+	x1 > z1; /* { dg-warning "before C2X" } */
+	x2 > z2; /* { dg-warning "before C2X" } */
+	// conditional expressions
+	(void)(1 ? x0 : z0);
+	(void)(1 ? x1 : z1); /* { dg-warning "before C2X" } */
+	(void)(1 ? x2 : z2); /* { dg-warning "before C2X" } */
+	(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-warning "before C2X" } */
+				/* { dg-error "assignment discards" "" { target *-*-* } .-1 } */
+	v2p = (1 ? z2 : v2p); /* { dg-warning "before C2X" } */
+				/* { dg-error "assignment discards" "" { target *-*-* } .-1 } */
+	v0p = (1 ? x0 : x0p); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+	v1p = (1 ? x1 : x1p); /* { dg-error "assignment discards" } */
+				/* { dg-warning "before C2X" "" { target *-*-* } .-1 } */
+	v2p = (1 ? x2 : x2p); /* { dg-error "assignment discards" } */
+				/* { dg-warning "before C2X" "" { target *-*-* } .-1 } */
+	(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" } */
+				/* { dg-warning "before C2X" "" { target *-*-* } .-1 } */
+	(1 ? x2 : z2)[0][0][0] = 1; /* { dg-error "assignment of read-only location" } */
+				/* { dg-warning "before C2X" "" { target *-*-* } .-1 } */
+	v0p = (1 ? p : z0); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+	v1p = (1 ? p : z1); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+				/* { dg-warning "before C2X" "" { target *-*-* } .-1 } */
+	v2p = (1 ? p : z2); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+				/* { dg-warning "before C2X" "" { target *-*-* } .-1 } */
+	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" } */
+}
+
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) { }

^ permalink raw reply	[flat|nested] 9+ messages in thread
* [C PATCH] qualifiers of pointers to arrays in C2X [PR 98397]
@ 2020-12-21 10:28 Uecker, Martin
  2021-01-01  0:01 ` Joseph Myers
  0 siblings, 1 reply; 9+ messages in thread
From: Uecker, Martin @ 2020-12-21 10:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: joseph


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.


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);
+}

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2021-08-22 22:20 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-24  6:05 [C PATCH] qualifiers of pointers to arrays in C2X [PR 98397] Uecker, Martin
2021-06-11 19:25 ` Uecker, Martin
2021-08-01  7:20   ` PING^2 " Uecker, Martin
2021-08-12 16:58 ` Joseph Myers
2021-08-22 22:20   ` Uecker, Martin
  -- strict thread matches above, loose matches on Subject: below --
2020-12-21 10:28 Uecker, Martin
2021-01-01  0:01 ` Joseph Myers
2021-01-17 20:18   ` Uecker, Martin
2021-01-18 21:48     ` Joseph Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).