public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* PING: C++0x decltype patch
@ 2007-07-25 19:31 Doug Gregor
  2007-07-26  7:54 ` Paolo Carlini
  2007-07-26 19:29 ` Nathan Sidwell
  0 siblings, 2 replies; 9+ messages in thread
From: Doug Gregor @ 2007-07-25 19:31 UTC (permalink / raw)
  To: GCC Patches

It's been about two weeks since I submitted the latest decltype patch:

  http://gcc.gnu.org/ml/gcc-patches/2007-07/msg01058.html

Since then, decltype has been accepted into C++0x, in exactly the same
form as it is implemented in the patch.

Okay for mainline?

  - Doug

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING: C++0x decltype patch
  2007-07-25 19:31 PING: C++0x decltype patch Doug Gregor
@ 2007-07-26  7:54 ` Paolo Carlini
  2007-07-26  8:04   ` Paolo Carlini
  2007-07-26  8:13   ` Andrew Pinski
  2007-07-26 19:29 ` Nathan Sidwell
  1 sibling, 2 replies; 9+ messages in thread
From: Paolo Carlini @ 2007-07-26  7:54 UTC (permalink / raw)
  To: Doug Gregor; +Cc: GCC Patches, Mark Mitchell

Doug Gregor wrote:

> It's been about two weeks since I submitted the latest decltype patch:
>
>  http://gcc.gnu.org/ml/gcc-patches/2007-07/msg01058.html
>
> Since then, decltype has been accepted into C++0x, in exactly the same
> form as it is implemented in the patch.
>
> Okay for mainline?

If that makes sense, I'd like to solicitate myself a prompt overview of 
Doug's work, this implementation of decltype and the other fixes. Doug 
is spending a lot of time on implementing for the first time the new 
C++0x features on GCC and if that effort isn't fully supported by the 
community it's a real pity...

Please, thanks,
Paolo.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING: C++0x decltype patch
  2007-07-26  7:54 ` Paolo Carlini
@ 2007-07-26  8:04   ` Paolo Carlini
  2007-07-26  8:13   ` Andrew Pinski
  1 sibling, 0 replies; 9+ messages in thread
From: Paolo Carlini @ 2007-07-26  8:04 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: Doug Gregor, GCC Patches, Mark Mitchell

Paolo Carlini wrote:

> If that makes sense, I'd like to solicitate myself a prompt overview

read that "review" of course, sorry (I have an -overview- on my desktop 
now and no good coffee yet ;)

Paolo.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING: C++0x decltype patch
  2007-07-26  7:54 ` Paolo Carlini
  2007-07-26  8:04   ` Paolo Carlini
@ 2007-07-26  8:13   ` Andrew Pinski
  2007-07-26  9:06     ` Paolo Carlini
  1 sibling, 1 reply; 9+ messages in thread
From: Andrew Pinski @ 2007-07-26  8:13 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: Doug Gregor, GCC Patches, Mark Mitchell

On 7/26/07, Paolo Carlini <pcarlini@suse.de> wrote:
>Doug
> is spending a lot of time on implementing for the first time the new
> C++0x features on GCC and if that effort isn't fully supported by the
> community it's a real pity...

I don't think it is the community is not supporting it but it is just
we are all busy with other things.  We all have our own issues we are
trying to solve.  Though I will admit the C++ front-end is not being
looked after like it should be but I don't have a solution for it.

Thanks,
Andrew Pinski

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING: C++0x decltype patch
  2007-07-26  8:13   ` Andrew Pinski
@ 2007-07-26  9:06     ` Paolo Carlini
  0 siblings, 0 replies; 9+ messages in thread
From: Paolo Carlini @ 2007-07-26  9:06 UTC (permalink / raw)
  To: Andrew Pinski; +Cc: Doug Gregor, GCC Patches, Mark Mitchell

Andrew Pinski wrote:

> I don't think it is the community is not supporting it but it is just
> we are all busy with other things.  We all have our own issues we are
> trying to solve.  Though I will admit the C++ front-end is not being
> looked after like it should be but I don't have a solution for it.

I see your point. Maybe we just need additional maintainers? For 
example, if you ask me, I consider Doug definitely able to tell if a new 
C++0x feature is risky wrt the existing C++03 implementation. That 
means, I would suggest a new C++0x-maintainer role for Doug.

Paolo.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING: C++0x decltype patch
  2007-07-25 19:31 PING: C++0x decltype patch Doug Gregor
  2007-07-26  7:54 ` Paolo Carlini
