PR c++/54401 - Confusing diagnostics about type-alias at class scope
authorDodji Seketeli <dodji@redhat.com>
Fri, 7 Dec 2012 17:05:19 +0000 (17:05 +0000)
committerDodji Seketeli <dodji@gcc.gnu.org>
Fri, 7 Dec 2012 17:05:19 +0000 (18:05 +0100)
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 commit the tentative parse when we see
the '=' token in the alias-declaration.  That way any error encounter
after that token is reported to the user.

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_alias_declaration): Commit to tentative
parse when see the '=' token.  Get out if the type-id is invalid.
Update function comment.
(cp_parser_member_declaration): Don't try to parse a using
declaration if we know that we expected an alias declaration; that
is, if we see the '=' token after the identifier.

gcc/testsuite/

* g++.dg/cpp0x/alias-decl-28.C: New test.
* g++.dg/cpp0x/alias-decl-16.C: Update.

From-SVN: r194306

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/alias-decl-16.C
gcc/testsuite/g++.dg/cpp0x/alias-decl-28.C [new file with mode: 0644]

index 7bec9ca96caa3da802335b9c88596a745cad58e5..81c20488a37dd6b237af869aef1fb9c0a53758e5 100644 (file)
@@ -1,3 +1,13 @@
+2012-12-07  Dodji Seketeli  <dodji@redhat.com>
+
+       PR c++/54401
+       * parser.c (cp_parser_alias_declaration): Commit to tentative
+       parse when see the '=' token.  Get out if the type-id is invalid.
+       Update function comment.
+       (cp_parser_member_declaration): Don't try to parse a using
+       declaration if we know that we expected an alias declaration; that
+       is, if we see the '=' token after the identifier.
+
 2012-12-06  Jason Merrill  <jason@redhat.com>
 
        PR c++/54325
index 3566d741f14c7b3a2f294f6c6b57eebc4e35170f..3dc2ec6316a0d7b439d36c0a5d7034bdac70ef08 100644 (file)
@@ -15295,6 +15295,8 @@ cp_parser_alias_declaration (cp_parser* parser)
   if (cp_parser_error_occurred (parser))
     return error_mark_node;
 
+  cp_parser_commit_to_tentative_parse (parser);
+
   /* Now we are going to parse the type-id of the declaration.  */
 
   /*
@@ -15324,10 +15326,19 @@ 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)
+    {
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+      return error_mark_node;
+    }
+
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
 
   if (cp_parser_error_occurred (parser))
-    return error_mark_node;
+    {
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+      return error_mark_node;
+    }
 
   /* A typedef-name can also be introduced by an alias-declaration. The
      identifier following the using keyword becomes a typedef-name. It has
@@ -19063,9 +19074,19 @@ cp_parser_member_declaration (cp_parser* parser)
       else
        {
          tree decl;
+         bool alias_decl_expected;
          cp_parser_parse_tentatively (parser);
          decl = cp_parser_alias_declaration (parser);
-         if (cp_parser_parse_definitely (parser))
+         /* Note that if we actually see the '=' token after the
+            identifier, cp_parser_alias_declaration commits the
+            tentative parse.  In that case, we really expects an
+            alias-declaration.  Otherwise, we expect a using
+            declaration.  */
+         alias_decl_expected =
+           !cp_parser_uncommitted_to_tentative_parse_p (parser);
+         cp_parser_parse_definitely (parser);
+
+         if (alias_decl_expected)
            finish_member_declaration (decl);
          else
            cp_parser_using_declaration (parser,
index d50d73b0e9d5bf978879b7e8743cdf073eea1eb5..1fd69fab38a69dcd866dc45e73ab0e6234841923 100644 (file)
@@ -1,3 +1,9 @@
+2012-12-07  Dodji Seketeli  <dodji@redhat.com>
+
+       PR c++/54401
+       * g++.dg/cpp0x/alias-decl-28.C: New test.
+       * g++.dg/cpp0x/alias-decl-16.C: Update.
+
 2012-12-07  Martin Jambor  <mjambor@suse.cz>
 
        PR tree-optimization/55590
index d66660a5f4e2473b92ac42c8fe578723888cb953..ce6ad0a62168b5b33f33324655389b36fa93d92f 100644 (file)
@@ -23,6 +23,6 @@ template<class T>
 using A3 =
     enum B3 {b = 0;}; //{ dg-error "types may not be defined in alias template" }
 
-A3<int> a3;
+A3<int> a3; // { dg-error "'A3' does not name a type" }
 
 int main() { }
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-28.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-28.C
new file mode 100644 (file)
index 0000000..086b5e5
--- /dev/null
@@ -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" }
+};