2007-07-27 Douglas Gregor <doug.gregor@gmail.com>
authordgregor <dgregor@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 27 Jul 2007 17:43:05 +0000 (17:43 +0000)
committerdgregor <dgregor@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 27 Jul 2007 17:43:05 +0000 (17:43 +0000)
* typeck.c (structural_comptypes): Compare DECLTYPE_TYPE nodes.
* cp-tree.def (DECLTYPE_TYPE): New.
* error.c (dump_type): Dump DECLTYPE_TYPE nodes.
(dump_type_prefix): Ditto.
(dump_type_suffix): Ditto.
* tree.c (DECLTYPE_TYPE): Walk DECLTYPE_TYPE nodes.
* mangle.c (write_type): Handle DECLTYPE_TYPE.
* cp-tree.h (IS_AGGR_TYPE): DECLTYPE_TYPE nodes can be aggregate
types.
(DECLTYPE_TYPE_EXPR): New.
(DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P): New.
(finish_declared_type): Declare.
* cxx-pretty-print.c (pp_cxx_type_specifier_seq): Print
DECLTYPE_TYPE nodes.
(pp_cxx_type_id): Ditto.
* pt.c (for_each_template_parm_r): Walk DECLTYPE_TYPE children.
(tsubst): Substitute into a DECLTYPE_TYPE node.
(tsubst_copy): Ditto.
(unify): Cannot deduce anything from TYPEOF_TYPE or DECLTYPE_TYPE
nodes.
(dependent_type_p_r): DECLTYPE_TYPE types are always dependent.
* semantics.c (finish_typeof): TYPEOF_TYPE types need to use
structural equality (because we can't hash the expressions).
(finish_declared_type): New.
* lex.c (reswords): Add "decltype" keyword.
* parser.c cp_lexer_next_token_is_decl_specifier_keyword
(cp_parser_postfix_expression): Add member_access_only_p to
restrict postfix expression to member access expressions.
(cp_parser_unary_expression): Update call to
cp_parser_postfix_expression to reflect new parameter.
(cp_parser_declared_type): New.
(cp_parser_simple_type_specifier): Parse decltype types.

2007-07-27  Douglas Gregor  <doug.gregor@gmail.com>

       * c-common.h (enum rid): Add RID_DECLTYPE, update RID_LAST_CXX0X.

2007-07-27  Douglas Gregor  <doug.gregor@gmail.com>

* g++.dg/cpp0x/decltype1.C: New.
* g++.dg/cpp0x/decltype2.C: New.
* g++.dg/cpp0x/decltype3.C: New.
* g++.dg/cpp0x/decltype4.C: New.
* g++.dg/cpp0x/decltype5.C: New.
* g++.dg/cpp0x/decltype6.C: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@126991 138bc75d-0d04-0410-961f-82ee72b054a4

21 files changed:
gcc/ChangeLog
gcc/c-common.h
gcc/cp/ChangeLog
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/cxx-pretty-print.c
gcc/cp/error.c
gcc/cp/lex.c
gcc/cp/mangle.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/decltype1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/decltype2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/decltype3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/decltype4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/decltype5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/decltype6.C [new file with mode: 0644]

index a13f349..283c343 100644 (file)
@@ -1,3 +1,7 @@
+2007-07-27  Douglas Gregor  <doug.gregor@gmail.com>
+       
+       * c-common.h (enum rid): Add RID_DECLTYPE, update RID_LAST_CXX0X.
+
 2007-07-26  Kenneth Zadeck <zadeck@naturalbridge.com>
 
        PR middle-end/32749
index 5417c8b..cb2c56b 100644 (file)
@@ -101,7 +101,7 @@ enum rid
   RID_IS_UNION,
 
   /* C++0x */
-  RID_STATIC_ASSERT,
+  RID_STATIC_ASSERT, RID_DECLTYPE,
 
   /* Objective-C */
   RID_AT_ENCODE,   RID_AT_END,
@@ -119,7 +119,7 @@ enum rid
   RID_LAST_MODIFIER = RID_ONEWAY,
 
   RID_FIRST_CXX0X = RID_STATIC_ASSERT,
-  RID_LAST_CXX0X = RID_STATIC_ASSERT,
+  RID_LAST_CXX0X = RID_DECLTYPE,
   RID_FIRST_AT = RID_AT_ENCODE,
   RID_LAST_AT = RID_AT_IMPLEMENTATION,
   RID_FIRST_PQ = RID_IN,
index 3c7b8c6..5141298 100644 (file)
@@ -1,3 +1,38 @@
+2007-07-27  Douglas Gregor  <doug.gregor@gmail.com>
+
+       * typeck.c (structural_comptypes): Compare DECLTYPE_TYPE nodes.
+       * cp-tree.def (DECLTYPE_TYPE): New.
+       * error.c (dump_type): Dump DECLTYPE_TYPE nodes.
+       (dump_type_prefix): Ditto.
+       (dump_type_suffix): Ditto.
+       * tree.c (DECLTYPE_TYPE): Walk DECLTYPE_TYPE nodes.
+       * mangle.c (write_type): Handle DECLTYPE_TYPE.
+       * cp-tree.h (IS_AGGR_TYPE): DECLTYPE_TYPE nodes can be aggregate
+       types.
+       (DECLTYPE_TYPE_EXPR): New.
+       (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P): New.
+       (finish_declared_type): Declare.
+       * cxx-pretty-print.c (pp_cxx_type_specifier_seq): Print
+       DECLTYPE_TYPE nodes.
+       (pp_cxx_type_id): Ditto.
+       * pt.c (for_each_template_parm_r): Walk DECLTYPE_TYPE children.
+       (tsubst): Substitute into a DECLTYPE_TYPE node.
+       (tsubst_copy): Ditto.
+       (unify): Cannot deduce anything from TYPEOF_TYPE or DECLTYPE_TYPE
+       nodes.
+       (dependent_type_p_r): DECLTYPE_TYPE types are always dependent.
+       * semantics.c (finish_typeof): TYPEOF_TYPE types need to use
+       structural equality (because we can't hash the expressions).
+       (finish_declared_type): New.
+       * lex.c (reswords): Add "decltype" keyword.
+       * parser.c cp_lexer_next_token_is_decl_specifier_keyword
+       (cp_parser_postfix_expression): Add member_access_only_p to
+       restrict postfix expression to member access expressions.
+       (cp_parser_unary_expression): Update call to
+       cp_parser_postfix_expression to reflect new parameter.
+       (cp_parser_declared_type): New.
+       (cp_parser_simple_type_specifier): Parse decltype types.
+
 2007-07-27  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/32346
index a0feb30..3dd6646 100644 (file)
@@ -427,6 +427,13 @@ DEFTREECODE (ARGUMENT_PACK_SELECT, "argument_pack_select", tcc_exceptional, 0)
 /* Represents a trait expression during template expansion.  */
 DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0)
 
+/* The declared type of an expression.  This is a C++0x extension.
+   DECLTYPE_TYPE_EXPR is the expression whose type we are computing.
+   DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P states whether the
+   expression was parsed as an id-expression or a member access
+   expression. When false, it was parsed as a full expression.  */
+DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0)
+
 /*
 Local variables:
 mode:c
index e440171..52cd6ae 100644 (file)
@@ -977,6 +977,7 @@ enum languages { lang_c, lang_cplusplus, lang_java };
    || TREE_CODE (T) == TYPENAME_TYPE                   \
    || TREE_CODE (T) == TYPEOF_TYPE                     \
    || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM    \
+   || TREE_CODE (T) == DECLTYPE_TYPE                   \
    || TYPE_LANG_FLAG_5 (T))
 
 /* Set IS_AGGR_TYPE for T to VAL.  T must be a class, struct, or
@@ -2921,6 +2922,15 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 /* The expression in question for a TYPEOF_TYPE.  */
 #define TYPEOF_TYPE_EXPR(NODE) (TYPEOF_TYPE_CHECK (NODE))->type.values
 
