PR c++/6709 (DR 743)
authorJason Merrill <jason@redhat.com>
Wed, 20 Jul 2011 14:21:05 +0000 (10:21 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 20 Jul 2011 14:21:05 +0000 (10:21 -0400)
PR c++/6709 (DR 743)
PR c++/42603 (DR 950)
gcc/cp/
* parser.c (token_is_decltype, cp_lexer_next_token_is_decltype): New.
(cp_parser_nested_name_specifier_opt): Allow decltype.
(cp_parser_qualifying_entity): Likewise.
(cp_parser_decltype): Replace source tokens with CPP_DECLTYPE.
(cp_parser_simple_type_specifier): Handle decltype as scope.
(cp_parser_base_specifier): Allow decltype.
(cp_parser_base_clause): Don't crash on null base.
* parser.h (CPP_KEYWORD, CPP_TEMPLATE_ID): Move to c-common.h.
(CPP_NESTED_NAME_SPECIFIER, N_CP_TTYPES): Likewise.
gcc/c-family/
* c-common.h (CPP_KEYWORD, CPP_TEMPLATE_ID): Move from cp/parser.h.
(CPP_NESTED_NAME_SPECIFIER, N_CP_TTYPES): Likewise.
(CPP_DECLTYPE): New.
* c-common.c (c_parse_error): Handle CPP_DECLTYPE.

From-SVN: r176513

gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/cp/parser.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/decltype21.C [new file with mode: 0644]

index 9ff311c90bb24c95cd44d7a50fa3b525982615b0..c5f2306ca62290dab967342c557fbe31f33fcb9f 100644 (file)
@@ -1,3 +1,12 @@
+2011-07-20  Jason Merrill  <jason@redhat.com>
+
+       PR c++/6709 (DR 743)
+       PR c++/42603 (DR 950)
+       * c-common.h (CPP_KEYWORD, CPP_TEMPLATE_ID): Move from cp/parser.h.
+       (CPP_NESTED_NAME_SPECIFIER, N_CP_TTYPES): Likewise.
+       (CPP_DECLTYPE): New.
+       * c-common.c (c_parse_error): Handle CPP_DECLTYPE.
+
 2011-07-19  Richard Guenther  <rguenther@suse.de>
 
        * c-common.c (pointer_int_sum): Use fold_build_pointer_plus.
index ecb0c8463e7627ff9363b8f02c3a5b8e9a28eafe..6078d948ae4284101dc6a64438dbd0b000b2485a 100644 (file)
@@ -8329,6 +8329,8 @@ c_parse_error (const char *gmsgid, enum cpp_ttype token_type,
     message = catenate_messages (gmsgid, " before %<#pragma%>");
   else if (token_type == CPP_PRAGMA_EOL)
     message = catenate_messages (gmsgid, " before end of line");
+  else if (token_type == CPP_DECLTYPE)
+    message = catenate_messages (gmsgid, " before %<decltype%>");
   else if (token_type < N_TTYPES)
     {
       message = catenate_messages (gmsgid, " before %qs token");
index a80c0eaec4093ad49ac89328a2f23825fdd96af1..13aae0f3ecc5a92d9e8622b7486fb2c615a0a404 100644 (file)
@@ -320,6 +320,30 @@ struct c_common_resword
   const unsigned int disable   : 16;
 };
 
+/* Extra cpp_ttype values for C++.  */
+
+/* A token type for keywords, as opposed to ordinary identifiers.  */
+#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
+
+/* A token type for template-ids.  If a template-id is processed while
+   parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token;
+   the value of the CPP_TEMPLATE_ID is whatever was returned by
+   cp_parser_template_id.  */
+#define CPP_TEMPLATE_ID ((enum cpp_ttype) (CPP_KEYWORD + 1))
+
+/* A token type for nested-name-specifiers.  If a
+   nested-name-specifier is processed while parsing tentatively, it is
+   replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the
+   CPP_NESTED_NAME_SPECIFIER is whatever was returned by
+   cp_parser_nested_name_specifier_opt.  */
+#define CPP_NESTED_NAME_SPECIFIER ((enum cpp_ttype) (CPP_TEMPLATE_ID + 1))
+
+/* A token type for pre-parsed C++0x decltype.  */
+#define CPP_DECLTYPE ((enum cpp_ttype) (CPP_NESTED_NAME_SPECIFIER + 1))
+
+/* The number of token types, including C++-specific ones.  */
+#define N_CP_TTYPES ((int) (CPP_DECLTYPE + 1))
+
 /* Disable mask.  Keywords are disabled if (reswords[i].disable &
    mask) is _true_.  Thus for keywords which are present in all
    languages the disable field is zero.  */
index 2f5be0ac1e53731283aa66c57f02d9035890f51e..37fa0522fc71246d8639de17c80b8a7ac1ecf65f 100644 (file)
@@ -1,4 +1,16 @@
-2011-07-19  Jason Merrill  <jason@redhat.com>
+2011-07-20  Jason Merrill  <jason@redhat.com>
+
+       PR c++/6709 (DR 743)
+       PR c++/42603 (DR 950)
+       * parser.c (token_is_decltype, cp_lexer_next_token_is_decltype): New.
+       (cp_parser_nested_name_specifier_opt): Allow decltype.
+       (cp_parser_qualifying_entity): Likewise.
+       (cp_parser_decltype): Replace source tokens with CPP_DECLTYPE.
+       (cp_parser_simple_type_specifier): Handle decltype as scope.
+       (cp_parser_base_specifier): Allow decltype.
+       (cp_parser_base_clause): Don't crash on null base.
+       * parser.h (CPP_KEYWORD, CPP_TEMPLATE_ID): Move to c-common.h.
+       (CPP_NESTED_NAME_SPECIFIER, N_CP_TTYPES): Likewise.
 
        PR c++/49785
        * pt.c (coerce_template_parms): Handle non-pack after pack.
index b928ef734973c5866a37ad644289a7ef106005b9..b8dc48e04ca15d86940f665559928528aa69974a 100644 (file)
@@ -663,6 +663,24 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
     }
 }
 
