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.carl...@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.carl...@oracle.com>
PR c++/51222
* g++.dg/cpp0x/decltype37.C: New.
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);