+/* The expression in question for a DECLTYPE_TYPE.  */
+#define DECLTYPE_TYPE_EXPR(NODE) (DECLTYPE_TYPE_CHECK (NODE))->type.values
+
+/* Whether the DECLTYPE_TYPE_EXPR of NODE was originally parsed as an
+   id-expression or a member-access expression. When false, it was
+   parsed as a full expression.  */
+#define DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P(NODE) \
+  (DECLTYPE_TYPE_CHECK (NODE))->type.string_flag
+
 /* Nonzero for VAR_DECL and FUNCTION_DECL node means that `extern' was
    specified in its declaration.  This can also be set for an
    erroneously declared PARM_DECL.  */
@@ -4657,6 +4667,7 @@ extern bool cxx_omp_privatize_by_reference        (tree);
 extern tree baselink_for_fns                    (tree);
 extern void finish_static_assert                (tree, tree, location_t,
                                                  bool);
+extern tree finish_decltype_type                (tree, bool);
 extern tree finish_trait_expr                  (enum cp_trait_kind, tree, tree);
 
 /* in tree.c */
index ac75e1d..9717969 100644 (file)
@@ -1198,6 +1198,13 @@ pp_cxx_type_specifier_seq (cxx_pretty_printer *pp, tree t)
       pp_cxx_nested_name_specifier (pp, TYPE_METHOD_BASETYPE (t));
       break;
 
+    case DECLTYPE_TYPE:
+      pp_cxx_identifier (pp, "decltype");
+      pp_cxx_left_paren (pp);
+      pp_cxx_expression (pp, DECLTYPE_TYPE_EXPR (t));
+      pp_cxx_right_paren (pp);
+      break;
+
     default:
       if (!(TREE_CODE (t) == FUNCTION_DECL && DECL_CONSTRUCTOR_P (t)))
        pp_c_specifier_qualifier_list (pp_c_base (pp), t);
@@ -1581,6 +1588,7 @@ pp_cxx_type_id (cxx_pretty_printer *pp, tree t)
     case TEMPLATE_PARM_INDEX:
     case TEMPLATE_DECL:
     case TYPEOF_TYPE:
+    case DECLTYPE_TYPE:
     case TEMPLATE_ID_EXPR:
       pp_cxx_type_specifier_seq (pp, t);
       break;
index 7e4828c..7df9256 100644 (file)
@@ -408,6 +408,14 @@ dump_type (tree t, int flags)
       }
       break;
 