+/* Returns TRUE iff the token T begins a decltype type.  */
+
+static bool
+token_is_decltype (cp_token *t)
+{
+  return (t->keyword == RID_DECLTYPE
+         || t->type == CPP_DECLTYPE);
+}
+
+/* Returns TRUE iff the next token begins a decltype type.  */
+
+static bool
+cp_lexer_next_token_is_decltype (cp_lexer *lexer)
+{
+  cp_token *t = cp_lexer_peek_token (lexer);
+  return token_is_decltype (t);
+}
+
 /* Return a pointer to the Nth token in the token stream.  If N is 1,
    then this is precisely equivalent to cp_lexer_peek_token (except
    that it is not inline).  One would like to disallow that case, but
@@ -4313,6 +4331,9 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
       /* A template-id can start a nested-name-specifier.  */
       else if (token->type == CPP_TEMPLATE_ID)
        ;
+      /* DR 743: decltype can be used in a nested-name-specifier.  */
+      else if (token_is_decltype (token))
+       ;
       else
        {
          /* If the next token is not an identifier, then it is
@@ -4386,6 +4407,28 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
             class-or-namespace-name.  */
          parser->scope = old_scope;
          parser->qualifying_scope = saved_qualifying_scope;
+
+         /* If the next token is a decltype, and the one after that is a
+            `::', then the decltype has failed to resolve to a class or
+            enumeration type.  Give this error even when parsing
+            tentatively since it can't possibly be valid--and we're going
+            to replace it with a CPP_NESTED_NAME_SPECIFIER below, so we
+            won't get another chance.*/
+         if (cp_lexer_next_token_is (parser->lexer, CPP_DECLTYPE)
+             && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
+                 == CPP_SCOPE))
+           {
+             token = cp_lexer_consume_token (parser->lexer);
+             error_at (token->location, "decltype evaluates to %qT, "
+                       "which is not a class or enumeration type",
+                       token->u.value);
+             parser->scope = error_mark_node;
+             error_p = true;
+             /* As below.  */
+             success = true;
+             cp_lexer_consume_token (parser->lexer);
+           }
+
          if (cp_parser_uncommitted_to_tentative_parse_p (parser))
            break;
          /* If the next token is an identifier, and the one after
@@ -4585,6 +4628,19 @@ cp_parser_qualifying_entity (cp_parser *parser,
   bool only_class_p;
   bool successful_parse_p;
 
+  /* DR 743: decltype can appear in a nested-name-specifier.  */
+  if (cp_lexer_next_token_is_decltype (parser->lexer))
+    {
+      scope = cp_parser_decltype (parser);
+      if (TREE_CODE (scope) != ENUMERAL_TYPE
+         && !MAYBE_CLASS_TYPE_P (scope))
+       {
+         cp_parser_simulate_error (parser);
+         return error_mark_node;
+       }
+      return TYPE_NAME (scope);
+    }
+
   /* Before we try to parse the class-name, we must save away the
      current PARSER->SCOPE since cp_parser_class_name will destroy
      it.  */
