Patchwork [RFH,/] PR 51222

login
register
mail settings
Submitter Paolo Carlini
Date May 1, 2012, noon
Message ID <4F9FD050.7040700@oracle.com>
Download mbox | patch
Permalink /patch/156051/
State New
Headers show

Comments

Paolo Carlini - May 1, 2012, noon
On 05/01/2012 06:28 AM, Jason Merrill wrote:
> On 04/30/2012 07:37 PM, Paolo Carlini wrote:
>> Thus, my question would be: is something like the below in the right
>> direction? The alternate possibility I can see, would be basically
>> redoing a slightly slimmed version of for_each_template_parm specialized
>> for our needs (a few less conditionals)
> I think either approach would be fine; I lean toward the first, but 
> changing the name and adding a flag for clarity.  Changing the walking 
> behavior based on fn being null is too subtle.
Agreed. The below is what I booted and tested on x86_64-linux.

Thanks,
Paolo.

///////////////////
/cp
2012-05-01  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/51222
	* pt.c (for_each_template_parm): Rename to walk_template_parms,
	add any_p bool parameter.
	(mark_template_parm, uses_template_parms_level): Adjust.
	(instantiation_dependent_expression_p): New.
	(finish_decltype_type): Use it.
	* cp-tree.h: Update declarations.

/testsuite
2012-05-01  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/51222
	* g++.dg/cpp0x/decltype37.C: New.
Jason Merrill - May 1, 2012, 6:02 p.m.
On 05/01/2012 08:00 AM, Paolo Carlini wrote:
>> I think either approach would be fine; I lean toward the first, but
>> changing the name and adding a flag for clarity. Changing the walking
>> behavior based on fn being null is too subtle.
> Agreed. The below is what I booted and tested on x86_64-linux.

> +   If ANY_P is true, return 1 if any, 0 otherwise.

This isn't really what the parameter means; it means also look into the 
types of declarations used in the expression.  So perhaps call it 
"check_types"?

> +   If ANY_P is false, for each the iteration calls FN with the parameter
> +   and the DATA.

This doesn't actually depend on ANY_P, it depends on whether or not FN 
is null.

>       /* If there's no type, then this thing must be some expression
>          involving template parameters.  */
>       if (!fn && !TREE_TYPE (t))
>         return error_mark_node;

Hmm, this preexisting code seems to assume that any type-dependent 
expression must include a direct use of a template parameter, but it 
might just have a declaration with dependent type.  We should also test 
any_p/check_types, and this should apply to all expressions, not just these.

>     case MODOP_EXPR:
>     case CAST_EXPR:
>     case IMPLICIT_CONV_EXPR:
>     case REINTERPRET_CAST_EXPR:
>     case CONST_CAST_EXPR:
>     case STATIC_CAST_EXPR:
>     case DYNAMIC_CAST_EXPR:
>     case ARROW_EXPR:
>     case DOTSTAR_EXPR:
>     case TYPEID_EXPR:
>     case PSEUDO_DTOR_EXPR:
>       if (!fn)
>         return error_mark_node;
>       break;

This pre-existing code seems like it will do the wrong thing; these 
codes don't necessarily imply a dependent expression.  We can drop these 
cases, too.

Jason

Patch