+    case DECLTYPE_TYPE:
+      pp_cxx_identifier (cxx_pp, "decltype");
+      pp_cxx_whitespace (cxx_pp);
+      pp_cxx_left_paren (cxx_pp);
+      dump_expr (DECLTYPE_TYPE_EXPR (t), flags & ~TFF_EXPR_IN_PARENS);
+      pp_cxx_right_paren (cxx_pp);
+      break;
+
     default:
       pp_unsupported_tree (cxx_pp, t);
       /* Fall through to error.  */
@@ -611,6 +619,7 @@ dump_type_prefix (tree t, int flags)
     case COMPLEX_TYPE:
     case VECTOR_TYPE:
     case TYPEOF_TYPE:
+    case DECLTYPE_TYPE:
       dump_type (t, flags);
       pp_base (cxx_pp)->padding = pp_before;
       break;
@@ -707,6 +716,7 @@ dump_type_suffix (tree t, int flags)
     case COMPLEX_TYPE:
     case VECTOR_TYPE:
     case TYPEOF_TYPE:
+    case DECLTYPE_TYPE:
       break;
 
     default:
index f1dc864..6aefb47 100644 (file)
@@ -197,6 +197,7 @@ static const struct resword reswords[] =
   { "__complex__",     RID_COMPLEX,    0 },
   { "__const",         RID_CONST,      0 },
   { "__const__",       RID_CONST,      0 },
+  { "__decltype",       RID_DECLTYPE,   0 },
   { "__extension__",   RID_EXTENSION,  0 },
   { "__func__",                RID_C99_FUNCTION_NAME,  0 },
   { "__has_nothrow_assign", RID_HAS_NOTHROW_ASSIGN, 0 },
@@ -244,6 +245,7 @@ static const struct resword reswords[] =
   { "const",           RID_CONST,      0 },
   { "const_cast",      RID_CONSTCAST,  0 },
   { "continue",                RID_CONTINUE,   0 },
+  { "decltype",         RID_DECLTYPE,   D_CXX0X },
   { "default",         RID_DEFAULT,    0 },
   { "delete",          RID_DELETE,     0 },
   { "do",              RID_DO,         0 },
index d708a2b..7318f49 100644 (file)
@@ -1544,6 +1544,9 @@ write_local_name (const tree function, const tree local_entity,
    C++0x extensions
 
      <type> ::= RR <type>   # rvalue reference-to
+     <type> ::= Dt <expression> # decltype of an id-expression or 
+                                # class member access
+     <type> ::= DT <expression> # decltype of an expression
 
    TYPE is a type node.  */
 
@@ -1674,6 +1677,16 @@ write_type (tree type)
               write_type (PACK_EXPANSION_PATTERN (type));
               break;
 
+            case DECLTYPE_TYPE:
+              write_char ('D');
+              if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type))
+                write_char ('t');
+              else
+                write_char ('T');
+              write_expression (DECLTYPE_TYPE_EXPR (type));
+              write_char ('E');
+              break;
+
            default:
              gcc_unreachable ();
            }
index b8d2b15..a7190cb 100644 (file)
@@ -577,6 +577,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
       /* GNU extensions.  */ 
     case RID_ATTRIBUTE:
     case RID_TYPEOF:
+      /* C++0x extensions.  */
+    case RID_DECLTYPE:
       return true;
 
     default:
@@ -1582,7 +1584,7 @@ static tree cp_parser_nested_name_specifier
 static tree cp_parser_class_or_namespace_name
   (cp_parser *, bool, bool, bool, bool, bool);
 static tree cp_parser_postfix_expression
-  (cp_parser *, bool, bool);
+  (cp_parser *, bool, bool, bool);
 static tree cp_parser_postfix_open_square_expression
   (cp_parser *, tree, bool);
 static tree cp_parser_postfix_dot_deref_expression
@@ -1707,6 +1709,8 @@ static void cp_parser_linkage_specification
   (cp_parser *);
 static void cp_parser_static_assert
   (cp_parser *, bool);
+static tree cp_parser_decltype
+  (cp_parser *);
 
 /* Declarators [gram.dcl.decl] */
 
