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.
commit 8a4393fa57437072d140065b5949e3aa9c4674d6
Author: Jason Merrill <ja...@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 "" }
}
};