@@ -10197,6 +10253,14 @@ cp_parser_decltype (cp_parser *parser)
   bool saved_integral_constant_expression_p;
   bool saved_non_integral_constant_expression_p;
   cp_token *id_expr_start_token;
+  cp_token *start_token = cp_lexer_peek_token (parser->lexer);
+
+  if (start_token->type == CPP_DECLTYPE)
+    {
+      /* Already parsed.  */
+      cp_lexer_consume_token (parser->lexer);
+      return start_token->u.value;
+    }
 
   /* Look for the `decltype' token.  */
   if (!cp_parser_require_keyword (parser, RID_DECLTYPE, RT_DECLTYPE))
@@ -10350,14 +10414,6 @@ cp_parser_decltype (cp_parser *parser)
   parser->non_integral_constant_expression_p
     = saved_non_integral_constant_expression_p;
 
-  if (expr == error_mark_node)
-    {
-      /* Skip everything up to the closing `)'.  */
-      cp_parser_skip_to_closing_parenthesis (parser, true, false,
-                                             /*consume_paren=*/true);
-      return error_mark_node;
-    }
-  
   /* Parse to the closing `)'.  */
   if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
     {
@@ -10366,8 +10422,17 @@ cp_parser_decltype (cp_parser *parser)
       return error_mark_node;
     }
 
-  return finish_decltype_type (expr, id_expression_or_member_access_p,
+  expr = finish_decltype_type (expr, id_expression_or_member_access_p,
                               tf_warning_or_error);
+
+  /* Replace the decltype with a CPP_DECLTYPE so we don't need to parse
+     it again.  */
+  start_token->type = CPP_DECLTYPE;
+  start_token->u.value = expr;
+  start_token->keyword = RID_MAX;
+  cp_lexer_purge_tokens_after (parser->lexer, start_token);
+
+  return expr;
 }
 
 /* Special member functions [gram.special] */
@@ -12679,15 +12744,13 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       break;
 
     case RID_DECLTYPE:
-      /* Parse the `decltype' type.  */
-      type = cp_parser_decltype (parser);
-
-      if (decl_specs)
-       cp_parser_set_decl_spec_type (decl_specs, type,
-                                     token->location,
-                                     /*user_defined_p=*/true);
-
-      return type;
+      /* Since DR 743, decltype can either be a simple-type-specifier by
+        itself or begin a nested-name-specifier.  Parsing it will replace
+        it with a CPP_DECLTYPE, so just rewind and let the CPP_DECLTYPE
+        handling below decide what to do.  */
+      cp_parser_decltype (parser);
+      cp_lexer_set_token_position (parser->lexer, token);
+      break;
 
     case RID_TYPEOF:
       /* Consume the `typeof' token.  */
@@ -12719,6 +12782,20 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       break;
     }
 
+  /* If token is an already-parsed decltype not followed by ::,
+     it's a simple-type-specifier.  */
+  if (token->type == CPP_DECLTYPE
+      && cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_SCOPE)
+    {
+      type = token->u.value;
+      if (decl_specs)
+       cp_parser_set_decl_spec_type (decl_specs, type,
+                                     token->location,
+                                     /*user_defined_p=*/true);
+      cp_lexer_consume_token (parser->lexer);
+      return type;
+    }
+
   /* If the type-specifier was for a built-in type, we're done.  */
   if (type)
     {
@@ -18232,12 +18309,11 @@ cp_parser_base_clause (cp_parser* parser)
         }
 
       /* Add BASE to the front of the list.  */