@ 2007-07-26 19:29 ` Nathan Sidwell
  2007-07-27 17:11   ` Doug Gregor
  1 sibling, 1 reply; 9+ messages in thread
From: Nathan Sidwell @ 2007-07-26 19:29 UTC (permalink / raw)
  To: Doug Gregor; +Cc: GCC Patches

Doug Gregor wrote:
> It's been about two weeks since I submitted the latest decltype patch:
> 
>  http://gcc.gnu.org/ml/gcc-patches/2007-07/msg01058.html
> 
> Since then, decltype has been accepted into C++0x, in exactly the same
> form as it is implemented in the patch.
> 
> Okay for mainline?
> 
>  - Doug

Index: cp/semantics.c
+        case BIT_FIELD_REF:
+          sorry ("bit-field accesses in a decltype expression");
+          return error_mark_node;

+        default:
+          if (TYPE_P (expr) || DECL_P (expr))
+            error ("argument to decltype must be an expression");
+          else
+            sorry ("unhandled decltype expression kind: %s",
+                   tree_code_name[(int) TREE_CODE (expr)]);

why sorry and not gcc_assert or gcc_unreachable?

+      if (TREE_CODE (expr) == CALL_EXPR
+          && (fndecl = get_callee_fndecl (expr))
+          && (fndecl != error_mark_node))

+      else if ((type = is_bitfield_expr_with_lowered_type (expr)))

ow :)  can we avoid assignments in conditionals here?

Index: cp/parser.c
+static tree
+cp_parser_decltype (cp_parser *parser)

here you parse tentatively, but don't appear to be committing to the tentative 
parse when it succeeds.

Also, I can't see where decltype is gated on using c++0x extensions

