Hello,

Consider this invalid example given in the PR, where T is not defined:

     1  template<typename>
     2  struct X {
     3      using type = T;
     4  };

g++ yields the confusing diagnostics:

test.cc:3:10: error: expected nested-name-specifier before 'type'
    using type = T;
          ^
test.cc:3:10: error: using-declaration for non-member at class scope
test.cc:3:15: error: expected ';' before '=' token
    using type = T;
               ^
test.cc:3:15: error: expected unqualified-id before '=' token

I think this is because in cp_parser_member_declaration we tentatively
parse an alias declaration; we then have a somewhat meaningful
diagnostic which alas is not emitted because we are parsing
tentatively.  As the parsing didn't succeed (because the input is
invalid) we try to parse a using declaration, which fails as well; but
then the diagnostic emitted is the one for the failed attempt at
parsing a using declaration, not an alias declaration.  Oops.

The idea of this patch is to detect in advance that we want to parse
an alias declaration, parse it non-tentatively, and then if an error
arises, emit it.

I also changed cp_parser_alias_declaration to get out directly when it
detects that the type-id is invalid, rather than going on nonetheless
and emitting more (irrelevant) error diagnostics.

We are now getting the following output:

    test.cc:3:18: erreur: expected type-specifier before ‘T’
         using type = T;
                      ^
    test.cc:3:18: erreur: ‘T’ does not name a type

I don't really like the "before 'T'" there, but I think we maybe could
revisit the format of what cp_parser_error emits in general, now that
we have caret diagnostics;  We could maybe do away with the "before T"
altogether?

In the mean time, it seems to me that this patch brings an improvement
over what we already have in trunk, and the issue above could be
addressed separately.

Tested on x86_64-unknown-linux-gnu against trunk.

gcc/cp/

        * parser.c (cp_parser_expecting_alias_declaration_p): New static
        function.
        (cp_parser_block_declaration): Use it.
        (cp_parser_member_declaration): Likewise.  Don't parse the using
        declaration tentatively.
        (cp_parser_alias_declaration): Get out if the type-id is invalid.

gcc/testsuite/

        * g++.dg/cpp0x/alias-decl-23.C: New test.
---
 gcc/cp/parser.c                            | 38 +++++++++++++++++++++++-------
 gcc/testsuite/g++.dg/cpp0x/alias-decl-23.C |  7 ++++++
 2 files changed, 36 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-23.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e8c0378..cab2d09 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1937,6 +1937,8 @@ static bool cp_parser_using_declaration
   (cp_parser *, bool);
 static void cp_parser_using_directive
   (cp_parser *);
+static bool cp_parser_expecting_alias_declaration_p
+  (cp_parser*);
 static tree cp_parser_alias_declaration
   (cp_parser *);
 static void cp_parser_asm_definition
@@ -10292,11 +10294,7 @@ cp_parser_block_declaration (cp_parser *parser,
        cp_parser_using_directive (parser);
       /* If the second token after 'using' is '=', then we have an
         alias-declaration.  */
-      else if (cxx_dialect >= cxx0x
-              && token2->type == CPP_NAME
-              && ((cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ)
-                  || (cp_lexer_peek_nth_token (parser->lexer, 3)->keyword
-                      == RID_ATTRIBUTE)))
+      else if (cp_parser_expecting_alias_declaration_p (parser))
        cp_parser_alias_declaration (parser);
       /* Otherwise, it's a using-declaration.  */
       else
@@ -15079,6 +15077,24 @@ cp_parser_using_declaration (cp_parser* parser,
   return true;
 }
 
+/* Return TRUE if the coming tokens reasonably denote the beginning of
+   an alias declaration.  */
+
+static bool
+cp_parser_expecting_alias_declaration_p (cp_parser* parser)
+{
+  if (cxx_dialect < cxx0x)
+    return false;
+  cp_parser_parse_tentatively (parser);
+  cp_parser_require_keyword (parser, RID_USING, RT_USING);
+  cp_parser_identifier (parser);
+  cp_parser_attributes_opt (parser);
+  cp_parser_require (parser, CPP_EQ, RT_EQ);
+  bool is_ok = !cp_parser_error_occurred (parser);
+  cp_parser_abort_tentative_parse (parser);
+  return is_ok;
+}
+
 /* Parse an alias-declaration.
 
    alias-declaration:
@@ -15141,6 +15157,9 @@ cp_parser_alias_declaration (cp_parser* parser)
   if (parser->num_template_parameter_lists)
     parser->type_definition_forbidden_message = saved_message;
 
+  if (type == error_mark_node)
+    return error_mark_node;
+
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
 
   if (cp_parser_error_occurred (parser))
@@ -18849,10 +18868,11 @@ cp_parser_member_declaration (cp_parser* parser)
       else
        {
          tree decl;
-         cp_parser_parse_tentatively (parser);
-         decl = cp_parser_alias_declaration (parser);
-         if (cp_parser_parse_definitely (parser))
-           finish_member_declaration (decl);
+         if (cp_parser_expecting_alias_declaration_p (parser))
+           {
+             decl = cp_parser_alias_declaration (parser);
+             finish_member_declaration (decl);
+           }
          else
            cp_parser_using_declaration (parser,
                                         /*access_declaration_p=*/false);
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-23.C 
b/gcc/testsuite/g++.dg/cpp0x/alias-decl-23.C
new file mode 100644
index 0000000..086b5e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-23.C
@@ -0,0 +1,7 @@
+// Origin: PR c++/54401
+// { dg-do compile { target c++11 } }
+
+template<typename>
+struct X {
+    using type = T; // { dg-error "expected type-specifier|does not name a 
type" }
+};
-- 
1.7.11.4


-- 
                Dodji

Reply via email to