mirror of git://gcc.gnu.org/git/gcc.git
Allow partial specialization of variable templates.
* cp-tree.h (TINFO_USED_TEMPLATE_ID): New. * decl.c (duplicate_decls): Copy it. * error.c (dump_decl) [TEMPLATE_ID_EXPR]: Handle variables. * parser.c (cp_parser_decltype_expr): Do call finish_id_expression on template-ids. * pt.c (register_specialization): Remember variable template insts. (instantiate_template_1): Find the matching partial specialization. (check_explicit_specialization): Allow variable partial specialization. (process_partial_specialization): Likewise. (push_template_decl_real): Likewise. (more_specialized_partial_spec): Rename from more_specialized_class. (most_specialized_partial_spec): Rename from most_specialized_class. (get_partial_spec_bindings): Rename from get_class_bindings. From-SVN: r218104
This commit is contained in:
parent
d896cc4d45
commit
a2033ab107
|
|
@ -1,3 +1,20 @@
|
||||||
|
2014-11-26 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
|
Allow partial specialization of variable templates.
|
||||||
|
* cp-tree.h (TINFO_USED_TEMPLATE_ID): New.
|
||||||
|
* decl.c (duplicate_decls): Copy it.
|
||||||
|
* error.c (dump_decl) [TEMPLATE_ID_EXPR]: Handle variables.
|
||||||
|
* parser.c (cp_parser_decltype_expr): Do call finish_id_expression
|
||||||
|
on template-ids.
|
||||||
|
* pt.c (register_specialization): Remember variable template insts.
|
||||||
|
(instantiate_template_1): Find the matching partial specialization.
|
||||||
|
(check_explicit_specialization): Allow variable partial specialization.
|
||||||
|
(process_partial_specialization): Likewise.
|
||||||
|
(push_template_decl_real): Likewise.
|
||||||
|
(more_specialized_partial_spec): Rename from more_specialized_class.
|
||||||
|
(most_specialized_partial_spec): Rename from most_specialized_class.
|
||||||
|
(get_partial_spec_bindings): Rename from get_class_bindings.
|
||||||
|
|
||||||
2014-11-26 Paolo Carlini <paolo.carlini@oracle.com>
|
2014-11-26 Paolo Carlini <paolo.carlini@oracle.com>
|
||||||
|
|
||||||
PR c++/63757
|
PR c++/63757
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@ c-common.h, not after.
|
||||||
QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF)
|
QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF)
|
||||||
DECLTYPE_FOR_INIT_CAPTURE (in DECLTYPE_TYPE)
|
DECLTYPE_FOR_INIT_CAPTURE (in DECLTYPE_TYPE)
|
||||||
CONSTRUCTOR_NO_IMPLICIT_ZERO (in CONSTRUCTOR)
|
CONSTRUCTOR_NO_IMPLICIT_ZERO (in CONSTRUCTOR)
|
||||||
|
TINFO_USED_TEMPLATE_ID (in TEMPLATE_INFO)
|
||||||
2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE)
|
2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE)
|
||||||
ICS_THIS_FLAG (in _CONV)
|
ICS_THIS_FLAG (in _CONV)
|
||||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
|
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
|
||||||
|
|
@ -801,6 +802,12 @@ typedef struct qualified_typedef_usage_s qualified_typedef_usage_t;
|
||||||
#define FNDECL_HAS_ACCESS_ERRORS(NODE) \
|
#define FNDECL_HAS_ACCESS_ERRORS(NODE) \
|
||||||
(TINFO_HAS_ACCESS_ERRORS (DECL_TEMPLATE_INFO (NODE)))
|
(TINFO_HAS_ACCESS_ERRORS (DECL_TEMPLATE_INFO (NODE)))
|
||||||
|
|
||||||
|
/* Non-zero if this variable template specialization was specified using a
|
||||||
|
template-id, so it's a partial or full specialization and not a definition
|
||||||
|
of the member template of a particular class specialization. */
|
||||||
|
#define TINFO_USED_TEMPLATE_ID(NODE) \
|
||||||
|
(TREE_LANG_FLAG_1 (TEMPLATE_INFO_CHECK (NODE)))
|
||||||
|
|
||||||
struct GTY(()) tree_template_info {
|
struct GTY(()) tree_template_info {
|
||||||
struct tree_common common;
|
struct tree_common common;
|
||||||
vec<qualified_typedef_usage_t, va_gc> *typedefs_needing_access_checking;
|
vec<qualified_typedef_usage_t, va_gc> *typedefs_needing_access_checking;
|
||||||
|
|
|
||||||
|
|
@ -2137,7 +2137,14 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
|
||||||
DECL_LANG_SPECIFIC (newdecl)->u.min.u2 =
|
DECL_LANG_SPECIFIC (newdecl)->u.min.u2 =
|
||||||
DECL_LANG_SPECIFIC (olddecl)->u.min.u2;
|
DECL_LANG_SPECIFIC (olddecl)->u.min.u2;
|
||||||
if (DECL_TEMPLATE_INFO (newdecl))
|
if (DECL_TEMPLATE_INFO (newdecl))
|
||||||
new_template_info = DECL_TEMPLATE_INFO (newdecl);
|
{
|
||||||
|
new_template_info = DECL_TEMPLATE_INFO (newdecl);
|
||||||
|
if (DECL_TEMPLATE_INSTANTIATION (olddecl)
|
||||||
|
&& DECL_TEMPLATE_SPECIALIZATION (newdecl))
|
||||||
|
/* Remember the presence of explicit specialization args. */
|
||||||
|
TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (olddecl))
|
||||||
|
= TINFO_USED_TEMPLATE_ID (new_template_info);
|
||||||
|
}
|
||||||
DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
|
DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
|
||||||
}
|
}
|
||||||
/* Only functions have these fields. */
|
/* Only functions have these fields. */
|
||||||
|
|
|
||||||
|
|
@ -1212,7 +1212,9 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
|
||||||
tree args = TREE_OPERAND (t, 1);
|
tree args = TREE_OPERAND (t, 1);
|
||||||
|
|
||||||
if (is_overloaded_fn (name))
|
if (is_overloaded_fn (name))
|
||||||
name = DECL_NAME (get_first_fn (name));
|
name = get_first_fn (name);
|
||||||
|
if (DECL_P (name))
|
||||||
|
name = DECL_NAME (name);
|
||||||
dump_decl (pp, name, flags);
|
dump_decl (pp, name, flags);
|
||||||
pp_cxx_begin_template_argument_list (pp);
|
pp_cxx_begin_template_argument_list (pp);
|
||||||
if (args == error_mark_node)
|
if (args == error_mark_node)
|
||||||
|
|
|
||||||
|
|
@ -12175,7 +12175,6 @@ cp_parser_decltype_expr (cp_parser *parser,
|
||||||
|
|
||||||
if (expr
|
if (expr
|
||||||
&& expr != error_mark_node
|
&& expr != error_mark_node
|
||||||
&& TREE_CODE (expr) != TEMPLATE_ID_EXPR
|
|
||||||
&& TREE_CODE (expr) != TYPE_DECL
|
&& TREE_CODE (expr) != TYPE_DECL
|
||||||
&& (TREE_CODE (expr) != BIT_NOT_EXPR
|
&& (TREE_CODE (expr) != BIT_NOT_EXPR
|
||||||
|| !TYPE_P (TREE_OPERAND (expr, 0)))
|
|| !TYPE_P (TREE_OPERAND (expr, 0)))
|
||||||
|
|
|
||||||
211
gcc/cp/pt.c
211
gcc/cp/pt.c
|
|
@ -129,7 +129,7 @@ static int unify (tree, tree, tree, tree, int, bool);
|
||||||
static void add_pending_template (tree);
|
static void add_pending_template (tree);
|
||||||
static tree reopen_tinst_level (struct tinst_level *);
|
static tree reopen_tinst_level (struct tinst_level *);
|
||||||
static tree tsubst_initializer_list (tree, tree);
|
static tree tsubst_initializer_list (tree, tree);
|
||||||
static tree get_class_bindings (tree, tree, tree, tree);
|
static tree get_partial_spec_bindings (tree, tree, tree, tree);
|
||||||
static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
|
static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
|
||||||
bool, bool);
|
bool, bool);
|
||||||
static tree coerce_innermost_template_parms (tree, tree, tree, tsubst_flags_t,
|
static tree coerce_innermost_template_parms (tree, tree, tree, tsubst_flags_t,
|
||||||
|
|
@ -173,7 +173,7 @@ static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
|
||||||
static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
|
static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
|
||||||
static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
|
static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
|
||||||
static void regenerate_decl_from_template (tree, tree);
|
static void regenerate_decl_from_template (tree, tree);
|
||||||
static tree most_specialized_class (tree, tsubst_flags_t);
|
static tree most_specialized_partial_spec (tree, tsubst_flags_t);
|
||||||
static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int);
|
static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int);
|
||||||
static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree);
|
static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree);
|
||||||
static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
|
static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
|
||||||
|
|
@ -1485,12 +1485,17 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
|
||||||
gcc_assert (tmpl && args && spec);
|
gcc_assert (tmpl && args && spec);
|
||||||
*entry = elt;
|
*entry = elt;
|
||||||
*slot = entry;
|
*slot = entry;
|
||||||
if (TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec)
|
if ((TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec)
|
||||||
&& PRIMARY_TEMPLATE_P (tmpl)
|
&& PRIMARY_TEMPLATE_P (tmpl)
|
||||||
&& DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE)
|
&& DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE)
|
||||||
/* TMPL is a forward declaration of a template function; keep a list
|
|| variable_template_p (tmpl))
|
||||||
|
/* If TMPL is a forward declaration of a template function, keep a list
|
||||||
of all specializations in case we need to reassign them to a friend
|
of all specializations in case we need to reassign them to a friend
|
||||||
template later in tsubst_friend_function. */
|
template later in tsubst_friend_function.
|
||||||
|
|
||||||
|
Also keep a list of all variable template instantiations so that
|
||||||
|
process_partial_specialization can check whether a later partial
|
||||||
|
specialization would have used it. */
|
||||||
DECL_TEMPLATE_INSTANTIATIONS (tmpl)
|
DECL_TEMPLATE_INSTANTIATIONS (tmpl)
|
||||||
= tree_cons (args, spec, DECL_TEMPLATE_INSTANTIATIONS (tmpl));
|
= tree_cons (args, spec, DECL_TEMPLATE_INSTANTIATIONS (tmpl));
|
||||||
}
|
}
|
||||||
|
|
@ -2471,13 +2476,24 @@ check_explicit_specialization (tree declarator,
|
||||||
/* This case handles bogus declarations like template <>
|
/* This case handles bogus declarations like template <>
|
||||||
template <class T> void f<int>(); */
|
template <class T> void f<int>(); */
|
||||||
|
|
||||||
if (uses_template_parms (declarator))
|
if (!uses_template_parms (declarator))
|
||||||
|
error ("template-id %qD in declaration of primary template",
|
||||||
|
declarator);
|
||||||
|
else if (variable_template_p (TREE_OPERAND (declarator, 0)))
|
||||||
|
{
|
||||||
|
/* Partial specialization of variable template. */
|
||||||
|
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
|
||||||
|
specialization = 1;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
else if (cxx_dialect < cxx14)
|
||||||
error ("non-type partial specialization %qD "
|
error ("non-type partial specialization %qD "
|
||||||
"is not allowed", declarator);
|
"is not allowed", declarator);
|
||||||
else
|
else
|
||||||
error ("template-id %qD in declaration of primary template",
|
error ("non-class, non-variable partial specialization %qD "
|
||||||
declarator);
|
"is not allowed", declarator);
|
||||||
return decl;
|
return decl;
|
||||||
|
ok:;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctype && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype))
|
if (ctype && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype))
|
||||||
|
|
@ -2516,9 +2532,10 @@ check_explicit_specialization (tree declarator,
|
||||||
{
|
{
|
||||||
tree tmpl = NULL_TREE;
|
tree tmpl = NULL_TREE;
|
||||||
tree targs = NULL_TREE;
|
tree targs = NULL_TREE;
|
||||||
|
bool was_template_id = (TREE_CODE (declarator) == TEMPLATE_ID_EXPR);
|
||||||
|
|
||||||
/* Make sure that the declarator is a TEMPLATE_ID_EXPR. */
|
/* Make sure that the declarator is a TEMPLATE_ID_EXPR. */
|
||||||
if (TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
|
if (!was_template_id)
|
||||||
{
|
{
|
||||||
tree fns;
|
tree fns;
|
||||||
|
|
||||||
|
|
@ -2585,7 +2602,7 @@ check_explicit_specialization (tree declarator,
|
||||||
else if (ctype != NULL_TREE
|
else if (ctype != NULL_TREE
|
||||||
&& (identifier_p (TREE_OPERAND (declarator, 0))))
|
&& (identifier_p (TREE_OPERAND (declarator, 0))))
|
||||||
{
|
{
|
||||||
// Ignore variable templates.
|
// We'll match variable templates in start_decl.
|
||||||
if (VAR_P (decl))
|
if (VAR_P (decl))
|
||||||
return decl;
|
return decl;
|
||||||
|
|
||||||
|
|
@ -2722,7 +2739,7 @@ check_explicit_specialization (tree declarator,
|
||||||
/* If this is a specialization of a member template of a
|
/* If this is a specialization of a member template of a
|
||||||
template class, we want to return the TEMPLATE_DECL, not
|
template class, we want to return the TEMPLATE_DECL, not
|
||||||
the specialization of it. */
|
the specialization of it. */
|
||||||
if (tsk == tsk_template)
|
if (tsk == tsk_template && !was_template_id)
|
||||||
{
|
{
|
||||||
tree result = DECL_TEMPLATE_RESULT (tmpl);
|
tree result = DECL_TEMPLATE_RESULT (tmpl);
|
||||||
SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
|
SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
|
||||||
|
|
@ -2747,6 +2764,9 @@ check_explicit_specialization (tree declarator,
|
||||||
/* Set up the DECL_TEMPLATE_INFO for DECL. */
|
/* Set up the DECL_TEMPLATE_INFO for DECL. */
|
||||||
DECL_TEMPLATE_INFO (decl) = build_template_info (tmpl, targs);
|
DECL_TEMPLATE_INFO (decl) = build_template_info (tmpl, targs);
|
||||||
|
|
||||||
|
if (was_template_id)
|
||||||
|
TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (decl)) = true;
|
||||||
|
|
||||||
/* Inherit default function arguments from the template
|
/* Inherit default function arguments from the template
|
||||||
DECL is specializing. */
|
DECL is specializing. */
|
||||||
if (DECL_FUNCTION_TEMPLATE_P (tmpl))
|
if (DECL_FUNCTION_TEMPLATE_P (tmpl))
|
||||||
|
|
@ -4087,8 +4107,9 @@ static tree
|
||||||
process_partial_specialization (tree decl)
|
process_partial_specialization (tree decl)
|
||||||
{
|
{
|
||||||
tree type = TREE_TYPE (decl);
|
tree type = TREE_TYPE (decl);
|
||||||
tree maintmpl = CLASSTYPE_TI_TEMPLATE (type);
|
tree tinfo = get_template_info (decl);
|
||||||
tree specargs = CLASSTYPE_TI_ARGS (type);
|
tree maintmpl = TI_TEMPLATE (tinfo);
|
||||||
|
tree specargs = TI_ARGS (tinfo);
|
||||||
tree inner_args = INNERMOST_TEMPLATE_ARGS (specargs);
|
tree inner_args = INNERMOST_TEMPLATE_ARGS (specargs);
|
||||||
tree main_inner_parms = DECL_INNERMOST_TEMPLATE_PARMS (maintmpl);
|
tree main_inner_parms = DECL_INNERMOST_TEMPLATE_PARMS (maintmpl);
|
||||||
tree inner_parms;
|
tree inner_parms;
|
||||||
|
|
@ -4173,11 +4194,11 @@ process_partial_specialization (tree decl)
|
||||||
|
|
||||||
The argument list of the specialization shall not be identical to
|
The argument list of the specialization shall not be identical to
|
||||||
the implicit argument list of the primary template. */
|
the implicit argument list of the primary template. */
|
||||||
if (comp_template_args
|
tree main_args
|
||||||
(inner_args,
|
= TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (maintmpl)));
|
||||||
INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE
|
if (comp_template_args (inner_args, INNERMOST_TEMPLATE_ARGS (main_args)))
|
||||||
(maintmpl)))))
|
error ("partial specialization %qD does not specialize "
|
||||||
error ("partial specialization %qT does not specialize any template arguments", type);
|
"any template arguments", decl);
|
||||||
|
|
||||||
/* A partial specialization that replaces multiple parameters of the
|
/* A partial specialization that replaces multiple parameters of the
|
||||||
primary template with a pack expansion is less specialized for those
|
primary template with a pack expansion is less specialized for those
|
||||||
|
|
@ -4317,7 +4338,8 @@ process_partial_specialization (tree decl)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We should only get here once. */
|
/* We should only get here once. */
|
||||||
gcc_assert (!COMPLETE_TYPE_P (type));
|
if (TREE_CODE (decl) == TYPE_DECL)
|
||||||
|
gcc_assert (!COMPLETE_TYPE_P (type));
|
||||||
|
|
||||||
tree tmpl = build_template_decl (decl, current_template_parms,
|
tree tmpl = build_template_decl (decl, current_template_parms,
|
||||||
DECL_MEMBER_TEMPLATE_P (maintmpl));
|
DECL_MEMBER_TEMPLATE_P (maintmpl));
|
||||||
|
|
@ -4335,15 +4357,21 @@ process_partial_specialization (tree decl)
|
||||||
for (inst = DECL_TEMPLATE_INSTANTIATIONS (maintmpl); inst;
|
for (inst = DECL_TEMPLATE_INSTANTIATIONS (maintmpl); inst;
|
||||||
inst = TREE_CHAIN (inst))
|
inst = TREE_CHAIN (inst))
|
||||||
{
|
{
|
||||||
tree inst_type = TREE_VALUE (inst);
|
tree instance = TREE_VALUE (inst);
|
||||||
if (COMPLETE_TYPE_P (inst_type)
|
if (TYPE_P (instance)
|
||||||
&& CLASSTYPE_IMPLICIT_INSTANTIATION (inst_type))
|
? (COMPLETE_TYPE_P (instance)
|
||||||
|
&& CLASSTYPE_IMPLICIT_INSTANTIATION (instance))
|
||||||
|
: DECL_TEMPLATE_INSTANTIATION (instance))
|
||||||
{
|
{
|
||||||
tree spec = most_specialized_class (inst_type, tf_none);
|
tree spec = most_specialized_partial_spec (instance, tf_none);
|
||||||
if (spec && TREE_TYPE (spec) == type)
|
if (spec && TREE_VALUE (spec) == tmpl)
|
||||||
permerror (input_location,
|
{
|
||||||
"partial specialization of %qT after instantiation "
|
tree inst_decl = (DECL_P (instance)
|
||||||
"of %qT", type, inst_type);
|
? instance : TYPE_NAME (instance));
|
||||||
|
permerror (input_location,
|
||||||
|
"partial specialization of %qD after instantiation "
|
||||||
|
"of %qD", decl, inst_decl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4692,9 +4720,13 @@ push_template_decl_real (tree decl, bool is_friend)
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
|
|
||||||
/* See if this is a partial specialization. */
|
/* See if this is a partial specialization. */
|
||||||
is_partial = (DECL_IMPLICIT_TYPEDEF_P (decl)
|
is_partial = ((DECL_IMPLICIT_TYPEDEF_P (decl)
|
||||||
&& TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
|
&& TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
|
||||||
&& CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)));
|
&& CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
|
||||||
|
|| (TREE_CODE (decl) == VAR_DECL
|
||||||
|
&& DECL_LANG_SPECIFIC (decl)
|
||||||
|
&& DECL_TEMPLATE_SPECIALIZATION (decl)
|
||||||
|
&& TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (decl))));
|
||||||
|
|
||||||
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl))
|
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl))
|
||||||
is_friend = true;
|
is_friend = true;
|
||||||
|
|
@ -9057,7 +9089,7 @@ instantiate_class_template_1 (tree type)
|
||||||
|
|
||||||
/* Determine what specialization of the original template to
|
/* Determine what specialization of the original template to
|
||||||
instantiate. */
|
instantiate. */
|
||||||
t = most_specialized_class (type, tf_warning_or_error);
|
t = most_specialized_partial_spec (type, tf_warning_or_error);
|
||||||
if (t == error_mark_node)
|
if (t == error_mark_node)
|
||||||
{
|
{
|
||||||
TYPE_BEING_DEFINED (type) = 1;
|
TYPE_BEING_DEFINED (type) = 1;
|
||||||
|
|
@ -10519,7 +10551,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
|
||||||
if (new_type == error_mark_node)
|
if (new_type == error_mark_node)
|
||||||
RETURN (error_mark_node);
|
RETURN (error_mark_node);
|
||||||
/* If we get a real template back, return it. This can happen in
|
/* If we get a real template back, return it. This can happen in
|
||||||
the context of most_specialized_class. */
|
the context of most_specialized_partial_spec. */
|
||||||
if (TREE_CODE (new_type) == TEMPLATE_DECL)
|
if (TREE_CODE (new_type) == TEMPLATE_DECL)
|
||||||
return new_type;
|
return new_type;
|
||||||
|
|
||||||
|
|
@ -15878,9 +15910,28 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
|
||||||
complain, gen_tmpl, true);
|
complain, gen_tmpl, true);
|
||||||
push_nested_class (ctx);
|
push_nested_class (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tree pattern = DECL_TEMPLATE_RESULT (gen_tmpl);
|
||||||
|
|
||||||
|
if (VAR_P (pattern))
|
||||||
|
{
|
||||||
|
/* We need to determine if we're using a partial or explicit
|
||||||
|
specialization now, because the type of the variable could be
|
||||||
|
different. */
|
||||||
|
tree tid = lookup_template_variable (gen_tmpl, targ_ptr);
|
||||||
|
tree elt = most_specialized_partial_spec (tid, complain);
|
||||||
|
if (elt == error_mark_node)
|
||||||
|
pattern = error_mark_node;
|
||||||
|
else if (elt)
|
||||||
|
{
|
||||||
|
tmpl = TREE_VALUE (elt);
|
||||||
|
pattern = DECL_TEMPLATE_RESULT (tmpl);
|
||||||
|
targ_ptr = TREE_PURPOSE (elt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Substitute template parameters to obtain the specialization. */
|
/* Substitute template parameters to obtain the specialization. */
|
||||||
fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl),
|
fndecl = tsubst (pattern, targ_ptr, complain, gen_tmpl);
|
||||||
targ_ptr, complain, gen_tmpl);
|
|
||||||
if (DECL_CLASS_SCOPE_P (gen_tmpl))
|
if (DECL_CLASS_SCOPE_P (gen_tmpl))
|
||||||
pop_nested_class ();
|
pop_nested_class ();
|
||||||
pop_from_top_level ();
|
pop_from_top_level ();
|
||||||
|
|
@ -18881,8 +18932,8 @@ more_specialized_fn (tree pat1, tree pat2, int len)
|
||||||
/* Determine which of two partial specializations of TMPL is more
|
/* Determine which of two partial specializations of TMPL is more
|
||||||
specialized.
|
specialized.
|
||||||
|
|
||||||
PAT1 is a TREE_LIST whose TREE_TYPE is the _TYPE node corresponding
|
PAT1 is a TREE_LIST whose TREE_VALUE is the TEMPLATE_DECL corresponding
|
||||||
to the first partial specialization. The TREE_VALUE is the
|
to the first partial specialization. The TREE_PURPOSE is the
|
||||||
innermost set of template parameters for the partial
|
innermost set of template parameters for the partial
|
||||||
specialization. PAT2 is similar, but for the second template.
|
specialization. PAT2 is similar, but for the second template.
|
||||||
|
|
||||||
|
|
@ -18894,33 +18945,32 @@ more_specialized_fn (tree pat1, tree pat2, int len)
|
||||||
two templates is more specialized. */
|
two templates is more specialized. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
more_specialized_class (tree tmpl, tree pat1, tree pat2)
|
more_specialized_partial_spec (tree tmpl, tree pat1, tree pat2)
|
||||||
{
|
{
|
||||||
tree targs;
|
tree targs;
|
||||||
tree tmpl1, tmpl2;
|
|
||||||
int winner = 0;
|
int winner = 0;
|
||||||
bool any_deductions = false;
|
bool any_deductions = false;
|
||||||
|
|
||||||
tmpl1 = TREE_TYPE (pat1);
|
tree tmpl1 = TREE_VALUE (pat1);
|
||||||
tmpl2 = TREE_TYPE (pat2);
|
tree tmpl2 = TREE_VALUE (pat2);
|
||||||
|
tree parms1 = DECL_INNERMOST_TEMPLATE_PARMS (tmpl1);
|
||||||
|
tree parms2 = DECL_INNERMOST_TEMPLATE_PARMS (tmpl2);
|
||||||
|
tree specargs1 = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl1)));
|
||||||
|
tree specargs2 = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl2)));
|
||||||
|
|
||||||
/* Just like what happens for functions, if we are ordering between
|
/* Just like what happens for functions, if we are ordering between
|
||||||
different class template specializations, we may encounter dependent
|
different template specializations, we may encounter dependent
|
||||||
types in the arguments, and we need our dependency check functions
|
types in the arguments, and we need our dependency check functions
|
||||||
to behave correctly. */
|
to behave correctly. */
|
||||||
++processing_template_decl;
|
++processing_template_decl;
|
||||||
targs = get_class_bindings (tmpl, TREE_VALUE (pat1),
|
targs = get_partial_spec_bindings (tmpl, parms1, specargs1, specargs2);
|
||||||
CLASSTYPE_TI_ARGS (tmpl1),
|
|
||||||
CLASSTYPE_TI_ARGS (tmpl2));
|
|
||||||
if (targs)
|
if (targs)
|
||||||
{
|
{
|
||||||
--winner;
|
--winner;
|
||||||
any_deductions = true;
|
any_deductions = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
targs = get_class_bindings (tmpl, TREE_VALUE (pat2),
|
targs = get_partial_spec_bindings (tmpl, parms2, specargs2, specargs1);
|
||||||
CLASSTYPE_TI_ARGS (tmpl2),
|
|
||||||
CLASSTYPE_TI_ARGS (tmpl1));
|
|
||||||
if (targs)
|
if (targs)
|
||||||
{
|
{
|
||||||
++winner;
|
++winner;
|
||||||
|
|
@ -18928,7 +18978,7 @@ more_specialized_class (tree tmpl, tree pat1, tree pat2)
|
||||||
}
|
}
|
||||||
--processing_template_decl;
|
--processing_template_decl;
|
||||||
|
|
||||||
/* In the case of a tie where at least one of the class templates
|
/* In the case of a tie where at least one of the templates
|
||||||
has a parameter pack at the end, the template with the most
|
has a parameter pack at the end, the template with the most
|
||||||
non-packed parameters wins. */
|
non-packed parameters wins. */
|
||||||
if (winner == 0
|
if (winner == 0
|
||||||
|
|
@ -19014,7 +19064,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
|
||||||
is bound to `double'. */
|
is bound to `double'. */
|
||||||
|
|
||||||
static tree
|
static tree
|
||||||
get_class_bindings (tree tmpl, tree tparms, tree spec_args, tree args)
|
get_partial_spec_bindings (tree tmpl, tree tparms, tree spec_args, tree args)
|
||||||
{
|
{
|
||||||
int i, ntparms = TREE_VEC_LENGTH (tparms);
|
int i, ntparms = TREE_VEC_LENGTH (tparms);
|
||||||
tree deduced_args;
|
tree deduced_args;
|
||||||
|
|
@ -19197,20 +19247,20 @@ most_general_template (tree decl)
|
||||||
return decl;
|
return decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the most specialized of the class template partial
|
/* Return the most specialized of the template partial specializations
|
||||||
specializations which can produce TYPE, a specialization of some class
|
which can produce TARGET, a specialization of some class or variable
|
||||||
template. The value returned is actually a TREE_LIST; the TREE_TYPE is
|
template. The value returned is actually a TREE_LIST; the TREE_VALUE is
|
||||||
a _TYPE node corresponding to the partial specialization, while the
|
a TEMPLATE_DECL node corresponding to the partial specialization, while
|
||||||
TREE_PURPOSE is the set of template arguments that must be
|
the TREE_PURPOSE is the set of template arguments that must be
|
||||||
substituted into the TREE_TYPE in order to generate TYPE.
|
substituted into the template pattern in order to generate TARGET.
|
||||||
|
|
||||||
If the choice of partial specialization is ambiguous, a diagnostic
|
If the choice of partial specialization is ambiguous, a diagnostic
|
||||||
is issued, and the error_mark_node is returned. If there are no
|
is issued, and the error_mark_node is returned. If there are no
|
||||||
partial specializations matching TYPE, then NULL_TREE is
|
partial specializations matching TARGET, then NULL_TREE is
|
||||||
returned, indicating that the primary template should be used. */
|
returned, indicating that the primary template should be used. */
|
||||||
|
|
||||||
static tree
|
static tree
|
||||||
most_specialized_class (tree type, tsubst_flags_t complain)
|
most_specialized_partial_spec (tree target, tsubst_flags_t complain)
|
||||||
{
|
{
|
||||||
tree list = NULL_TREE;
|
tree list = NULL_TREE;
|
||||||
tree t;
|
tree t;
|
||||||
|
|
@ -19218,10 +19268,29 @@ most_specialized_class (tree type, tsubst_flags_t complain)
|
||||||
int fate;
|
int fate;
|
||||||
bool ambiguous_p;
|
bool ambiguous_p;
|
||||||
tree outer_args = NULL_TREE;
|
tree outer_args = NULL_TREE;
|
||||||
|
tree tmpl, args;
|
||||||
|
|
||||||
|
if (TYPE_P (target))
|
||||||
|
{
|
||||||
|
tree tinfo = CLASSTYPE_TEMPLATE_INFO (target);
|
||||||
|
tmpl = TI_TEMPLATE (tinfo);
|
||||||
|
args = TI_ARGS (tinfo);
|
||||||
|
}
|
||||||
|
else if (TREE_CODE (target) == TEMPLATE_ID_EXPR)
|
||||||
|
{
|
||||||
|
tmpl = TREE_OPERAND (target, 0);
|
||||||
|
args = TREE_OPERAND (target, 1);
|
||||||
|
}
|
||||||
|
else if (VAR_P (target))
|
||||||
|
{
|
||||||
|
tree tinfo = DECL_TEMPLATE_INFO (target);
|
||||||
|
tmpl = TI_TEMPLATE (tinfo);
|
||||||
|
args = TI_ARGS (tinfo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gcc_unreachable ();
|
||||||
|
|
||||||
tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
|
|
||||||
tree main_tmpl = most_general_template (tmpl);
|
tree main_tmpl = most_general_template (tmpl);
|
||||||
tree args = CLASSTYPE_TI_ARGS (type);
|
|
||||||
|
|
||||||
/* For determining which partial specialization to use, only the
|
/* For determining which partial specialization to use, only the
|
||||||
innermost args are interesting. */
|
innermost args are interesting. */
|
||||||
|
|
@ -19236,9 +19305,8 @@ most_specialized_class (tree type, tsubst_flags_t complain)
|
||||||
tree partial_spec_args;
|
tree partial_spec_args;
|
||||||
tree spec_args;
|
tree spec_args;
|
||||||
tree spec_tmpl = TREE_VALUE (t);
|
tree spec_tmpl = TREE_VALUE (t);
|
||||||
tree orig_parms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl);
|
|
||||||
|
|
||||||
partial_spec_args = CLASSTYPE_TI_ARGS (TREE_TYPE (t));
|
partial_spec_args = TREE_PURPOSE (t);
|
||||||
|
|
||||||
++processing_template_decl;
|
++processing_template_decl;
|
||||||
|
|
||||||
|
|
@ -19269,14 +19337,14 @@ most_specialized_class (tree type, tsubst_flags_t complain)
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
|
|
||||||
tree parms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl);
|
tree parms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl);
|
||||||
spec_args = get_class_bindings (tmpl, parms,
|
spec_args = get_partial_spec_bindings (tmpl, parms,
|
||||||
partial_spec_args,
|
partial_spec_args,
|
||||||
args);
|
args);
|
||||||
if (spec_args)
|
if (spec_args)
|
||||||
{
|
{
|
||||||
if (outer_args)
|
if (outer_args)
|
||||||
spec_args = add_to_template_args (outer_args, spec_args);
|
spec_args = add_to_template_args (outer_args, spec_args);
|
||||||
list = tree_cons (spec_args, orig_parms, list);
|
list = tree_cons (spec_args, TREE_VALUE (t), list);
|
||||||
TREE_TYPE (list) = TREE_TYPE (t);
|
TREE_TYPE (list) = TREE_TYPE (t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -19290,7 +19358,7 @@ most_specialized_class (tree type, tsubst_flags_t complain)
|
||||||
t = TREE_CHAIN (t);
|
t = TREE_CHAIN (t);
|
||||||
for (; t; t = TREE_CHAIN (t))
|
for (; t; t = TREE_CHAIN (t))
|
||||||
{
|
{
|
||||||
fate = more_specialized_class (tmpl, champ, t);
|
fate = more_specialized_partial_spec (tmpl, champ, t);
|
||||||
if (fate == 1)
|
if (fate == 1)
|
||||||
;
|
;
|
||||||
else
|
else
|
||||||
|
|
@ -19311,7 +19379,7 @@ most_specialized_class (tree type, tsubst_flags_t complain)
|
||||||
if (!ambiguous_p)
|
if (!ambiguous_p)
|
||||||
for (t = list; t && t != champ; t = TREE_CHAIN (t))
|
for (t = list; t && t != champ; t = TREE_CHAIN (t))
|
||||||
{
|
{
|
||||||
fate = more_specialized_class (tmpl, champ, t);
|
fate = more_specialized_partial_spec (tmpl, champ, t);
|
||||||
if (fate != 1)
|
if (fate != 1)
|
||||||
{
|
{
|
||||||
ambiguous_p = true;
|
ambiguous_p = true;
|
||||||
|
|
@ -19325,11 +19393,16 @@ most_specialized_class (tree type, tsubst_flags_t complain)
|
||||||
char *spaces = NULL;
|
char *spaces = NULL;
|
||||||
if (!(complain & tf_error))
|
if (!(complain & tf_error))
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
error ("ambiguous class template instantiation for %q#T", type);
|
if (TYPE_P (target))
|
||||||
|
error ("ambiguous template instantiation for %q#T", target);
|
||||||
|
else
|
||||||
|
error ("ambiguous template instantiation for %q#D", target);
|
||||||
str = ngettext ("candidate is:", "candidates are:", list_length (list));
|
str = ngettext ("candidate is:", "candidates are:", list_length (list));
|
||||||
for (t = list; t; t = TREE_CHAIN (t))
|
for (t = list; t; t = TREE_CHAIN (t))
|
||||||
{
|
{
|
||||||
error ("%s %+#T", spaces ? spaces : str, TREE_TYPE (t));
|
tree subst = build_tree_list (TREE_VALUE (t), TREE_PURPOSE (t));
|
||||||
|
inform (DECL_SOURCE_LOCATION (TREE_VALUE (t)),
|
||||||
|
"%s %#S", spaces ? spaces : str, subst);
|
||||||
spaces = spaces ? spaces : get_spaces (str);
|
spaces = spaces ? spaces : get_spaces (str);
|
||||||
}
|
}
|
||||||
free (spaces);
|
free (spaces);
|
||||||
|
|
|
||||||
|
|
@ -13,25 +13,25 @@ struct metatuple<add_pointer> {
|
||||||
};
|
};
|
||||||
|
|
||||||
template<template<class T> class Meta>
|
template<template<class T> class Meta>
|
||||||
struct metatuple<Meta, Meta> { // { dg-error "candidates" }
|
struct metatuple<Meta, Meta> { // { dg-message "candidates" }
|
||||||
static const int value = 2;
|
static const int value = 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<template<class T> class... Metafunctions>
|
template<template<class T> class... Metafunctions>
|
||||||
struct metatuple<add_pointer, Metafunctions...> { // { dg-error "" }
|
struct metatuple<add_pointer, Metafunctions...> { // { dg-message "" }
|
||||||
static const int value = 3;
|
static const int value = 3;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<template<class T> class First,
|
template<template<class T> class First,
|
||||||
template<class T> class... Metafunctions>
|
template<class T> class... Metafunctions>
|
||||||
struct metatuple<First, Metafunctions...> { // { dg-error "struct" }
|
struct metatuple<First, Metafunctions...> { // { dg-message "struct" }
|
||||||
static const int value = 4;
|
static const int value = 4;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<template<class T> class First,
|
template<template<class T> class First,
|
||||||
template<class T> class Second,
|
template<class T> class Second,
|
||||||
template<class T> class... Metafunctions>
|
template<class T> class... Metafunctions>
|
||||||
struct metatuple<First, Second, Metafunctions...> { // { dg-error "struct" }
|
struct metatuple<First, Second, Metafunctions...> { // { dg-message "struct" }
|
||||||
static const int value = 5;
|
static const int value = 5;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
// { dg-do compile { target c++14 } }
|
||||||
|
|
||||||
|
template <class T> T t = 42;
|
||||||
|
template <class T> T* t<T*> = nullptr;
|
||||||
|
|
||||||
|
void *p = t<void*>;
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
// DR 1727: a specialization doesn't need to have the same type
|
||||||
|
// { dg-do compile { target c++14 } }
|
||||||
|
|
||||||
|
template <class T> T t = 42;
|
||||||
|
template <class T> int t<T*> = 0;
|
||||||
|
|
||||||
|
template<class T, class U> struct same;
|
||||||
|
template<class T> struct same<T,T> {};
|
||||||
|
same<int,decltype(t<void*>)> s;
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
// { dg-do compile { target c++14 } }
|
||||||
|
|
||||||
|
template <class T> T t1 = 42;
|
||||||
|
template <class T> T* t1<T> = nullptr; // { dg-error "partial" }
|
||||||
|
|
||||||
|
template <class T> T t2 = 42;
|
||||||
|
template <class T> T* t2<T*> = nullptr;
|
||||||
|
template <class T> T* t2<T*> = nullptr; // { dg-error "redefinition" }
|
||||||
|
|
||||||
|
template <class T, class U> T t3 = U();
|
||||||
|
template <class T> T t3<T,int> = 42;
|
||||||
|
template <class U> int t3<int,U> = U();
|
||||||
|
|
||||||
|
int i = t3<int,int>; // { dg-error "ambiguous" }
|
||||||
|
|
||||||
|
template <class T> T t4 = T();
|
||||||
|
void *p = t4<void*>;
|
||||||
|
template <class T> T* t4<T*> = nullptr; // { dg-error "after instantiation" }
|
||||||
Loading…
Reference in New Issue