-      if (base != error_mark_node)
+      if (base && base != error_mark_node)
        {
           if (pack_expansion_p)
             /* Make this a pack expansion type. */
             TREE_VALUE (base) = make_pack_expansion (TREE_VALUE (base));
-          
 
           if (!check_for_bare_parameter_packs (TREE_VALUE (base)))
             {
@@ -18379,19 +18455,27 @@ cp_parser_base_specifier (cp_parser* parser)
   class_scope_p = (parser->scope && TYPE_P (parser->scope));
   template_p = class_scope_p && cp_parser_optional_template_keyword (parser);
 
-  /* Finally, look for the class-name.  */
-  type = cp_parser_class_name (parser,
-                              class_scope_p,
-                              template_p,
-                              typename_type,
-                              /*check_dependency_p=*/true,
-                              /*class_head_p=*/false,
-                              /*is_declaration=*/true);
+  if (!parser->scope
+      && cp_lexer_next_token_is_decltype (parser->lexer))
+    /* DR 950 allows decltype as a base-specifier.  */
+    type = cp_parser_decltype (parser);
+  else
+    {
+      /* Otherwise, look for the class-name.  */
+      type = cp_parser_class_name (parser,
+                                  class_scope_p,
+                                  template_p,
+                                  typename_type,
+                                  /*check_dependency_p=*/true,
+                                  /*class_head_p=*/false,
+                                  /*is_declaration=*/true);
+      type = TREE_TYPE (type);
+    }
 
   if (type == error_mark_node)
     return error_mark_node;
 
-  return finish_base_specifier (TREE_TYPE (type), access, virtual_p);
+  return finish_base_specifier (type, access, virtual_p);
 }
 
 /* Exception handling [gram.exception] */
index 31ff0d9f2b979197d4fe7b890874c92f438eadd8..33582fbc0f189579d6c90e8e78df265d6109244a 100644 (file)
@@ -23,25 +23,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "c-family/c-pragma.h"
 
-/* A token type for keywords, as opposed to ordinary identifiers.  */
-#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
-
-/* A token type for template-ids.  If a template-id is processed while
-   parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token;
-   the value of the CPP_TEMPLATE_ID is whatever was returned by
-   cp_parser_template_id.  */
-#define CPP_TEMPLATE_ID ((enum cpp_ttype) (CPP_KEYWORD + 1))
-
-/* A token type for nested-name-specifiers.  If a
-   nested-name-specifier is processed while parsing tentatively, it is
-   replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the
-   CPP_NESTED_NAME_SPECIFIER is whatever was returned by
-   cp_parser_nested_name_specifier_opt.  */
-#define CPP_NESTED_NAME_SPECIFIER ((enum cpp_ttype) (CPP_TEMPLATE_ID + 1))
-
-/* The number of token types, including C++-specific ones.  */
-#define N_CP_TTYPES ((int) (CPP_NESTED_NAME_SPECIFIER + 1))
-
 /* A token's value and its associated deferred access checks and
    qualifying scope.  */
 
index 1e2bc1c07cdee10ef095e36cbf1aa946246486c6..faa412beca01de94412895670b78f930863a3b27 100644 (file)
@@ -1,3 +1,9 @@
+2011-07-19  Jason Merrill  <jason@redhat.com>
+
+       PR c++/6709 (DR 743)
+       PR c++/42603 (DR 950)
+       * g++.dg/cpp0x/decltype21.C: New.
+
 2011-07-20  Richard Guenther  <rguenther@suse.de>
 
        PR middle-end/18908
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype21.C b/gcc/testsuite/g++.dg/cpp0x/decltype21.C
new file mode 100644 (file)
index 0000000..ee73bfb
--- /dev/null
@@ -0,0 +1,18 @@
+// PR c++/6709 (DR 743)
+// PR c++/42603 (DR 950)
+// { dg-options -std=c++0x }
+
+template <class T>
+T make();
+
+struct p { typedef int t; };
+struct c : decltype(make<p>()) {};
+
+decltype(make<p>())::t t;
+
+int f();
+decltype(f())::t t2;           // { dg-error "not a class" }
+
+struct D: decltype(f()) { };   // { dg-error "not a class" }
+
+// { dg-prune-output "expected initializer" }