diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 4b33059287f92cdcaa9a859659086bff60fe96a6..2c681c0edbc4bdf04c7d2187b9af7a04fce0c4a8 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,16 @@
+2008-12-17  Jason Merrill  <jason@redhat.com>
+
+	* semantics.c (describable_type): New function.
+	(finish_decltype_type): Use it for dependent exprs.
+	* cp-tree.h: Declare it.
+	* mangle.c (write_type) [DECLTYPE_TYPE]: Set skip_evaluation.
+	(write_expression): If skip_evaluation, use type stubs.
+	* tree.c (cp_tree_equal): Handle PARM_DECLs from different
+	declarations of a function.
+	* init.c (build_new): Do auto deduction if type is describable.
+	* decl.c (cp_finish_decl): Likewise.
+	* parser.c (cp_parser_omp_for_loop): Likewise.
+
 2008-12-10  Jason Merrill  <jason@redhat.com>
 
 	PR c++/35319
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index bf22eb4d85f1bca2b5c5a3a1f1634e4cc1c90771..ff43bc70d74eafdbcc66b0955407d2fbb486cd17 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4814,6 +4814,7 @@ extern bool cxx_omp_create_clause_info		(tree, tree, bool, bool, bool);
 extern tree baselink_for_fns                    (tree);
 extern void finish_static_assert                (tree, tree, location_t,
                                                  bool);
+extern tree describable_type			(tree);
 extern tree finish_decltype_type                (tree, bool);
 extern tree finish_trait_expr			(enum cp_trait_kind, tree, tree);
 
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index e786b39c8e30555876744414ba0c550ca5d8f9ae..efc7e2eb8a3835c884d34d9db4c791e36de900f9 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5496,7 +5496,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	  TREE_TYPE (decl) = error_mark_node;
 	  return;
 	}