@@ -4254,15 +4258,20 @@ cp_parser_class_or_namespace_name (cp_parser *parser,
    `&' operator.  CAST_P is true if this expression is the target of a
    cast.
 
+   If MEMBER_ACCESS_ONLY_P, we only allow postfix expressions that are
+   class member access expressions [expr.ref].
+
    Returns a representation of the expression.  */
 
 static tree
-cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
+cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
+                              bool member_access_only_p)
 {
   cp_token *token;
   enum rid keyword;
   cp_id_kind idk = CP_ID_KIND_NONE;
   tree postfix_expression = NULL_TREE;
+  bool is_member_access = false;
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
@@ -4513,6 +4522,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
                                                        postfix_expression,
                                                        false);
          idk = CP_ID_KIND_NONE;
+          is_member_access = false;
          break;
 
        case CPP_OPEN_PAREN:
@@ -4524,6 +4534,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
            bool saved_non_integral_constant_expression_p = false;
            tree args;
 
+            is_member_access = false;
+
            is_builtin_constant_p
              = DECL_IS_BUILTIN_CONSTANT_P (postfix_expression);
            if (is_builtin_constant_p)
@@ -4669,6 +4681,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
            = cp_parser_postfix_dot_deref_expression (parser, token->type,
                                                      postfix_expression,
                                                      false, &idk);
+
+          is_member_access = true;
          break;
 
        case CPP_PLUS_PLUS:
@@ -4684,6 +4698,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
                                                          "an increment"))
            postfix_expression = error_mark_node;
          idk = CP_ID_KIND_NONE;
+          is_member_access = false;
          break;
 
        case CPP_MINUS_MINUS:
@@ -4699,10 +4714,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
                                                          "a decrement"))
            postfix_expression = error_mark_node;
          idk = CP_ID_KIND_NONE;
+          is_member_access = false;
          break;
 
        default:
-         return postfix_expression;
+          if (member_access_only_p)
+            return is_member_access? postfix_expression : error_mark_node;
+          else
+            return postfix_expression;
        }
     }
 
@@ -5341,7 +5360,8 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p)
       return expression;
     }
 
-  return cp_parser_postfix_expression (parser, address_p, cast_p);
+  return cp_parser_postfix_expression (parser, address_p, cast_p,
+                                       /*member_access_only_p=*/false);
 }
 
 /* Returns ERROR_MARK if TOKEN is not a unary-operator.  If TOKEN is a
@@ -8371,6 +8391,164 @@ cp_parser_static_assert(cp_parser *parser, bool member_p)
   finish_static_assert (condition, message, saved_loc, member_p);
 }
 
+/* Parse a `decltype' type. Returns the type. 
+
+   simple-type-specifier:
+     decltype ( expression )  */
+
+static tree
+cp_parser_decltype (cp_parser *parser)
+{
+  tree expr;
+  bool id_expression_or_member_access_p = false;
+  const char *saved_message;
+  bool saved_integral_constant_expression_p;
+  bool saved_non_integral_constant_expression_p;
+
+  /* Look for the `decltype' token.  */
+  if (!cp_parser_require_keyword (parser, RID_DECLTYPE, "`decltype'"))
+    return error_mark_node;
+
+  /* Types cannot be defined in a `decltype' expression.  Save away the
+     old message.  */
+  saved_message = parser->type_definition_forbidden_message;
+
+  /* And create the new one.  */
+  parser->type_definition_forbidden_message
+    = "types may not be defined in `decltype' expressions";
+
+  /* The restrictions on constant-expressions do not apply inside
+     decltype expressions.  */
+  saved_integral_constant_expression_p
+    = parser->integral_constant_expression_p;
+  saved_non_integral_constant_expression_p
+    = parser->non_integral_constant_expression_p;
+  parser->integral_constant_expression_p = false;
+
+  /* Do not actually evaluate the expression.  */
+  ++skip_evaluation;
+
+  /* Parse the opening `('.  */
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+  
+  /* First, try parsing an id-expression.  */
+  cp_parser_parse_tentatively (parser);
+  expr = cp_parser_id_expression (parser,
+                                  /*template_keyword_p=*/false,
+                                  /*check_dependency_p=*/true,
+                                  /*template_p=*/NULL,
+                                  /*declarator_p=*/false,
+                                  /*optional_p=*/false);
+
+  if (!cp_parser_error_occurred (parser) && expr != error_mark_node)
+    {
+      bool non_integral_constant_expression_p = false;
+      tree id_expression = expr;
+      cp_id_kind idk;
+      const char *error_msg;
+
+      /* Lookup the name we got back from the id-expression.  */
+      expr = cp_parser_lookup_name (parser, expr,
+                                    none_type,
+                                    /*is_template=*/false,
+                                    /*is_namespace=*/false,
+                                    /*check_dependency=*/true,
+                                    /*ambiguous_decls=*/NULL);
+      
+      if (expr 
+          && expr != error_mark_node
+          && TREE_CODE (expr) != TEMPLATE_ID_EXPR
+          && TREE_CODE (expr) != TYPE_DECL
+          && cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN)
+        {
+          /* Complete lookup of the id-expression.  */
+          expr = (finish_id_expression
+                  (id_expression, expr, parser->scope, &idk,
+                   /*integral_constant_expression_p=*/false,
+                   /*allow_non_integral_constant_expression_p=*/true,
+                   &non_integral_constant_expression_p,
+                   /*template_p=*/false,
+                   /*done=*/true,
+                   /*address_p=*/false,
+                   /*template_arg_p=*/false,
+                   &error_msg));
+
+          if (expr == error_mark_node)
+            /* We found an id-expression, but it was something that we
+               should not have found. This is an error, not something
+               we can recover from, so note that we found an
+               id-expression and we'll recover as gracefully as
+               possible.  */
+            id_expression_or_member_access_p = true;
+        }
+
+      if (expr 
+          && expr != error_mark_node
+          && cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN)
+        /* We have an id-expression.  */
+        id_expression_or_member_access_p = true;
+    }
+
+  if (!id_expression_or_member_access_p)
+    {
+      /* Abort the id-expression parse.  */
+      cp_parser_abort_tentative_parse (parser);
+
+      /* Parsing tentatively, again.  */
+      cp_parser_parse_tentatively (parser);
+
+      /* Parse a class member access.  */
+      expr = cp_parser_postfix_expression (parser, /*address_p=*/false,
+                                           /*cast_p=*/false,
+                                           /*member_access_only_p=*/true);
+
+      if (expr 
+          && expr != error_mark_node
+          && cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN)
+        /* We have an id-expression.  */
+        id_expression_or_member_access_p = true;
+    }
+
+  if (id_expression_or_member_access_p)
+    /* We have parsed the complete id-expression or member access.  */
+    cp_parser_parse_definitely (parser);
+  else
+    {
+      /* Abort our attempt to parse an id-expression or member access
+         expression.  */
+      cp_parser_abort_tentative_parse (parser);
+
+      /* Parse a full expression.  */
+      expr = cp_parser_expression (parser, /*cast_p=*/false);
+    }
+
+  /* Go back to evaluating expressions.  */
+  --skip_evaluation;
+
+  /* Restore the old message and the integral constant expression
+     flags.  */
+  parser->type_definition_forbidden_message = saved_message;
+  parser->integral_constant_expression_p
+    = saved_integral_constant_expression_p;
+  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, "`)'"))
+    cp_parser_skip_to_closing_parenthesis (parser, true, false,
+                                          /*consume_paren=*/true);
+
+  return finish_decltype_type (expr, id_expression_or_member_access_p);
+}
+
 /* Special member functions [gram.special] */
 
 /* Parse a conversion-function-id.
@@ -10438,6 +10616,11 @@ cp_parser_type_specifier (cp_parser* parser,
      double
      void
 
+   C++0x Extension:
+
+   simple-type-specifier:
+     decltype ( expression )   
+
    GNU Extension:
 
    simple-type-specifier:
@@ -10507,6 +10690,16 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       type = void_type_node;
       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,
+                                     /*user_defined_p=*/true);
+
+      return type;
+
     case RID_TYPEOF:
       /* Consume the `typeof' token.  */
       cp_lexer_consume_token (parser->lexer);
