Hi,
On 05/02/2012 03:47 AM, Jason Merrill wrote:
On 05/01/2012 08:14 PM, Paolo Carlini wrote:
I think we need to handle FIELD_DECL, too.
Are there hopes that handling FIELD_DECL like FUNCTION_DECL and VAR_DECL
(besides the DECL_LANG_SPECIFIC check) would work?
I would think so.
Ok, if we want it, I adjusted the code, see attached.
A data point I can give you, I put a gcc_assert (TREE_CODE (t) !=
FIELD_DECL) in the default case of the walk_template_parms_r switch,
and it never triggers for the whole testsuite.
With your patch, what happens if you have a member access like
template <class T>
struct A
{
T t;
auto f(A a) -> decltype (sizeof (a.t)) { }
};
I would expect that to hit the FIELD_DECL case.
Well, not really. The first time walk_template_parms_r is called, t is a
SIZEOF_EXPR which remains unhandled, the function returns NULL_TREE. The
second time, t is a COMPONENT_REF, thus !TYPE_P (t) is true, TREE_TYPE
is NULL, the function immediately returns error_mark_node and the
iteration ends (with the correct result that the expression is
instantiation-dependent).
Does it make sense?
Anyway, the attached appear to also pass the testsuite, I could test it
more completely tomorrow. If the FIELD_DECL bits seem safe to have... ;)
Thanks,
Paolo.
Index: pt.c
===================================================================
--- pt.c (revision 187012)
+++ 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,
+ /*check_types=*/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,
+ /*check_types=*/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,26 +7752,34 @@ struct pair_fn_data
{
tree_fn_t fn;
void *data;
+ bool check_types;
/* 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;
tree_fn_t fn = pfd->fn;
void *data = pfd->data;
+ /* If the type is null, this is a type-dependent expression, and if
+ we're checking types, we would find the relevant template parameters.
+ And fn must be null, so we can just return. */
+ if (pfd->check_types && !TYPE_P (t) && TREE_TYPE (t) == NULL_TREE)
+ return error_mark_node;
+
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->check_types,
+ pfd->include_nondeduced_p))
return error_mark_node;
switch (TREE_CODE (t))
@@ -7783,34 +7793,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->check_types,
+ 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->check_types,
+ pfd->include_nondeduced_p)
+ || walk_template_parms (TYPE_MAX_VALUE (t),
+ fn, data, pfd->visited,
+ pfd->check_types,
+ 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->check_types,
+ 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->check_types,
+ pfd->include_nondeduced_p))
return error_mark_node;
/* Check the parameter types. Since default arguments are not
@@ -7823,8 +7838,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->check_types,
+ pfd->include_nondeduced_p))
return error_mark_node;
/* Since we've already handled the TYPE_ARG_TYPES, we don't
@@ -7836,37 +7852,48 @@ 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->check_types,
+ 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))
+ case FIELD_DECL:
+ if ((TREE_CODE (t) == FIELD_DECL
+ || DECL_LANG_SPECIFIC (t)) && DECL_TEMPLATE_INFO (t)
+ && walk_template_parms (DECL_TI_ARGS (t), fn, data,
+ pfd->visited, pfd->check_types,
+ 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->check_types,
+ 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->check_types,
+ pfd->include_nondeduced_p))
return error_mark_node;
+ if (pfd->check_types && TREE_TYPE (t)
+ && walk_template_parms (TREE_TYPE(t), fn, data,
+ pfd->visited, pfd->check_types,
+ 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->check_types,
+ pfd->include_nondeduced_p))
return error_mark_node;
/* Fall through. */
@@ -7882,8 +7909,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->check_types,
+ pfd->include_nondeduced_p))
return error_mark_node;
/* Already substituted template template parameter */
@@ -7892,44 +7920,27 @@ 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->check_types,
+ 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->check_types,
+ pfd->include_nondeduced_p))
return error_mark_node;
- break;
-
- case INDIRECT_REF:
- case COMPONENT_REF:
- /* If there's no type, then this thing must be some expression
- involving template parameters. */
- if (!fn && !TREE_TYPE (t))
+ else if (pfd->check_types && TREE_TYPE (t)
+ && walk_template_parms (TREE_TYPE (t), fn, data,
+ pfd->visited, pfd->check_types,
+ pfd->include_nondeduced_p))
return error_mark_node;
break;
- 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;
-
default:
break;
}
@@ -7938,35 +7949,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 CHECK_TYPES, return 1 if any, 0 otherwise.
+
+ If FN is non-null, 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 check_types, bool include_nondeduced_p)
{
struct pair_fn_data pfd;
int result;
+ gcc_assert (!check_types || !fn);
+
/* Set up. */
pfd.fn = fn;
pfd.data = data;
+ pfd.check_types = check_types;
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 +7991,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 +8052,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,
+ /*check_types=*/false,
+ /*include_nondeduced_p=*/true);
}
/* Returns TRUE iff INST is an instantiation we don't need to do in an
@@ -19744,6 +19762,27 @@ 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;
+
+ return walk_template_parms (expression, /*fn=*/NULL, NULL, NULL,
+ /*check_types=*/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: semantics.c
===================================================================
--- semantics.c (revision 187012)
+++ 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). */
@@ -8171,7 +8170,7 @@ potential_constant_expression_1 (tree t, bool want
/* -- a reinterpret_cast. FIXME not implemented, and this rule
may change to something more specific to type-punning (DR 1312). */
{
- tree from = TREE_OPERAND (t, 0);
+ tree from = TREE_OPERAND (t, 0);
return (potential_constant_expression_1
(from, TREE_CODE (t) != VIEW_CONVERT_EXPR, flags));
}
Index: cp-tree.h
===================================================================
--- cp-tree.h (revision 187012)
+++ 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);