-      else if (!type_dependent_expression_p (init))
+      else if (describable_type (init))
 	{
 	  type = TREE_TYPE (decl) = do_auto_deduction (type, init, auto_node);
 	  if (type == error_mark_node)
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index d71b68badaa1c71707efecb65b6f3d43086c7eba..abcf858647346b22132bfc0c2548a58fad670154 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2329,7 +2329,7 @@ build_new (tree placement, tree type, tree nelts, tree init,
   orig_init = init;
 
   if (nelts == NULL_TREE && init != void_zero_node && list_length (init) == 1
-      && !any_type_dependent_arguments_p (init))
+      && describable_type (TREE_VALUE (init)))
     {
       tree auto_node = type_uses_auto (type);
       if (auto_node)
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 36b984e321407103d6e142102a76e24169365261..1ec27c1ffcd722ea1e322caa05dd1beeefa14db6 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -1680,7 +1680,9 @@ write_type (tree type)
                 write_char ('t');
               else
                 write_char ('T');
+	      ++skip_evaluation;
               write_expression (DECLTYPE_TYPE_EXPR (type));
+	      --skip_evaluation;
               write_char ('E');
               break;
 
@@ -2139,9 +2141,28 @@ write_member_name (tree member)
 static void
 write_expression (tree expr)
 {
-  enum tree_code code;
+  enum tree_code code = TREE_CODE (expr);
 
-  code = TREE_CODE (expr);
+  /* Inside decltype we can simplify some expressions, since we're only
+     interested in the type.  */
+  if (skip_evaluation)
+    {
+      tree type = describable_type (expr);
+      if (type == NULL_TREE)
+	;
+      else if (TREE_CODE (type) == REFERENCE_TYPE)
+	{
+	  write_string ("sT");
+	  write_type (TREE_TYPE (type));
+	  return;
+	}
+      else
+	{
+	  write_string ("sR");
+	  write_type (type);
+	  return;
+	}
+    }
 
   /* Skip NOP_EXPRs.  They can occur when (say) a pointer argument
      is converted (via qualification conversions) to another
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 45abd2414d51ee83422ae7eb50fadfec9ed053ab..79be488028f2a8b1dfe4f80bad1ac31889407c39 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -21159,7 +21159,7 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses)
 						    &is_direct_init,
 						    &is_non_constant_init);
 
-		      if (auto_node && !type_dependent_expression_p (init))
+		      if (auto_node && describable_type (init))
 			{
 			  TREE_TYPE (decl)
 			    = do_auto_deduction (TREE_TYPE (decl), init,
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index e0ae6fff4adcd8420aeb31493473e734aeaff6e5..d5efb834810734ba5f19b85274cc863f4d22d605 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -4438,12 +4438,79 @@ finish_static_assert (tree condition, tree message, location_t location,
     }
 }
 
+/* Returns decltype((EXPR)) for cases where we can drop the decltype and
+   just return the type even though EXPR is a type-dependent expression.
+   The ABI specifies which cases this applies to, which is a subset of the
+   possible cases.  */
+
+tree
+describable_type (tree expr)
+{
+  tree type = NULL_TREE;
+
+  /* processing_template_decl isn't set when we're called from the mangling
+     code, so bump it now.  */
+  ++processing_template_decl;
+  if (! type_dependent_expression_p (expr)
+      && ! type_unknown_p (expr))
+    {
+      type = TREE_TYPE (expr);
+      if (real_lvalue_p (expr))
+	type = build_reference_type (type);
+    }
+  --processing_template_decl;
+
+  if (type)
+    return type;
+
+  switch (TREE_CODE (expr))
+    {
+    case VAR_DECL:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case FUNCTION_DECL:
+      /* Named rvalue reference becomes lvalue.  */
+      type = build_reference_type (non_reference (TREE_TYPE (expr)));
+      break;
+
+    case NEW_EXPR:
+    case CONST_DECL:
+    case TEMPLATE_PARM_INDEX:
+    case CAST_EXPR:
+    case STATIC_CAST_EXPR:
+    case REINTERPRET_CAST_EXPR:
+    case CONST_CAST_EXPR:
+    case DYNAMIC_CAST_EXPR:
+      type = TREE_TYPE (expr);
+      break;
+
+    case INDIRECT_REF:
+      {
+	tree ptrtype = describable_type (TREE_OPERAND (expr, 0));
+	if (ptrtype && POINTER_TYPE_P (ptrtype))
+	  type = build_reference_type (TREE_TYPE (ptrtype));
+      }
+      break;
+
+    default:
+      if (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_constant)
+	type = TREE_TYPE (expr);
+      break;
+    }
+
+  if (type && type_uses_auto (type))
+    return NULL_TREE;
+  else
+    return type;
+}
+
 /* 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)
 {
@@ -4464,6 +4531,29 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p)
 
   if (type_dependent_expression_p (expr))
     {
+      if (id_expression_or_member_access_p)
+	{
+	  switch (TREE_CODE (expr))
+	    {
+	    case VAR_DECL:
+	    case PARM_DECL:
+	    case RESULT_DECL:
+	    case FUNCTION_DECL:
+	    case CONST_DECL:
+	    case TEMPLATE_PARM_INDEX:
+	      type = TREE_TYPE (expr);
+	      break;
+
+	    default:
+	      break;
+	    }
+	}
+      else
+	type = describable_type (expr);
+
+      if (type && !type_uses_auto (type))
+	return type;
+
       type = cxx_make_type (DECLTYPE_TYPE);
       DECLTYPE_TYPE_EXPR (type) = expr;
       DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type)
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 2ae65431c7be868090e5d9d11ba1851790e8e28c..1f2c6319ece66c219d820c781178620b4873cdbf 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1857,8 +1857,17 @@ cp_tree_equal (tree t1, tree t2)
 	return false;
       return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
 
-    case VAR_DECL:
     case PARM_DECL:
+      /* For comparing uses of parameters in late-specified return types
+	 with an out-of-class definition of the function.  */
+      if ((!DECL_CONTEXT (t1) || !DECL_CONTEXT (t2))
+	  && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+	  && DECL_NAME (t1) == DECL_NAME (t2))
+	return true;
+      else
+	return false;
+
+    case VAR_DECL:
     case CONST_DECL:
     case FUNCTION_DECL:
     case TEMPLATE_DECL:
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 74b39a4eaf626667b026e3dcec92f63a99933d49..11a6a70953142a0ed52c9652c40c85946512d6d4 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2008-12-17  Jason Merrill  <jason@redhat.com>
+
+	* g++.dg/cpp0x/auto6.C: Test more stuff.
+	* g++.dg/cpp0x/auto12.C: New test.
+
 2008-12-17  Daniel Kraft  <d@domob.eu>
 
 	PR fortran/38137
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto12.C b/gcc/testsuite/g++.dg/cpp0x/auto12.C
new file mode 100644
index 0000000000000000000000000000000000000000..94652cb5ca88dd51f5a579be11267f59f294f586
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/auto12.C
@@ -0,0 +1,52 @@
+// More auto/decltype mangling tests.
+// { dg-options "-std=c++0x" }
+
+template <class T>
+struct B
+{
+  static int i;
+};
+
+int&& x();
+
+template <class T>
+struct A
+{
+  static int i;
+  static int &ir;
+  static int &&irr;
+  template <class U>
+  auto f(U u) -> decltype (u + i);
+  template <class U>
+  auto fr(U u) -> decltype (u + ir);
+  template <class U>
+  auto frr(U u) -> decltype (u + irr);
+  template <class U>
+  auto g(U u) -> decltype (u + sizeof (i));
+  template <class U>
+  auto h(U u) -> decltype (u + B<U>::i);
+  template <class U>
+  auto j(U u) -> decltype (u + x());
+};
+
+template<class T> template<class U>
+auto A<T>::f(U u) -> decltype (u + i)
+{
+  return u + i;
+}
+
+int main()
+{
+  // { dg-final { scan-assembler  "_ZN1AIiE1fIiEEDTplsTT_sTiES2_" } }
+  A<int>().f(1);
+  // { dg-final { scan-assembler  "_ZN1AIiE2frIiEEDTplsTT_sTiES2_" } }
+  A<int>().fr(1);
+  // { dg-final { scan-assembler  "_ZN1AIiE3frrIiEEDTplsTT_sTiES2_" } }
+  A<int>().frr(1);
+  // { dg-final { scan-assembler  "_ZN1AIiE1gIiEEDTplsTT_sRjES2_" } }
+  A<int>().g(1);
+  // { dg-final { scan-assembler  "_ZN1AIiE1hIiEEDTplsTT_sr1BIS2_E1iES2_" } }
+  A<int>().h(1);
+  // { dg-final { scan-assembler  "_ZN1AIiE1jIiEEDTplsTT_sRiES2_" } }
+  A<int>().j(1);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto6.C b/gcc/testsuite/g++.dg/cpp0x/auto6.C
index d2bcfedb63c658e04a644d0687521dc31c712f69..7d659c7236a09c541a6910b17462d80507f79ca9 100644
--- a/gcc/testsuite/g++.dg/cpp0x/auto6.C
+++ b/gcc/testsuite/g++.dg/cpp0x/auto6.C
@@ -30,6 +30,12 @@ auto add3(T t, U u) -> decltype (ag(t,u))
   return ag(t,u);
 }
 
+template<class T, class U>
+decltype(*(T*)0+*(U*)0) add4(T t, U u)
+{
+  return t+u;
+}
+
 template <class T>
 struct A
 {
@@ -72,13 +78,28 @@ auto k(T t, U u, V v) -> decltype (t.U::template B<V>::MEM)
   return t.U::template B<V>::MEM;
 }
 
+// For these two examples we can elide the 'decltype' and just mangle the type.
+template <class T>
+auto l(T t) -> decltype (t)
+{
+  return t;
+}
+
+template <class T, T u>
+auto m(T t) -> decltype (u)
+{
+  return t;
+}
+
 A<int> a, *p;
 
 int main()
 {
-  // { dg-final { scan-assembler "_Z3addIidEDTplsTT_sTT0_ES0_S1_" } }
+  // { dg-final { scan-assembler  "_Z3addIidEDTplsTT_sTT0_ES0_S1_" } }
   auto i = add(1, 2.0);
-  // { dg-final { scan-assembler "_Z4add2IidEDTplcvT_vcvT0_vES0_S1_" } }
+  // { dg-final { scan-assembler "_Z4add4IidEDTplsTT_sTT0_ES0_S1_" } }
+  auto i4 = add4(1, 2.0);
+  // { dg-final { scan-assembler "_Z4add2IidEDTplsRT_sRT0_ES0_S1_" } }
   auto i2 = add2(1, 2.0);
   // { dg-final { scan-assembler "_Z4add3IidEDTclL_Z2agEsTT_sTT0_EES0_S1_" } }
   auto i3 = add3(1, 2.0);
@@ -90,4 +111,8 @@ int main()
   h(a,1.0);
   // { dg-final { scan-assembler "_Z1kI1C1AIiE1DEDtdtsTT_srNT0_1BIT1_EE3MEMES4_S5_S7_" } }
   k( C(), A<int>(), D() );
+  // { dg-final { scan-assembler "_Z1lIiET_S0_" } }
+  l(1);
+  // { dg-final { scan-assembler "_Z1mIiLi1EET_S0_" } }
+  m<int,1>(1);
 }
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index a6721bf906d81e91531520e93d25288e6ab28fe4..4eaee542b3beacbaead67b4c208a6f76daf74713 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -1,3 +1,10 @@
+2008-12-17  Jason Merrill  <jason@redhat.com>
+
+	* cp-demangle.c (d_expression): Handle rvalue stubs too.
+	[DEMANGLE_COMPONENT_CAST]: Update mangling.
+	(d_print_comp): Avoid extra ", " with empty template argument packs.
+	Remove handling for obsolete T() mangling.
+
 2008-12-10  Jason Merrill  <jason@redhat.com>
 
 	* cp-demangle.c (cplus_demangle_type): Support fixed-point types.
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index de0d9f7610eaea73ad937ca0e41e828348f25c46..8ab5729dbb7642d569e164ce04b70a791e2778a6 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -2561,7 +2561,8 @@ d_expression (struct d_info *di)
 			    d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
 					 d_template_args (di)));
     }
