[PATCH] c++, v2: Implement DR2351 - void{} [PR102820]

Jakub Jelinek jakub@redhat.com
Thu Oct 28 11:26:34 GMT 2021


On Wed, Oct 27, 2021 at 04:58:53PM -0400, Jason Merrill wrote:
> On 10/21/21 04:42, Jakub Jelinek wrote:
> > Hi!
> > 
> > Here is an attempt to implement DR2351 - void{} - where void{} after
> > pack expansion is considered valid and the same thing as void().
> > For templates, dunno if we have some better way to check if a CONSTRUCTOR
> > might be empty after pack expansion.  Would that only if the constructor
> > only contains EXPR_PACK_EXPANSION elements and nothing else, or something
> > else too?
> 
> I think that's the only case.  For template args there's the
> pack_expansion_args_count function, but I don't think there's anything
> similar for constructor elts; please feel free to add it.

Ok.  But counting how many packs its CONSTRUCTOR_ELTS have and then comparing
that number against CONSTRUCTOR_NELTS seems to be unnecessarily expensive if
there are many elements, for the purpose the DR2351 code needs we can stop
as soon as we see first non-pack element.

So what about this if it passes bootstrap/regtest?

2021-10-28  Jakub Jelinek  <jakub@redhat.com>

	PR c++/102820
	* semantics.c (maybe_zero_constructor_nelts): New function.
	(finish_compound_literal): Implement DR2351 - void{}.
	If type is cv void and compound_literal has no elements, return
	void_node.  If type is cv void and compound_literal might have no
	elements after expansion, handle it like other dependent compound
	literals.

	* g++.dg/cpp0x/dr2351.C: New test.

--- gcc/cp/semantics.c.jj	2021-10-27 09:16:41.161600606 +0200
+++ gcc/cp/semantics.c	2021-10-28 13:06:59.325791588 +0200
@@ -3079,6 +3079,24 @@ finish_unary_op_expr (location_t op_loc,
   return result;
 }
 
+/* Return true if CONSTRUCTOR EXPR after pack expansion could have no
+   elements.  */
+
+static bool
+maybe_zero_constructor_nelts (tree expr)
+{
+  if (CONSTRUCTOR_NELTS (expr) == 0)
+    return true;
+  if (!processing_template_decl)
+    return false;
+  unsigned int i;
+  tree val;
+  FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), i, val)
+    if (!PACK_EXPANSION_P (val))
+      return false;
+  return true;
+}
+
 /* Finish a compound-literal expression or C++11 functional cast with aggregate
    initializer.  TYPE is the type to which the CONSTRUCTOR in COMPOUND_LITERAL
    is being cast.  */
@@ -3104,9 +3122,20 @@ finish_compound_literal (tree type, tree
 
   if (!TYPE_OBJ_P (type))
     {
-      if (complain & tf_error)
-	error ("compound literal of non-object type %qT", type);
-      return error_mark_node;
+      /* DR2351 */
+      if (VOID_TYPE_P (type) && CONSTRUCTOR_NELTS (compound_literal) == 0)
+	return void_node;
+      else if (VOID_TYPE_P (type)
+	       && processing_template_decl
+	       && maybe_zero_constructor_nelts (compound_literal))
+	/* If there are only packs in compound_literal, it could
+	   be void{} after pack expansion.  */;
+      else
+	{
+	  if (complain & tf_error)
+	    error ("compound literal of non-object type %qT", type);
+	  return error_mark_node;
+	}
     }
 
   if (template_placeholder_p (type))
--- gcc/testsuite/g++.dg/cpp0x/dr2351.C.jj	2021-10-28 12:59:27.987120315 +0200
+++ gcc/testsuite/g++.dg/cpp0x/dr2351.C	2021-10-28 13:15:20.532760871 +0200
@@ -0,0 +1,51 @@
+// DR2351
+// { dg-do compile { target c++11 } }
+
+void
+foo ()
+{
+  void{};
+  void();
+}
+
+template <class ...T>
+void
+bar (T... t)
+{
+  void{t...};
+  void(t...);
+}
+
+void
+baz ()
+{
+  bar ();
+}
+
+template <class ...T>
+void
+qux (T... t)
+{
+  void{t...};	// { dg-error "compound literal of non-object type" }
+}
+
+void
+corge ()
+{
+  qux (1, 2);
+}
+
+template <class ...T>
+void
+garply (T... t)
+{
+  void{t..., t..., t...};
+  void(t..., t..., t...);
+}
+
+template <class ...T>
+void
+grault (T... t)
+{
+  void{t..., 1};	// { dg-error "compound literal of non-object type" }
+}


	Jakub



More information about the Gcc-patches mailing list