Index: testsuite/g++.dg/cpp0x/decltype37.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype37.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype37.C	(revision 0)
@@ -0,0 +1,101 @@ 
+// PR c++/51222
+// { dg-options -std=c++11 }
+
+template<class T>
+struct add_rref {
+  typedef T&& type;
+};
+
+template<>
+struct add_rref<void> {
+  typedef void type;
+};
+
+template<class T>
+typename add_rref<T>::type declval();
+
+template<class T, class U, class =
+  decltype(::delete ::new T(declval<U>()))
+>
+auto f(int) -> char;
+
+template<class, class>
+auto f(...) -> char(&)[2];
+
+template<class T, class =
+  decltype(::delete ::new T())
+>
+auto g(int) -> char;
+
+template<class>
+auto g(...) -> char(&)[2];
+
+template<class T, class U>
+auto f2(int) -> decltype(::delete ::new T(declval<U>()), char());
+
+template<class, class>
+auto f2(...) -> char(&)[2];
+
+template<class T>
+auto g2(int) -> decltype(::delete ::new T(), char());
+
+template<class>
+auto g2(...) -> char(&)[2];
+
+struct C { };
+
+struct A {
+  virtual ~A() = 0;
+};
+
+struct D1 {
+  D1() = delete;
+};
+
+struct D2 {
+  ~D2() = delete;
+};
+
+static_assert(sizeof(g<void>(0)) == 2, "Ouch");
+static_assert(sizeof(g<void()>(0)) == 2, "Ouch");
+static_assert(sizeof(g<void() const>(0)) == 2, "Ouch");
+static_assert(sizeof(g<A>(0)) == 2, "Ouch");
+static_assert(sizeof(g<D1>(0)) == 2, "Ouch");
+static_assert(sizeof(g<D2>(0)) == 2, "Ouch");
+static_assert(sizeof(g<int&>(0)) == 2, "Ouch");
+static_assert(sizeof(g<int&&>(0)) == 2, "Ouch");
+static_assert(sizeof(g<void(&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(g<void(&&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void(), void()>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void() const, void() const>(0)) == 2, "Ouch");
+static_assert(sizeof(f<int, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void, int>(0)) == 2, "Ouch");
+static_assert(sizeof(f<C, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f<C, int>(0)) == 2, "Ouch");
+static_assert(sizeof(f<int&, int&>(0)) == 2, "Ouch");
+static_assert(sizeof(f<int&&, int&&>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void(&)(), void(&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void(&&)(), void(&&)()>(0)) == 2, "Ouch");
+
+static_assert(sizeof(g2<void>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<void()>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<void() const>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<A>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<D1>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<D2>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<int&>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<int&&>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<void(&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<void(&&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void(), void()>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void() const, void() const>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<int, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void, int>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<C, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<C, int>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<int&, int&>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<int&&, int&&>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void(&)(), void(&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void(&&)(), void(&&)()>(0)) == 2, "Ouch");
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 187012)
+++ cp/pt.c	(working copy)
@@ -145,8 +145,8 @@  static tree convert_nontype_argument_function (tre
 static tree convert_nontype_argument (tree, tree, tsubst_flags_t);
 static tree convert_template_argument (tree, tree, tree,
 				       tsubst_flags_t, int, tree);
-static int for_each_template_parm (tree, tree_fn_t, void*,
-				   struct pointer_set_t*, bool);
+static int walk_template_parms (tree, tree_fn_t, void*,
+				struct pointer_set_t*, bool, bool);
 static tree expand_template_argument_pack (tree);
 static tree build_template_parm_index (int, int, int, int, tree, tree);
 static bool inline_needs_template_parms (tree);
@@ -185,7 +185,7 @@  static int coerce_template_template_parms (tree, t
 static bool template_template_parm_bindings_ok_p (tree, tree);
 static int template_args_equal (tree, tree);
 static void tsubst_default_arguments (tree);
-static tree for_each_template_parm_r (tree *, int *, void *);
+static tree walk_template_parms_r (tree *, int *, void *);
 static tree copy_default_args_to_explicit_spec_1 (tree, tree);
 static void copy_default_args_to_explicit_spec (tree);
 static int invalid_nontype_parm_type_p (tree, tsubst_flags_t);
@@ -4276,8 +4276,8 @@  mark_template_parm (tree t, void* data)
       tpd->arg_uses_template_parms[tpd->current_arg] = 1;
     }
 
-  /* Return zero so that for_each_template_parm will continue the
-     traversal of the tree; we want to mark *every* template parm.  */
+  /* Return zero so that walk_template_parms will continue the traversal
+     of the tree; we want to mark *every* template parm.  */
   return 0;
 }
 
@@ -4344,11 +4344,12 @@  process_partial_specialization (tree decl)
   for (i = 0; i < nargs; ++i)
     {
       tpd.current_arg = i;
-      for_each_template_parm (TREE_VEC_ELT (inner_args, i),
-			      &mark_template_parm,
-			      &tpd,
-			      NULL,
-			      /*include_nondeduced_p=*/false);
+      walk_template_parms (TREE_VEC_ELT (inner_args, i),
+			   &mark_template_parm,
+			   &tpd,
+			   NULL,
+			   /*any_p=*/false,
+			   /*include_nondeduced_p=*/false);
     }
   for (i = 0; i < ntparms; ++i)
     if (tpd.parms[i] == 0)
@@ -4481,11 +4482,12 @@  process_partial_specialization (tree decl)
                   tpd2.current_arg = i;
                   tpd2.arg_uses_template_parms[i] = 0;
                   memset (tpd2.parms, 0, sizeof (int) * nargs);
-                  for_each_template_parm (type,
-                                          &mark_template_parm,
-                                          &tpd2,
-                                          NULL,
-					  /*include_nondeduced_p=*/false);
+                  walk_template_parms (type,
+				       &mark_template_parm,
+				       &tpd2,
+				       NULL,
+				       /*any_p=*/false,
+				       /*include_nondeduced_p=*/false);
 
                   if (tpd2.arg_uses_template_parms [i])
                     {
@@ -4755,7 +4757,7 @@  check_default_tmpl_args (tree decl, tree parms, in
 }
 
 /* Worker for push_template_decl_real, called via
-   for_each_template_parm.  DATA is really an int, indicating the
+   walk_template_parms.  DATA is really an int, indicating the
    level of the parameters we are interested in.  If T is a template
    parameter of that level, return nonzero.  */
 
@@ -7750,16 +7752,17 @@  struct pair_fn_data
 {
   tree_fn_t fn;
   void *data;
+  bool any_p;
   /* True when we should also visit template parameters that occur in
      non-deduced contexts.  */
   bool include_nondeduced_p;
   struct pointer_set_t *visited;
 };
 
-/* Called from for_each_template_parm via walk_tree.  */
+/* Called from walk_template_parms via walk_tree.  */
 
 static tree
-for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
+walk_template_parms_r (tree *tp, int *walk_subtrees, void *d)
 {
   tree t = *tp;
   struct pair_fn_data *pfd = (struct pair_fn_data *) d;
@@ -7768,8 +7771,9 @@  static tree
 
   if (TYPE_P (t)
       && (pfd->include_nondeduced_p || TREE_CODE (t) != TYPENAME_TYPE)
-      && for_each_template_parm (TYPE_CONTEXT (t), fn, data, pfd->visited,
-				 pfd->include_nondeduced_p))
+      && walk_template_parms (TYPE_CONTEXT (t), fn, data,
+			      pfd->visited, pfd->any_p,
+			      pfd->include_nondeduced_p))
     return error_mark_node;
 
   switch (TREE_CODE (t))
@@ -7783,34 +7787,39 @@  static tree
     case ENUMERAL_TYPE:
       if (!TYPE_TEMPLATE_INFO (t))
 	*walk_subtrees = 0;
-      else if (for_each_template_parm (TI_ARGS (TYPE_TEMPLATE_INFO (t)),
-				       fn, data, pfd->visited, 
-				       pfd->include_nondeduced_p))
+      else if (walk_template_parms (TI_ARGS (TYPE_TEMPLATE_INFO (t)),
+				    fn, data, pfd->visited,
+				    pfd->any_p,
+				    pfd->include_nondeduced_p))
 	return error_mark_node;
       break;
 
     case INTEGER_TYPE:
-      if (for_each_template_parm (TYPE_MIN_VALUE (t),
-				  fn, data, pfd->visited, 
-				  pfd->include_nondeduced_p)
-	  || for_each_template_parm (TYPE_MAX_VALUE (t),
-				     fn, data, pfd->visited,
-				     pfd->include_nondeduced_p))
+      if (walk_template_parms (TYPE_MIN_VALUE (t),
+			       fn, data, pfd->visited,
+			       pfd->any_p,
+			       pfd->include_nondeduced_p)
+	  || walk_template_parms (TYPE_MAX_VALUE (t),
+				  fn, data, pfd->visited,
+				  pfd->any_p,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
       break;
 
     case METHOD_TYPE:
       /* Since we're not going to walk subtrees, we have to do this
 	 explicitly here.  */
-      if (for_each_template_parm (TYPE_METHOD_BASETYPE (t), fn, data,
-				  pfd->visited, pfd->include_nondeduced_p))
+      if (walk_template_parms (TYPE_METHOD_BASETYPE (t), fn, data,
+			       pfd->visited, pfd->any_p,
+			       pfd->include_nondeduced_p))
 	return error_mark_node;
       /* Fall through.  */
 
     case FUNCTION_TYPE:
       /* Check the return type.  */
-      if (for_each_template_parm (TREE_TYPE (t), fn, data, pfd->visited,
-				  pfd->include_nondeduced_p))
+      if (walk_template_parms (TREE_TYPE (t), fn, data,
+			       pfd->visited, pfd->any_p,
+			       pfd->include_nondeduced_p))
 	return error_mark_node;
 
       /* Check the parameter types.  Since default arguments are not
@@ -7823,8 +7832,9 @@  static tree
 	tree parm;
 
 	for (parm = TYPE_ARG_TYPES (t); parm; parm = TREE_CHAIN (parm))
-	  if (for_each_template_parm (TREE_VALUE (parm), fn, data,
-				      pfd->visited, pfd->include_nondeduced_p))
+	  if (walk_template_parms (TREE_VALUE (parm), fn, data,
+				   pfd->visited, pfd->any_p,
+				   pfd->include_nondeduced_p))
 	    return error_mark_node;
 
 	/* Since we've already handled the TYPE_ARG_TYPES, we don't
@@ -7836,37 +7846,46 @@  static tree
     case TYPEOF_TYPE:
     case UNDERLYING_TYPE:
       if (pfd->include_nondeduced_p
-	  && for_each_template_parm (TYPE_FIELDS (t), fn, data,
-				     pfd->visited, 
-				     pfd->include_nondeduced_p))
+	  && walk_template_parms (TYPE_FIELDS (t), fn, data,
+				  pfd->visited, pfd->any_p,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
       break;
 
     case FUNCTION_DECL:
     case VAR_DECL:
       if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)
-	  && for_each_template_parm (DECL_TI_ARGS (t), fn, data,
-				     pfd->visited, pfd->include_nondeduced_p))
+	  && walk_template_parms (DECL_TI_ARGS (t), fn, data,
+				  pfd->visited, pfd->any_p,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
       /* Fall through.  */
 
     case PARM_DECL:
     case CONST_DECL:
       if (TREE_CODE (t) == CONST_DECL && DECL_TEMPLATE_PARM_P (t)
-	  && for_each_template_parm (DECL_INITIAL (t), fn, data,
-				     pfd->visited, pfd->include_nondeduced_p))
+	  && walk_template_parms (DECL_INITIAL (t), fn, data,
+				  pfd->visited, pfd->any_p,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
       if (DECL_CONTEXT (t)
 	  && pfd->include_nondeduced_p
-	  && for_each_template_parm (DECL_CONTEXT (t), fn, data,
-				     pfd->visited, pfd->include_nondeduced_p))
+	  && walk_template_parms (DECL_CONTEXT (t), fn, data,
+				  pfd->visited, pfd->any_p,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
+      if (pfd->any_p && TREE_TYPE (t)
+	  && walk_template_parms (TREE_TYPE(t), fn, data,
+				  pfd->visited, pfd->any_p,
+				  pfd->include_nondeduced_p))
+	return error_mark_node;
       break;
 
     case BOUND_TEMPLATE_TEMPLATE_PARM:
       /* Record template parameters such as `T' inside `TT<T>'.  */
-      if (for_each_template_parm (TYPE_TI_ARGS (t), fn, data, pfd->visited,
-				  pfd->include_nondeduced_p))
+      if (walk_template_parms (TYPE_TI_ARGS (t), fn, data,
+			       pfd->visited, pfd->any_p,
+			       pfd->include_nondeduced_p))
 	return error_mark_node;
       /* Fall through.  */
 
@@ -7882,8 +7901,9 @@  static tree
     case TEMPLATE_DECL:
       /* A template template parameter is encountered.  */
       if (DECL_TEMPLATE_TEMPLATE_PARM_P (t)
-	  && for_each_template_parm (TREE_TYPE (t), fn, data, pfd->visited,
-				     pfd->include_nondeduced_p))
+	  && walk_template_parms (TREE_TYPE (t), fn, data,
+				  pfd->visited, pfd->any_p,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
 
       /* Already substituted template template parameter */
@@ -7892,19 +7912,25 @@  static tree
 
     case TYPENAME_TYPE:
       if (!fn
-	  || for_each_template_parm (TYPENAME_TYPE_FULLNAME (t), fn,
-				     data, pfd->visited, 
-				     pfd->include_nondeduced_p))
+	  || walk_template_parms (TYPENAME_TYPE_FULLNAME (t), fn,
+				  data, pfd->visited, pfd->any_p,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
       break;
 
     case CONSTRUCTOR:
       if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t))
 	  && pfd->include_nondeduced_p
-	  && for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE
-				     (TREE_TYPE (t)), fn, data,
-				     pfd->visited, pfd->include_nondeduced_p))
+	  && walk_template_parms (TYPE_PTRMEMFUNC_FN_TYPE
+				  (TREE_TYPE (t)), fn, data,
+				  pfd->visited, pfd->any_p,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
+      else if (pfd->any_p && TREE_TYPE (t)
+	       && walk_template_parms (TREE_TYPE (t), fn, data,
+				       pfd->visited, pfd->any_p,
+				       pfd->include_nondeduced_p))
+	return error_mark_node;
       break;
 
     case INDIRECT_REF:
@@ -7913,6 +7939,11 @@  static tree
 	 involving template parameters.  */
       if (!fn && !TREE_TYPE (t))
 	return error_mark_node;
+      else if (pfd->any_p && TREE_TYPE (t)
+	       && walk_template_parms  (TREE_TYPE (t), fn, data,
+					pfd->visited, pfd->any_p,
+					pfd->include_nondeduced_p))
+	return error_mark_node;
       break;
 
     case MODOP_EXPR:
@@ -7938,35 +7969,41 @@  static tree
   return NULL_TREE;
 }
 
-/* For each TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM,
-   BOUND_TEMPLATE_TEMPLATE_PARM or TEMPLATE_PARM_INDEX in T,
-   call FN with the parameter and the DATA.
-   If FN returns nonzero, the iteration is terminated, and
-   for_each_template_parm returns 1.  Otherwise, the iteration
-   continues.  If FN never returns a nonzero value, the value
-   returned by for_each_template_parm is 0.  If FN is NULL, it is
-   considered to be the function which always returns 1.
+/* Walk T looking for TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM,
+   BOUND_TEMPLATE_TEMPLATE_PARM or TEMPLATE_PARM_INDEX.
 
+   If ANY_P is true, return 1 if any, 0 otherwise.
+
+   If ANY_P is false, for each the iteration calls FN with the parameter
+   and the DATA.  If FN returns nonzero, the iteration is terminated,
+   and walk_template_parms returns 1.  Otherwise, the iteration continues.
+   If FN never returns a nonzero value, the value returned by
+   walk_template_parms is 0.  If FN is NULL, it is considered to be the
+   function which always returns 1.
+
    If INCLUDE_NONDEDUCED_P, then this routine will also visit template
    parameters that occur in non-deduced contexts.  When false, only
    visits those template parameters that can be deduced.  */
 
 static int
-for_each_template_parm (tree t, tree_fn_t fn, void* data,
-			struct pointer_set_t *visited,
-			bool include_nondeduced_p)
+walk_template_parms (tree t, tree_fn_t fn, void* data,
+		     struct pointer_set_t *visited,
+		     bool any_p, bool include_nondeduced_p)
 {
   struct pair_fn_data pfd;
   int result;
 
   /* Set up.  */
-  pfd.fn = fn;
+  /* When any_p is true, fn plays no role, thus make sure is NULL,
+     which simplifies a bit walk_template_parms_r.  */
+  pfd.fn = any_p ? NULL : fn;
   pfd.data = data;
+  pfd.any_p = any_p;
   pfd.include_nondeduced_p = include_nondeduced_p;
 
   /* Walk the tree.  (Conceptually, we would like to walk without
-     duplicates, but for_each_template_parm_r recursively calls
-     for_each_template_parm, so we would need to reorganize a fair
+     duplicates, but walk_template_parms_r recursively calls
+     walk_template_parms, so we would need to reorganize a fair
      bit to use walk_tree_without_duplicates, so we keep our own
      visited list.)  */
   if (visited)
@@ -7974,7 +8011,7 @@  static int
   else
     pfd.visited = pointer_set_create ();
   result = cp_walk_tree (&t,
-		         for_each_template_parm_r,
+		         walk_template_parms_r,
 		         &pfd,
 		         pfd.visited) != NULL_TREE;
 
@@ -8035,8 +8072,9 @@  uses_template_parms (tree t)
 int
 uses_template_parms_level (tree t, int level)
 {
-  return for_each_template_parm (t, template_parm_this_level_p, &level, NULL,
-				 /*include_nondeduced_p=*/true);
+  return walk_template_parms (t, template_parm_this_level_p, &level, NULL,
+			      /*any_p=*/false,
+			      /*include_nondeduced_p=*/true);
 }
 
 /* Returns TRUE iff INST is an instantiation we don't need to do in an
@@ -19744,6 +19782,30 @@  type_dependent_expression_p (tree expression)
   return (dependent_type_p (TREE_TYPE (expression)));
 }
 
+/* Returns TRUE if the EXPRESSION is instantiation-dependent, in the
+   sense defined by the ABI:
+
+   "An expression is instantiation-dependent if it is type-dependent
+   or value-dependent, or it has a subexpression that is type-dependent
+   or value-dependent."  */
+
+bool
+instantiation_dependent_expression_p (tree expression)
+{
+  if (!processing_template_decl)
+    return false;
+
+  if (expression == error_mark_node)
+    return false;
+
+  if (!TREE_TYPE (expression))
+    return true;
+
+  return walk_template_parms (expression, /*fn=*/NULL, NULL, NULL,
+			      /*any_p=*/true,
+			      /*include_nondeduced_p=*/true);
+}
+
 /* Like type_dependent_expression_p, but it also works while not processing
    a template definition, i.e. during substitution or mangling.  */
 
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 187012)
+++ cp/semantics.c	(working copy)
@@ -5168,8 +5168,7 @@  finish_decltype_type (tree expr, bool id_expressio
       return error_mark_node;
     }
 
-  /* FIXME instantiation-dependent  */
-  if (type_dependent_expression_p (expr)
+  if (instantiation_dependent_expression_p (expr)
       /* In a template, a COMPONENT_REF has an IDENTIFIER_NODE for op1 even
 	 if it isn't dependent, so that we can check access control at
 	 instantiation time, so defer the decltype as well (PR 42277).  */
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 187012)
+++ cp/cp-tree.h	(working copy)
@@ -5363,6 +5363,7 @@  extern bool any_type_dependent_arguments_p      (c
 extern bool any_type_dependent_elements_p       (const_tree);
 extern bool type_dependent_expression_p_push	(tree);
 extern bool value_dependent_expression_p	(tree);
+extern bool instantiation_dependent_expression_p(tree);
 extern bool any_value_dependent_elements_p      (const_tree);
 extern bool dependent_omp_for_p			(tree, tree, tree, tree);
 extern tree resolve_typename_type		(tree, bool);