diff mbox

C++ PATCH for c++/56679 (sizeof... of template template parameter pack)

Message ID 515488BA.2000902@redhat.com
State New
Headers show

Commit Message

Jason Merrill March 28, 2013, 6:15 p.m. UTC
The only valid operand for sizeof... is a single identifier, so it 
doesn't really make sense to share code with other forms of sizeof.

Tested x86_64-pc-linux-gnu, applying to trunk.
diff mbox

Patch

commit 8a4393fa57437072d140065b5949e3aa9c4674d6
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Mar 27 17:20:41 2013 -0400

    	PR c++/56679
    	* parser.c (cp_parser_sizeof_pack): Split out from...
    	(cp_parser_sizeof_operand): ...here.  Require (id).

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 5e2a4e0..ec6eb08 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -22618,6 +22618,44 @@  cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
   pop_unparsed_function_queues (parser);
 }
 
+/* Subroutine of cp_parser_sizeof_operand, for handling C++11
+
+     sizeof ... ( identifier )
+
+   where the 'sizeof' token has already been consumed.  */
+
+static tree
+cp_parser_sizeof_pack (cp_parser *parser)
+{
+  /* Consume the `...'.  */
+  cp_lexer_consume_token (parser->lexer);
+  maybe_warn_variadic_templates ();
+
+  bool paren = cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN);
+  if (paren)
+    cp_lexer_consume_token (parser->lexer);
+  else
+    permerror (cp_lexer_peek_token (parser->lexer)->location,
+	       "%<sizeof...%> argument must be surrounded by parentheses");
+
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+  tree name = cp_parser_identifier (parser);
+  tree expr = cp_parser_lookup_name_simple (parser, name, token->location);
+  if (expr == error_mark_node)
+    cp_parser_name_lookup_error (parser, name, expr, NLE_NULL,
+				 token->location);
+  if (TREE_CODE (expr) == TYPE_DECL)
+    expr = TREE_TYPE (expr);
+  else if (TREE_CODE (expr) == CONST_DECL)
+    expr = DECL_INITIAL (expr);
+  expr = make_pack_expansion (expr);
+
+  if (paren)
+    cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+
+  return expr;
+}
+
 /* Parse the operand of `sizeof' (or a similar operator).  Returns
    either a TYPE or an expression, depending on the form of the
    input.  The KEYWORD indicates which kind of expression we have
@@ -22631,7 +22669,12 @@  cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
   char *tmp;
   bool saved_integral_constant_expression_p;
   bool saved_non_integral_constant_expression_p;
-  bool pack_expansion_p = false;
+
+  /* If it's a `...', then we are computing the length of a parameter
+     pack.  */
+  if (keyword == RID_SIZEOF
+      && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+    return cp_parser_sizeof_pack (parser);
 
   /* Types cannot be defined in a `sizeof' expression.  Save away the
      old message.  */
@@ -22650,19 +22693,6 @@  cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
     = parser->non_integral_constant_expression_p;
   parser->integral_constant_expression_p = false;
 
-  /* If it's a `...', then we are computing the length of a parameter
-     pack.  */
-  if (keyword == RID_SIZEOF
-      && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
-    {
-      /* Consume the `...'.  */
-      cp_lexer_consume_token (parser->lexer);
-      maybe_warn_variadic_templates ();
-
-      /* Note that this is an expansion.  */
-      pack_expansion_p = true;
-    }
-
   /* Do not actually evaluate the expression.  */
   ++cp_unevaluated_operand;
   ++c_inhibit_evaluation_warnings;
@@ -22702,9 +22732,6 @@  cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
 				 /*attrlist=*/NULL);
 	}
     }
-  else if (pack_expansion_p)
-    permerror (cp_lexer_peek_token (parser->lexer)->location,
-	       "%<sizeof...%> argument must be surrounded by parentheses");
 
   /* If the type-id production did not work out, then we must be
      looking at the unary-expression production.  */
@@ -22712,10 +22739,6 @@  cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
     expr = cp_parser_unary_expression (parser, /*address_p=*/false,
 				       /*cast_p=*/false, NULL);
 
-  if (pack_expansion_p)
-    /* Build a pack expansion. */
-    expr = make_pack_expansion (expr);
-
   /* Go back to evaluating expressions.  */
   --cp_unevaluated_operand;
   --c_inhibit_evaluation_warnings;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-sizeof1.C b/gcc/testsuite/g++.dg/cpp0x/variadic-sizeof1.C
new file mode 100644
index 0000000..2837c85
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-sizeof1.C
@@ -0,0 +1,11 @@ 
+// PR c++/56679
+// { dg-require-effective-target c++11 }
+
+template <template <typename> class... Args>
+struct Foo {
+  static const int value = sizeof...(Args);
+};
+
+template <typename> struct Bar { };
+
+const int test = Foo<Bar>::value;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic76.C b/gcc/testsuite/g++.dg/cpp0x/variadic76.C
index fb80244..ff0211d 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic76.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic76.C
@@ -4,8 +4,8 @@ 
 
 template<int... N> int foo ()
 {
-  return sizeof... (N ());	// { dg-error "cannot be used as a function" }
-  return sizeof... (N) ();	// { dg-error "cannot be used as a function" }
+  return sizeof... (N ());	// { dg-error "" }
+  return sizeof... (N) ();	// { dg-error "" }
 }
 
 int bar ()
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic77.C b/gcc/testsuite/g++.dg/cpp0x/variadic77.C
index 43f2d1e..8c6119f 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic77.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic77.C
@@ -12,7 +12,7 @@  template<int... M> struct S
 {
   template<int... N> static int foo ()
   {
-    return sizeof... (pair<M, N>);	// { dg-error "mismatched argument pack lengths" }
+    return sizeof... (pair<M, N>);	// { dg-error "" }
   }
 };