-  else if (peek == 's' && d_peek_next_char (di) == 'T')
+  else if (peek == 's'
+	   && (d_peek_next_char (di) == 'T' || d_peek_next_char (di) == 'R'))
     {
       /* Just demangle a parameter placeholder as its type.  */
       d_advance (di, 2);
@@ -2608,20 +2609,22 @@ d_expression (struct d_info *di)
 	  args = op->u.s_extended_operator.args;
 	  break;
 	case DEMANGLE_COMPONENT_CAST:
-	  if (d_peek_char (di) == 'v')
-	    /* T() encoded as an operand of void.  */
-	    return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
-				cplus_demangle_type (di));
-	  else
-	    args = 1;
+	  args = 1;
 	  break;
 	}
 
       switch (args)
 	{
 	case 1:
-	  return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
-			      d_expression (di));
+	  {
+	    struct demangle_component *operand;
+	    if (op->type == DEMANGLE_COMPONENT_CAST)
+	      operand = d_exprlist (di);
+	    else
+	      operand = d_expression (di);
+	    return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+				operand);
+	  }
 	case 2:
 	  {
 	    struct demangle_component *left;
@@ -3763,8 +3766,14 @@ d_print_comp (struct d_print_info *dpi,
 	d_print_comp (dpi, d_left (dc));
       if (d_right (dc) != NULL)
 	{
+	  size_t len;
 	  d_append_string (dpi, ", ");
+	  len = dpi->len;
 	  d_print_comp (dpi, d_right (dc));
+	  /* If that didn't print anything (which can happen with empty
+	     template argument packs), remove the comma and space.  */
+	  if (dpi->len == len)
+	    dpi->len -= 2;
 	}
       return;
 
@@ -3800,12 +3809,7 @@ d_print_comp (struct d_print_info *dpi,
 	  d_print_cast (dpi, d_left (dc));
 	  d_append_char (dpi, ')');
 	}
-      if (d_left (dc)->type == DEMANGLE_COMPONENT_CAST
-	  && d_right (dc)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE)
-	/* type() -- FIXME what about type(multiple,args) */
-	d_append_string (dpi, "()");
-      else
-	d_print_subexpr (dpi, d_right (dc));
+      d_print_subexpr (dpi, d_right (dc));
       return;
 
     case DEMANGLE_COMPONENT_BINARY: