diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e11b240f0e6b6f4983fd2b09e09b6cd28e74c7c2..91df62da41b0353d1b9343c9f6243de108057423 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,13 @@
+2012-07-05  Jason Merrill  <jason@redhat.com>
+
+	PR c++/50852
+	PR c++/53039
+	* tree.c (strip_typedefs_expr): New.
+	* cp-tree.h: Declare it.
+	* pt.c (convert_template_argument, unify): Use it.
+	* parser.c (cp_parser_template_declaration_after_export): Don't call
+	fixup_template_parms.
+
 2012-07-04  Jason Merrill  <jason@redhat.com>
 
 	PR c++/53848
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 41ca83ca8c9bee4e4d20717dca3dbc2e0d70c592..e53f185d428f8d79144fd7bbc50a1a8c1040b804 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5692,6 +5692,7 @@ extern bool type_has_nontrivial_copy_init	(const_tree);
 extern bool class_tmpl_impl_spec_p		(const_tree);
 extern int zero_init_p				(const_tree);
 extern tree strip_typedefs			(tree);
+extern tree strip_typedefs_expr			(tree);
 extern tree copy_binfo				(tree, tree, tree,
 						 tree *, int);
 extern int member_p				(const_tree);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 027a7b9d07afcdb7de006561d5d3a4a2ef830e9a..4c2167aa7f616c17da02461ace3d28dd96a78436 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -21207,7 +21207,6 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
     {
       /* Parse the template parameters.  */
       parameter_list = cp_parser_template_parameter_list (parser);
-      fixup_template_parms ();
     }
 
   /* Get the deferred access checks from the parameter list.  These
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f618fa557d10212a24a55d96946a67f0288b73a7..550a1cb021c7338cf170db922472a8496e363d7b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6600,7 +6600,7 @@ convert_template_argument (tree parm,
 	   argument specification is valid.  */
 	val = convert_nontype_argument (t, orig_arg, complain);
       else
-	val = orig_arg;
+	val = strip_typedefs_expr (orig_arg);
 
       if (val == NULL_TREE)
 	val = error_mark_node;
@@ -16598,6 +16598,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 	  && !TEMPLATE_PARM_PARAMETER_PACK (parm))
 	return unify_parameter_pack_mismatch (explain_p, parm, arg);
 
+      arg = strip_typedefs_expr (arg);
       TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
       return unify_success (explain_p);
 
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index a03f8459da804d8d37de2b0d870a2d1fe7d86031..15effe41555ba1a1522cb24599bf92a4090ab9d3 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1094,7 +1094,7 @@ cv_unqualified (tree type)
     * If T is a type that needs structural equality
       its TYPE_CANONICAL (T) will be NULL.
     * TYPE_CANONICAL (T) desn't carry type attributes
-      and looses template parameter names.   */
+      and loses template parameter names.   */
 
 tree
 strip_typedefs (tree t)
@@ -1184,6 +1184,16 @@ strip_typedefs (tree t)
 				   TYPENAME_TYPE_FULLNAME (t),
 				   typename_type, tf_none);
       break;
+    case DECLTYPE_TYPE:
+      result = strip_typedefs_expr (DECLTYPE_TYPE_EXPR (t));
+      if (result == DECLTYPE_TYPE_EXPR (t))
+	return t;
+      else
+	result = (finish_decltype_type
+		  (result,
+		   DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t),
+		   tf_none));
+      break;
     default:
       break;
     }
@@ -1205,6 +1215,186 @@ strip_typedefs (tree t)
   return cp_build_qualified_type (result, cp_type_quals (t));
 }
 
+/* Like strip_typedefs above, but works on expressions, so that in
+
+   template<class T> struct A
+   {
+     typedef T TT;
+     B<sizeof(TT)> b;
+   };
+
+   sizeof(TT) is replaced by sizeof(T).  */
+
+tree
+strip_typedefs_expr (tree t)
+{
+  unsigned i,n;
+  tree r, type, *ops;
+  enum tree_code code;
+
+  if (t == NULL_TREE || t == error_mark_node)
+    return t;
+
+  if (DECL_P (t) || CONSTANT_CLASS_P (t))
+    return t;
+
+  /* Some expressions have type operands, so let's handle types here rather
+     than check TYPE_P in multiple places below.  */
+  if (TYPE_P (t))
+    return strip_typedefs (t);
+
+  code = TREE_CODE (t);
+  switch (code)
+    {
+    case IDENTIFIER_NODE:
+    case TEMPLATE_PARM_INDEX:
+    case OVERLOAD:
+    case BASELINK:
+    case ARGUMENT_PACK_SELECT:
+      return t;
+
+    case TRAIT_EXPR:
+      {
+	tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t));
+	tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t));
+	if (type1 == TRAIT_EXPR_TYPE1 (t)
+	    && type2 == TRAIT_EXPR_TYPE2 (t))
+	  return t;
+	r = copy_node (t);
+	TRAIT_EXPR_TYPE1 (t) = type1;
+	TRAIT_EXPR_TYPE2 (t) = type2;
+	return r;
+      }
+
+    case TREE_LIST:
+      {
+	VEC(tree,gc) *vec = make_tree_vector ();
+	bool changed = false;
+	tree it;
+	for (it = t; it; it = TREE_CHAIN (it))
+	  {
+	    tree val = strip_typedefs_expr (TREE_VALUE (t));
+	    VEC_safe_push (tree, gc, vec, val);
+	    if (val != TREE_VALUE (t))
+	      changed = true;
+	    gcc_assert (TREE_PURPOSE (it) == NULL_TREE);
+	  }
+	if (changed)
+	  {
+	    r = NULL_TREE;
+	    FOR_EACH_VEC_ELT_REVERSE (tree, vec, i, it)
+	      r = tree_cons (NULL_TREE, it, r);
+	  }
+	else
+	  r = t;
+	release_tree_vector (vec);
+	return r;
+      }
+
+    case TREE_VEC:
+      {
+	bool changed = false;
+	VEC(tree,gc)* vec = make_tree_vector ();
+	n = TREE_VEC_LENGTH (t);
+	VEC_reserve (tree, gc, vec, n);
+	for (i = 0; i < n; ++i)
+	  {
+	    tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i));
+	    VEC_quick_push (tree, vec, op);
+	    if (op != TREE_VEC_ELT (t, i))
+	      changed = true;
+	  }
+	if (changed)
+	  {
+	    r = copy_node (t);
+	    for (i = 0; i < n; ++i)
+	      TREE_VEC_ELT (r, i) = VEC_index (tree, vec, i);
+	  }
+	else
+	  r = t;
+	release_tree_vector (vec);
+	return r;
+      }
+
+    case CONSTRUCTOR:
+      {
+	bool changed = false;
+	VEC(constructor_elt,gc) *vec
+	  = VEC_copy (constructor_elt, gc, CONSTRUCTOR_ELTS (t));
+	n = CONSTRUCTOR_NELTS (t);
+	type = strip_typedefs (TREE_TYPE (t));
+	for (i = 0; i < n; ++i)
+	  {
+	    constructor_elt *e = VEC_index (constructor_elt, vec, i);
+	    tree op = strip_typedefs_expr (e->value);
+	    if (op != e->value)
+	      {
+		changed = true;
+		e->value = op;
+	      }
+	    gcc_checking_assert (e->index == strip_typedefs_expr (e->index));
+	  }
+
+	if (!changed && type == TREE_TYPE (t))
+	  {
+	    VEC_free (constructor_elt, gc, vec);
+	    return t;
+	  }
+	else
+	  {
+	    r = copy_node (t);
+	    TREE_TYPE (r) = type;
+	    CONSTRUCTOR_ELTS (r) = vec;
+	    return r;
+	  }
+      }
+
+    case LAMBDA_EXPR:
+      gcc_unreachable ();
+
+    default:
+      break;
+    }
+
+  gcc_assert (EXPR_P (t));
+
+  n = TREE_OPERAND_LENGTH (t);
+  ops = XALLOCAVEC (tree, n);
+  type = TREE_TYPE (t);
+
+  switch (code)
+    {
+    CASE_CONVERT:
+    case IMPLICIT_CONV_EXPR:
+    case DYNAMIC_CAST_EXPR:
+    case STATIC_CAST_EXPR:
+    case CONST_CAST_EXPR:
+    case REINTERPRET_CAST_EXPR:
+    case CAST_EXPR:
+    case NEW_EXPR:
+      type = strip_typedefs (type);
+      /* fallthrough */
+
+    default:
+      for (i = 0; i < n; ++i)
+	ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i));
+      break;
+    }
+
+  /* If nothing changed, return t.  */
+  for (i = 0; i < n; ++i)
+    if (ops[i] != TREE_OPERAND (t, i))
+      break;
+  if (i == n && type == TREE_TYPE (t))
+    return t;
+
+  r = copy_node (t);
+  TREE_TYPE (r) = type;
+  for (i = 0; i < n; ++i)
+    TREE_OPERAND (r, i) = ops[i];
+  return r;
+}
+
 /* Makes a copy of BINFO and TYPE, which is to be inherited into a
    graph dominated by T.  If BINFO is NULL, TYPE is a dependent base,
    and we do a shallow copy.  If BINFO is non-NULL, we do a deep copy.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 74ed2a3d9980add354ad5acafe0d3e3df4602803..a3c9f61fdbd926e9e0631c3071b1bf695ed77fb7 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+2012-07-05  Jason Merrill  <jason@redhat.com>
+
+	PR c++/50852
+	* g++.dg/template/typedef39.C: New.
+
+	PR c++/53039
+	* g++.dg/cpp0x/variadic133.C: New.
+	* g++.dg/template/param1.C: Adjust.
+
 2012-07-05  Ramana Radhakrishnan  <ramana.radhakrishnan@linaro.org>
 
         PR target/48941
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic133.C b/gcc/testsuite/g++.dg/cpp0x/variadic133.C
new file mode 100644
index 0000000000000000000000000000000000000000..0265f0991c186d249cb12c01c596dad7f5710604
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic133.C
@@ -0,0 +1,46 @@
+// PR c++/53039
+// { dg-do compile { target c++11 } }
+
+template <class, class>
+struct is_convertible
+{
+  static const bool value = true;
+};
+
+template<bool, class T>
+struct enable_if
+{
+  typedef T type;
+};
+
+template <bool...>
+struct Xs
+{
+  static const bool value = true;
+};
+
+template<typename... BTs>
+  class BType
+    {
+      template <typename... BUs,
+        typename enable_if<
+               Xs<is_convertible<BUs, BTs>::value...>::value,
+               bool>::type = false>
+        void fooX(BUs&&...);
+    };
+
+template <typename... ATs>
+  struct AType
+    {
+      template <typename... AUs,
+    typename enable_if<
+               Xs<is_convertible<AUs, ATs>::value...>::value,
+               bool>::type = false>
+        void foo(AUs&&...);
+    };
+
+int main()
+{
+  AType<int, int> t;
+  t.foo(1, 1);
+}
diff --git a/gcc/testsuite/g++.dg/template/param1.C b/gcc/testsuite/g++.dg/template/param1.C
index a8c3791254fd1baa7199693c443f5b395676f211..e3784736fc440fab7780915e292967e978c2db20 100644
--- a/gcc/testsuite/g++.dg/template/param1.C
+++ b/gcc/testsuite/g++.dg/template/param1.C
@@ -2,11 +2,11 @@
 // Origin: Volker Reichelt  <reichelt@igpm.rwth-aachen.de>
 // { dg-do compile }
 
-template<int> struct A // { dg-error "declaration" }
+template<int> struct A
 {
   A();
 };
 
-template<int N, char> A<N>::A() {}  // { dg-error "invalid use of incomplete type" }
+template<int N, char> A<N>::A() {}  // { dg-error "got 2 template parameters|1 required" }
 
 A<0> a;
diff --git a/gcc/testsuite/g++.dg/template/typedef39.C b/gcc/testsuite/g++.dg/template/typedef39.C
new file mode 100644
index 0000000000000000000000000000000000000000..71d8bdb1bef7f0ea2839ad6f3383f84ceb676a5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef39.C
@@ -0,0 +1,15 @@
+// PR c++/50852
+
+template<int d> class A;
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U,class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;	// { dg-error "not a member" }
+};
+template<class U,int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;	// the error should really be on this line
+};
+template class D<B<A<1> >,3>;