index fc5af16..d05bfd2 100644 (file)
@@ -9058,6 +9058,22 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
                                             complain);
       }
 
+    case DECLTYPE_TYPE:
+      {
+       tree type;
+
+       type = 
+          finish_decltype_type (tsubst_expr 
+                                (DECLTYPE_TYPE_EXPR (t), args,
+                                 complain, in_decl,
+                                 /*integral_constant_expression_p=*/false),
+                                DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t));
+       return cp_build_qualified_type_real (type,
+                                            cp_type_quals (t)
+                                            | cp_type_quals (type),
+                                            complain);
+      }
+
     case TYPE_ARGUMENT_PACK:
     case NONTYPE_ARGUMENT_PACK:
       {
@@ -9621,6 +9637,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     case TYPENAME_TYPE:
     case UNBOUND_CLASS_TEMPLATE:
     case TYPEOF_TYPE:
+    case DECLTYPE_TYPE:
     case TYPE_DECL:
       return tsubst (t, args, complain, in_decl);
 
@@ -12824,6 +12841,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
       break;
 
+    case TYPEOF_TYPE:
+    case DECLTYPE_TYPE:
+      /* Cannot deduce anything from TYPEOF_TYPE or DECLTYPE_TYPE
+         nodes.  */
+      return 0;
+
     default:
       gcc_assert (EXPR_P (parm));
 
@@ -14888,10 +14911,11 @@ dependent_type_p_r (tree type)
               (INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)))))
     return true;
 
-  /* All TYPEOF_TYPEs are dependent; if the argument of the `typeof'
-     expression is not type-dependent, then it should already been
-     have resolved.  */
-  if (TREE_CODE (type) == TYPEOF_TYPE)
+  /* All TYPEOF_TYPEs and DECLTYPE_TYPEs are dependent; if the
+     argument of the `typeof' expression is not type-dependent, then
+     it should already been have resolved.  */
+  if (TREE_CODE (type) == TYPEOF_TYPE
+      || TREE_CODE (type) == DECLTYPE_TYPE)
     return true;
 
   /* A template argument pack is dependent if any of its packed
index 6b0d407..b03ec2f 100644 (file)
@@ -2935,6 +2935,7 @@ finish_typeof (tree expr)
     {
       type = make_aggr_type (TYPEOF_TYPE);
       TYPEOF_TYPE_EXPR (type) = expr;
+      SET_TYPE_STRUCTURAL_EQUALITY (type);
 
       return type;
     }
@@ -4036,6 +4037,169 @@ finish_static_assert (tree condition, tree message, location_t location,
       input_location = saved_loc;
     }
 }
+\f
+/* Implements the C++0x decltype keyword. Returns the type of EXPR,
+   suitable for use as a type-specifier.
+
+   ID_EXPRESSION_OR_MEMBER_ACCESS_P is true when EXPR was parsed as an
+   id-expression or a class member access, FALSE when it was parsed as
+   a full expression.  */
+tree
+finish_decltype_type (tree expr, bool id_expression_or_member_access_p)
+{
+  tree orig_expr = expr;
+  tree type;
+
+  if (type_dependent_expression_p (expr))
+    {
+      type = make_aggr_type (DECLTYPE_TYPE);
+      DECLTYPE_TYPE_EXPR (type) = expr;
+      DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type)
+        = id_expression_or_member_access_p;
+      SET_TYPE_STRUCTURAL_EQUALITY (type);
+
+      return type;
+    }
+
+  /* The type denoted by decltype(e) is defined as follows:  */
+
+  if (id_expression_or_member_access_p)
+    {
+      /* If e is an id-expression or a class member access (5.2.5
+         [expr.ref]), decltype(e) is defined as the type of the entity
+         named by e. If there is no such entity, or e names a set of
+         overloaded functions, the program is ill-formed.  */
+      if (TREE_CODE (expr) == IDENTIFIER_NODE)
+        expr = lookup_name (expr);
+
+      if (TREE_CODE (expr) == INDIRECT_REF)
+        /* This can happen when the expression is, e.g., "a.b". Just
+           look at the underlying operand.  */
+        expr = TREE_OPERAND (expr, 0);
+
+      if (TREE_CODE (expr) == OFFSET_REF
+          || TREE_CODE (expr) == MEMBER_REF)
+        /* We're only interested in the field itself. If it is a
+           BASELINK, we will need to see through it in the next
+           step.  */
+        expr = TREE_OPERAND (expr, 1);
+
+      if (TREE_CODE (expr) == BASELINK)
+        /* See through BASELINK nodes to the underlying functions.  */
+        expr = BASELINK_FUNCTIONS (expr);
+
+      if (TREE_CODE (expr) == OVERLOAD)
+        {
+          if (OVL_CHAIN (expr))
+            {
+              error ("%qE refers to a set of overloaded functions", orig_expr);
+              return error_mark_node;
+            }
+          else
+            /* An overload set containing only one function: just look
+               at that function.  */
+            expr = OVL_FUNCTION (expr);
+        }
+
+      switch (TREE_CODE (expr))
+        {
+        case FIELD_DECL:
+          if (DECL_C_BIT_FIELD (expr))
+            {
+              type = DECL_BIT_FIELD_TYPE (expr);
+              break;
+            }
+          /* Fall through for fields that aren't bitfields.  */
+
+        case FUNCTION_DECL:
+        case VAR_DECL:
+        case CONST_DECL:
+        case PARM_DECL:
+        case RESULT_DECL:
+          type = TREE_TYPE (expr);
+          break;
+
+        case ERROR_MARK:
+          type = error_mark_node;
+          break;
+
+        case COMPONENT_REF:
+          type = is_bitfield_expr_with_lowered_type (expr);
+          if (!type)
+            type = TREE_TYPE (TREE_OPERAND (expr, 1));
+          break;
+
+        case BIT_FIELD_REF:
+          gcc_unreachable ();
+
+        case INTEGER_CST:
+          /* We can get here when the id-expression refers to an
+             enumerator.  */
+          type = TREE_TYPE (expr);
+          break;
+
+        default:
+          gcc_assert (TYPE_P (expr) || DECL_P (expr));
+          error ("argument to decltype must be an expression");
+          return error_mark_node;
+        }
+    }
+  else
+    {
+      tree fndecl;
+
+      if (TREE_CODE (expr) == CALL_EXPR
+          && (fndecl = get_callee_fndecl (expr))
+          && (fndecl != error_mark_node))
+        /* If e is a function call (5.2.2 [expr.call]) or an
+           invocation of an overloaded operator (parentheses around e
+           are ignored), decltype(e) is defined as the return type of
+           that function.  */
+        type = TREE_TYPE (TREE_TYPE (fndecl));
+      else 
+        {
+          type = is_bitfield_expr_with_lowered_type (expr);
+          if (type)
+            {
+              /* Bitfields are special, because their type encodes the
+                 number of bits they store.  If the expression referenced a
+                 bitfield, TYPE now has the declared type of that
+                 bitfield.  */
+              type = cp_build_qualified_type (type, 
+                                              cp_type_quals (TREE_TYPE (expr)));
+              
+              if (real_lvalue_p (expr))
+                type = build_reference_type (type);
+            }
+          else
+            {
+              /* Otherwise, where T is the type of e, if e is an lvalue,
+                 decltype(e) is defined as T&, otherwise decltype(e) is
+                 defined as T.  */
+              type = TREE_TYPE (expr);
+              if (expr == current_class_ptr)
+                /* If the expression is just "this", we want the
+                   cv-unqualified pointer for the "this" type.  */
+                type = TYPE_MAIN_VARIANT (type);
+              else if (real_lvalue_p (expr))
+                {
+                  if (TREE_CODE (type) != REFERENCE_TYPE)
+                    type = build_reference_type (type);
+                }
+              else
+                type = non_reference (type);
+            }
+        }
+    }
+
+  if (!type || type == unknown_type_node)
+    {
+      error ("type of %qE is unknown", expr);
+      return error_mark_node;
+    }
+
+  return type;
+}
 
 /* Called from trait_expr_value to evaluate either __has_nothrow_assign or 
    __has_nothrow_copy, depending on assign_p.  */
index 772df4c..9757363 100644 (file)
@@ -2380,6 +2380,12 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
       *walk_subtrees_p = 0;
       break;
 
+    case DECLTYPE_TYPE:
+      WALK_SUBTREE (DECLTYPE_TYPE_EXPR (*tp));
+      *walk_subtrees_p = 0;
+      break;
+
     default:
       return NULL_TREE;
     }
index 51deeb2..65371c7 100644 (file)
@@ -1080,6 +1080,14 @@ structural_comptypes (tree t1, tree t2, int strict)
       return same_type_p (PACK_EXPANSION_PATTERN (t1), 
                           PACK_EXPANSION_PATTERN (t2));
 
+    case DECLTYPE_TYPE:
+      if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
+          != DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2)
+          || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), 
+                             DECLTYPE_TYPE_EXPR (t2)))
+        return false;
+      break;
+
     default:
       return false;
     }
index 9b75942..c37bd1d 100644 (file)
@@ -1,3 +1,12 @@
+2007-07-27  Douglas Gregor  <doug.gregor@gmail.com>
+
+       * g++.dg/cpp0x/decltype1.C: New.
+       * g++.dg/cpp0x/decltype2.C: New.
+       * g++.dg/cpp0x/decltype3.C: New.
+       * g++.dg/cpp0x/decltype4.C: New.
+       * g++.dg/cpp0x/decltype5.C: New.
+       * g++.dg/cpp0x/decltype6.C: New.
+
 2007-07-27  Rask Ingemann Lambertsen  <rask@sygehus.dk>
 
        * gcc.dg/torture/pr27743.c (bar): Use an integer of exactly 32 bits
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype1.C b/gcc/testsuite/g++.dg/cpp0x/decltype1.C
new file mode 100644 (file)
index 0000000..447af54
--- /dev/null
@@ -0,0 +1,28 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T, typename U> 
+struct is_same 
+{
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+  static const bool value = true;
+};
+
+const int& foo(); 
+int i; 
+struct A { double x; };
+const A* a = new A(); 
+
+static_assert(is_same<decltype(foo()), const int&>::value,
+              "type should be const int&");
+static_assert(is_same<decltype(i), int>::value,
+              "type should be int");
+static_assert(is_same<decltype(a->x), double>::value,
+              "type should be double");
+static_assert(is_same<decltype((a->x)), const double&>::value,
+              "type should be const double&");
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype2.C b/gcc/testsuite/g++.dg/cpp0x/decltype2.C
new file mode 100644 (file)
index 0000000..65549b4
--- /dev/null
@@ -0,0 +1,59 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T, typename U> 
+struct is_same 
+{
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+  static const bool value = true;
+};
+
+#define CHECK_DECLTYPE(DECLTYPE,RESULT) \
+  static_assert(is_same< DECLTYPE , RESULT >::value, #RESULT)
+
+struct A {};
+
+int a; 
+int& b = a; 
+const int& c = a; 
+const int d = 5; 
+const A e = A(); 
+CHECK_DECLTYPE(decltype(a), int);
+CHECK_DECLTYPE(decltype(b), int&); 
+CHECK_DECLTYPE(decltype(c), const int&); 
+CHECK_DECLTYPE(decltype(d), const int); 
+CHECK_DECLTYPE(decltype(e), const A); 
+
+CHECK_DECLTYPE(decltype(a), int);
+CHECK_DECLTYPE(decltype((a)), int&);
+
+void foo_check(int a, int& b, float& c, int* d) 
+{ 
+  CHECK_DECLTYPE(decltype(a), int);
+  CHECK_DECLTYPE(decltype(b), int&); 
+  CHECK_DECLTYPE(decltype(c), float&);
+  CHECK_DECLTYPE(decltype(d), int*);
+} 
+
+int foo(char); 
+int bar(char); 
+int bar(int); 
+CHECK_DECLTYPE(decltype(foo), int(char));
+
+decltype(bar) z; // { dg-error "overload" }
+// { dg-error "invalid type" "" { target *-*-* } 48 }
+
+CHECK_DECLTYPE(decltype(&foo), int(*)(char));
+CHECK_DECLTYPE(decltype(*&foo), int(&)(char));
+
+void array_types()
+{
+  int a[10]; 
+  CHECK_DECLTYPE(decltype(a), int[10]);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype3.C b/gcc/testsuite/g++.dg/cpp0x/decltype3.C
new file mode 100644 (file)
index 0000000..556ae70
--- /dev/null
@@ -0,0 +1,72 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T, typename U> 
+struct is_same 
+{
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+  static const bool value = true;
+};
+
+#define CHECK_DECLTYPE(DECLTYPE,RESULT) \
+  static_assert(is_same< DECLTYPE , RESULT >::value, #DECLTYPE " should be " #RESULT)
+
+class A { 
+public:
+  int a; 
+  int& b; 
+  static int c; 
+
+  A(int& b) : b(b) { }
+
+  void foo() { 
+    CHECK_DECLTYPE(decltype(a), int);
+    CHECK_DECLTYPE(decltype(this->a), int);
+    CHECK_DECLTYPE(decltype((*this).a), int);
+    CHECK_DECLTYPE(decltype(b), int&);
+    CHECK_DECLTYPE(decltype(c), int);
+  } 
+  void bar() const {
+    CHECK_DECLTYPE(decltype(a), int);
+    CHECK_DECLTYPE(decltype(b), int&);
+    CHECK_DECLTYPE(decltype(c), int);
+  } 
+}; 
+
+int b;
+A aa(b); 
+const A& caa = aa; 
+CHECK_DECLTYPE(decltype(aa.a), int);
+CHECK_DECLTYPE(decltype(aa.b), int&);
+CHECK_DECLTYPE(decltype(caa.a), int);
+
+class B { 
+public:
+  int a;  // { dg-error "invalid use" }
+  enum B_enum { b }; 
+  decltype(a) c; // { dg-error "from this location" }
+  decltype(a) foo() { } // { dg-error "from this location" }
+  decltype(b) enums_are_in_scope() { return b; } // ok 
+}; 
+
+CHECK_DECLTYPE(decltype(aa.*&A::a), int&);
+decltype(aa.*&A::b) zz; // { dg-error "cannot create pointer to reference member" }
+// { dg-error "invalid type" "" { target *-*-* } 58 }
+CHECK_DECLTYPE(decltype(caa.*&A::a), const int&);
+
+class X { 
+  void foo() { 
+    CHECK_DECLTYPE(decltype(this), X*);
+    CHECK_DECLTYPE(decltype(*this), X&);
+  } 
+  void bar() const { 
+    CHECK_DECLTYPE(decltype(this), const X*);
+    CHECK_DECLTYPE(decltype(*this), const X&);
+  } 
+};
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype4.C b/gcc/testsuite/g++.dg/cpp0x/decltype4.C
new file mode 100644 (file)
index 0000000..18f2734
--- /dev/null
@@ -0,0 +1,82 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T, typename U> 
+struct is_same 
+{
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+  static const bool value = true;
+};
+
+#define CHECK_DECLTYPE(DECLTYPE,RESULT) \
+  static_assert(is_same< DECLTYPE , RESULT >::value, #DECLTYPE " should be " #RESULT)
+
+struct A {
+  int x; 
+  int& y; 
+  int foo(char); 
+  int& bar() const; 
+}; 
+
+CHECK_DECLTYPE(decltype(&A::x), int A::*);
+decltype(&A::y) Ay; // { dg-error "cannot create pointer to reference member|invalid type" }
+CHECK_DECLTYPE(decltype(&A::foo), int (A::*) (char));
+CHECK_DECLTYPE(decltype(&A::bar), int& (A::*) () const);
+
+CHECK_DECLTYPE(decltype("decltype"), const char(&)[9]);
+CHECK_DECLTYPE(decltype(1), int);
+
+int an_int = 5;
+int& i = an_int; 
+const int j = an_int; 
+
+CHECK_DECLTYPE(decltype(i)&, int&);
+CHECK_DECLTYPE(const decltype(j), const int);
+
+int foo(); 
+CHECK_DECLTYPE(decltype(foo()), int);
+float& bar(int); 
+CHECK_DECLTYPE(decltype (bar(1)), float&);
+const A bar(); 
+CHECK_DECLTYPE(decltype (bar()), const A);
+const A& bar2(); 
+CHECK_DECLTYPE(decltype (bar2()), const A&);
+
+void wibble() {
+  CHECK_DECLTYPE(decltype(1+2), int);
+  int* p; 
+  CHECK_DECLTYPE(decltype(*p), int&);
+  int a[10]; 
+  CHECK_DECLTYPE(decltype(a[3]), int&);
+  int i; int& j = i; 
+  CHECK_DECLTYPE(decltype (i = 5), int&);
+  CHECK_DECLTYPE(decltype (j = 5), int&);
+
+  CHECK_DECLTYPE(decltype (++i), int&); 
+  CHECK_DECLTYPE(decltype (i++), int);
+}
+
+struct B {
+  int bit : 2;
+  const int cbit : 3;
+
+  void foo()
+  {
+    CHECK_DECLTYPE(decltype(bit), int);
+    CHECK_DECLTYPE(decltype((bit)), int&);
+    CHECK_DECLTYPE(decltype(cbit), const int);
+    CHECK_DECLTYPE(decltype((cbit)), const int&); // { dg-bogus "static assertion failed" "GCC gets the actual type of this expression wrong" { xfail *-*-* } 73 }
+  }
+};
+
+B b;
+const B& bc = b;
+CHECK_DECLTYPE(decltype(b.bit), int);
+CHECK_DECLTYPE(decltype(bc.bit), int);
+CHECK_DECLTYPE(decltype((b.bit)), int&);
+CHECK_DECLTYPE(decltype((bc.bit)), const int&);
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype5.C b/gcc/testsuite/g++.dg/cpp0x/decltype5.C
new file mode 100644 (file)
index 0000000..4e8e64b
--- /dev/null
@@ -0,0 +1,38 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T, typename U> 
+struct is_same 
+{
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+  static const bool value = true;
+};
+
+#define CHECK_DECLTYPE(DECLTYPE,RESULT) \
+  static_assert(is_same< DECLTYPE , RESULT >::value, #RESULT)
+
+template<typename F> F create_a();
+
+template<typename F, typename T1>
+decltype(create_a<F&>()(create_a<const T1&>())) forward(F f, const T1& a1)
+{
+  return f(a1);
+}
+
+struct identity {
+  template<typename T>
+  const T& operator()(const T& x) { return x; }
+};
+
+
+identity id;
+int i;
+float f;
+
+CHECK_DECLTYPE(decltype(forward(id, i)), const int&);
+CHECK_DECLTYPE(decltype(forward(id, f)), const float&);
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype6.C b/gcc/testsuite/g++.dg/cpp0x/decltype6.C
new file mode 100644 (file)
index 0000000..c407c18
--- /dev/null
@@ -0,0 +1,36 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T, typename U> 
+struct is_same 
+{
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+  static const bool value = true;
+};
+
+template<typename T> const T& foo(); 
+
+
+int i; 
+
+template<typename T>
+struct A 
+{ 
+  double x; 
+};
+
+const A<double>* a = new A<double>(); 
+
+static_assert(is_same<decltype(foo<int>()), const int&>::value,
+              "type should be const int&");
+static_assert(is_same<decltype(i), int>::value,
+              "type should be int");
+static_assert(is_same<decltype(a->x), double>::value,
+              "type should be double");
+static_assert(is_same<decltype((a->x)), const double&>::value,
+              "type should be const double&");