This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: PR 27665
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 14 Jun 2006 20:55:30 -0700
- Subject: C++ PATCH: PR 27665
- Reply-to: mark at codesourcery dot com
This patch fixes PR c++/27665, a tricky ICE on valid code.
When parsing something like:
+ class A<N>::B::C X;
we need to determine whether A<N> is the abstract definition of A, or
some instantiation thereof. For example, in the scope of A's
definition, A<N> is the abstract definition, while, in the body of:
template <int N> void f() { ... }
it's just an instantiation. This patch refines the test used to
determine which of these two situations we are in, and then adjusts a
couple of other spots as necessary.
Tested on x86_64-unknown-linux-gnu, applied to mainline. I'll
backport this to 4.1 shortly.
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
2006-06-14 Mark Mitchell <mark@codesourcery.com>
PR c++/27665
* parser.c (cp_parser_unqualified_id): Use constructor_name_p to
identify destructors.
(cp_parser_nested_name_specifier_opt): Remove invalid
optimization.
(cp_parser_template_id): Refine heuristic for determining whether
we are entering a scope.
2006-06-14 Mark Mitchell <mark@codesourcery.com>
PR c++/27665
* g++.dg/template/crash52.C: New test.
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 114635)
+++ gcc/cp/parser.c (working copy)
@@ -3374,12 +3374,12 @@ cp_parser_unqualified_id (cp_parser* par
qualifying_scope = parser->qualifying_scope;
/* If the name is of the form "X::~X" it's OK. */
+ token = cp_lexer_peek_token (parser->lexer);
if (scope && TYPE_P (scope)
- && cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ && token->type == CPP_NAME
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_OPEN_PAREN)
- && (cp_lexer_peek_token (parser->lexer)->value
- == TYPE_IDENTIFIER (scope)))
+ && constructor_name_p (token->value, scope))
{
cp_lexer_consume_token (parser->lexer);
return build_nt (BIT_NOT_EXPR, scope);
@@ -3550,20 +3550,6 @@ cp_parser_nested_name_specifier_opt (cp_
cp_token_position start = 0;
cp_token *token;
- /* If the next token corresponds to a nested name specifier, there
- is no need to reparse it. However, if CHECK_DEPENDENCY_P is
- false, it may have been true before, in which case something
- like `A<X>::B<Y>::C' may have resulted in a nested-name-specifier
- of `A<X>::', where it should now be `A<X>::B<Y>::'. So, when
- CHECK_DEPENDENCY_P is false, we have to fall through into the
- main loop. */
- if (check_dependency_p
- && cp_lexer_next_token_is (parser->lexer, CPP_NESTED_NAME_SPECIFIER))
- {
- cp_parser_pre_parsed_nested_name_specifier (parser);
- return parser->scope;
- }
-
/* Remember where the nested-name-specifier starts. */
if (cp_parser_uncommitted_to_tentative_parse_p (parser))
{
@@ -3663,6 +3649,8 @@ cp_parser_nested_name_specifier_opt (cp_
class-or-namespace-name. */
parser->scope = old_scope;
parser->qualifying_scope = saved_qualifying_scope;
+ if (cp_parser_uncommitted_to_tentative_parse_p (parser))
+ break;
/* If the next token is an identifier, and the one after
that is a `::', then any valid interpretation would have
found a class-or-namespace-name. */
@@ -8797,10 +8785,19 @@ cp_parser_template_id (cp_parser *parser
template_id = build_min_nt (TEMPLATE_ID_EXPR, template, arguments);
else if (DECL_CLASS_TEMPLATE_P (template)
|| DECL_TEMPLATE_TEMPLATE_PARM_P (template))
- template_id
- = finish_template_type (template, arguments,
- cp_lexer_next_token_is (parser->lexer,
- CPP_SCOPE));
+ {
+ bool entering_scope;
+ /* In "template <typename T> ... A<T>::", A<T> is the abstract A
+ template (rather than some instantiation thereof) only if
+ is not nested within some other construct. For example, in
+ "template <typename T> void f(T) { A<T>::", A<T> is just an
+ instantiation of A. */
+ entering_scope = (template_parm_scope_p ()
+ && cp_lexer_next_token_is (parser->lexer,
+ CPP_SCOPE));
+ template_id
+ = finish_template_type (template, arguments, entering_scope);
+ }
else
{
/* If it's not a class-template or a template-template, it should be
Index: gcc/testsuite/g++.dg/template/crash52.C
===================================================================
--- gcc/testsuite/g++.dg/template/crash52.C (revision 0)
+++ gcc/testsuite/g++.dg/template/crash52.C (revision 0)
@@ -0,0 +1,19 @@
+// PR c++/27665
+
+template<int> struct A
+{
+ struct B
+ {
+ struct C {};
+ };
+};
+
+template<int N> void foo()
+{
+ class A<N>::B::C X;
+}
+
+void bar()
+{
+ foo<0>();
+}