nathan
-- 
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING: C++0x decltype patch
  2007-07-26 19:29 ` Nathan Sidwell
@ 2007-07-27 17:11   ` Doug Gregor
  2007-07-27 17:31     ` Nathan Sidwell
  0 siblings, 1 reply; 9+ messages in thread
From: Doug Gregor @ 2007-07-27 17:11 UTC (permalink / raw)
  To: Nathan Sidwell; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 2648 bytes --]

Thanks, Nathan!

On 7/26/07, Nathan Sidwell <nathan@codesourcery.com> wrote:
> Index: cp/semantics.c
> +        case BIT_FIELD_REF:
> +          sorry ("bit-field accesses in a decltype expression");
> +          return error_mark_node;
>
> +        default:
> +          if (TYPE_P (expr) || DECL_P (expr))
> +            error ("argument to decltype must be an expression");
> +          else
> +            sorry ("unhandled decltype expression kind: %s",
> +                   tree_code_name[(int) TREE_CODE (expr)]);
>
> why sorry and not gcc_assert or gcc_unreachable?

The first sorry(), for BIT_FIELD_REF, should be a gcc_unreachable; it
just can't happen here. The second "sorry" I'd like to keep... if we
get here, it means that I somehow missed a particular member-access
expression node. So, apologize to the user and when they report the
bug, we'll see what the expression code is to fix the bug. Perhaps
internal_error would be better?

> +      if (TREE_CODE (expr) == CALL_EXPR
> +          && (fndecl = get_callee_fndecl (expr))
> +          && (fndecl != error_mark_node))
>
> +      else if ((type = is_bitfield_expr_with_lowered_type (expr)))
>
> ow :)  can we avoid assignments in conditionals here?

Heh, sure.

> Index: cp/parser.c
> +static tree
> +cp_parser_decltype (cp_parser *parser)
>
> here you parse tentatively, but don't appear to be committing to the tentative
> parse when it succeeds.

Ah, thanks. The fix is:

  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);
    }

Essentially, by the time we reach this spot, we've either parsed an
id-expression or class member access expression, in which case there
is nothing left to tentatively parse (so we commit); or, we need to
abort the previous attempts and parse a full expression.

> Also, I can't see where decltype is gated on using c++0x extensions

In lex.c, if the keyword is only available when in C++0x mode, then
the feature is only available in C++0x mode:

  { "decltype",         RID_DECLTYPE,   D_CXX0X },

That said, decltype can save us (and the compiler) a LOT of work in
libstdc++, so I would suggest also:

  { "__decltype",       RID_DECLTYPE,   0 },

Updated patch attached, with those changes/fixes mention above.
Regtested powerpc-apple-darwin8.10.0, no regressions. Okay?

  - Doug

[-- Attachment #2: decltype.patch --]
[-- Type: application/octet-stream, Size: 35528 bytes --]

Index: testsuite/g++.dg/cpp0x/decltype3.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype3.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype3.C	(revision 0)
@@ -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&);
+  } 
+};
+
Index: testsuite/g++.dg/cpp0x/decltype4.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype4.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype4.C	(revision 0)
@@ -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&);
Index: testsuite/g++.dg/cpp0x/decltype1.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype1.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype1.C	(revision 0)
@@ -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&");
Index: testsuite/g++.dg/cpp0x/decltype5.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype5.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype5.C	(revision 0)
@@ -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&);
Index: testsuite/g++.dg/cpp0x/decltype2.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype2.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype2.C	(revision 0)
@@ -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]);
+}
+
Index: testsuite/g++.dg/cpp0x/decltype6.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype6.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype6.C	(revision 0)
@@ -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&");
Index: cp/typeck.c
===================================================================
--- cp/typeck.c	(revision 126961)
+++ cp/typeck.c	(working copy)
@@ -1080,6 +1080,14 @@ structural_comptypes (tree t1, tree t2, 
       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: cp/cp-tree.def
===================================================================
--- cp/cp-tree.def	(revision 126961)
+++ cp/cp-tree.def	(working copy)
@@ -427,6 +427,13 @@ DEFTREECODE (ARGUMENT_PACK_SELECT, "argu
 /* 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: cp/error.c
===================================================================
--- cp/error.c	(revision 126961)
+++ cp/error.c	(working copy)
@@ -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: cp/tree.c
===================================================================
--- cp/tree.c	(revision 126961)
+++ cp/tree.c	(working copy)
@@ -2380,6 +2380,12 @@ cp_walk_subtrees (tree *tp, int *walk_su
       *walk_subtrees_p = 0;
       break;
 
+    case DECLTYPE_TYPE:
+      WALK_SUBTREE (DECLTYPE_TYPE_EXPR (*tp));
+      *walk_subtrees_p = 0;
+      break;
+ 
+
     default:
       return NULL_TREE;
     }
Index: cp/mangle.c
===================================================================
--- cp/mangle.c	(revision 126961)
+++ cp/mangle.c	(working copy)
@@ -1544,6 +1544,9 @@ write_local_name (const tree function, c
    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: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 126961)
+++ cp/cp-tree.h	(working copy)
@@ -977,6 +977,7 @@ enum languages { lang_c, lang_cplusplus,
    || 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_i
 /* 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_referen
 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: cp/cxx-pretty-print.c
===================================================================
--- cp/cxx-pretty-print.c	(revision 126961)
+++ cp/cxx-pretty-print.c	(working copy)
@@ -1198,6 +1198,13 @@ pp_cxx_type_specifier_seq (cxx_pretty_pr
       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, 
     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: cp/pt.c
===================================================================
--- cp/pt.c	(revision 126961)
+++ cp/pt.c	(working copy)
@@ -9058,6 +9058,22 @@ tsubst (tree t, tree args, tsubst_flags_
 					     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_f
     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 par
 
       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: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 126961)
+++ cp/semantics.c	(working copy)
@@ -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,172 @@ finish_static_assert (tree condition, tr
       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:
+          if (TYPE_P (expr) || DECL_P (expr))
+            error ("argument to decltype must be an expression");
+          else
+            sorry ("unhandled decltype expression kind: %s",
+                   tree_code_name[(int) TREE_CODE (expr)]);
+          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: cp/lex.c
===================================================================
--- cp/lex.c	(revision 126961)
+++ cp/lex.c	(working copy)
@@ -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: cp/parser.c
===================================================================
--- cp/parser.c	(revision 126961)
+++ cp/parser.c	(working copy)
@@ -577,6 +577,8 @@ cp_lexer_next_token_is_decl_specifier_ke
       /* 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_specif
 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_specificat
   (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_pa
    `&' 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 
 							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 
 	    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 
 	    = 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 
 							  "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 
 							  "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 *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 *parse
   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* par
      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_pars
       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: c-common.h
===================================================================
--- c-common.h	(revision 126961)
+++ c-common.h	(working copy)
@@ -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,

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING: C++0x decltype patch
  2007-07-27 17:11   ` Doug Gregor
@ 2007-07-27 17:31     ` Nathan Sidwell
  2007-07-27 18:03       ` Doug Gregor
  0 siblings, 1 reply; 9+ messages in thread
From: Nathan Sidwell @ 2007-07-27 17:31 UTC (permalink / raw)
  To: Doug Gregor; +Cc: GCC Patches

Doug,
> The first sorry(), for BIT_FIELD_REF, should be a gcc_unreachable; it
> just can't happen here. The second "sorry" I'd like to keep... if we
> get here, it means that I somehow missed a particular member-access
> expression node. So, apologize to the user and when they report the
> bug, we'll see what the expression code is to fix the bug. Perhaps
> internal_error would be better?

IMHO that's exactly what
	gcc_assert (TYPE_P (expr) || DECL_P (expr))
is for :)  sorry is for pieces we _know_ we've not implemented.  Here we _think_ 
we've covered all the cases, so an assert is appropriate.

>> here you parse tentatively, but don't appear to be committing to the tentative
>> parse when it succeeds.
> 
> Ah, thanks. The fix is:
> 
>   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);
>     }
> 
> Essentially, by the time we reach this spot, we've either parsed an
> id-expression or class member access expression, in which case there
> is nothing left to tentatively parse (so we commit); or, we need to
> abort the previous attempts and parse a full expression.

Yup.

> 
>> Also, I can't see where decltype is gated on using c++0x extensions
> 
> In lex.c, if the keyword is only available when in C++0x mode, then
> the feature is only available in C++0x mode:
> 
>   { "decltype",         RID_DECLTYPE,   D_CXX0X },
> 
> That said, decltype can save us (and the compiler) a LOT of work in
> libstdc++, so I would suggest also:
> 
>   { "__decltype",       RID_DECLTYPE,   0 },

I'm fine with this.

> Updated patch attached, with those changes/fixes mention above.
> Regtested powerpc-apple-darwin8.10.0, no regressions. Okay?

I would still like the other sorry turned into gcc_assert, for the reasons I 
mentioned.

nathan
-- 
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: PING: C++0x decltype patch
  2007-07-27 17:31     ` Nathan Sidwell
@ 2007-07-27 18:03       ` Doug Gregor
  0 siblings, 0 replies; 9+ messages in thread
From: Doug Gregor @ 2007-07-27 18:03 UTC (permalink / raw)
  To: Nathan Sidwell; +Cc: GCC Patches

On 7/27/07, Nathan Sidwell <nathan@codesourcery.com> wrote:
> Doug,
> > The first sorry(), for BIT_FIELD_REF, should be a gcc_unreachable; it
> > just can't happen here. The second "sorry" I'd like to keep... if we
> > get here, it means that I somehow missed a particular member-access
> > expression node. So, apologize to the user and when they report the
> > bug, we'll see what the expression code is to fix the bug. Perhaps
> > internal_error would be better?
>
> IMHO that's exactly what
>         gcc_assert (TYPE_P (expr) || DECL_P (expr))
> is for :)  sorry is for pieces we _know_ we've not implemented.  Here we _think_
> we've covered all the cases, so an assert is appropriate.

Understood. I'll turn it into an assert.

  - Doug

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2007-07-27 17:39 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-07-25 19:31 PING: C++0x decltype patch Doug Gregor
2007-07-26  7:54 ` Paolo Carlini
2007-07-26  8:04   ` Paolo Carlini
2007-07-26  8:13   ` Andrew Pinski
2007-07-26  9:06     ` Paolo Carlini
2007-07-26 19:29 ` Nathan Sidwell
2007-07-27 17:11   ` Doug Gregor
2007-07-27 17:31     ` Nathan Sidwell
2007-07-27 18:03       ` Doug Gregor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).