#include "tm.h"
#include "obstack.h"
#include "tree.h"
+#include "intl.h"
#include "pointer-set.h"
#include "flags.h"
#include "c-common.h"
static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree);
static tree tsubst_decl (tree, tree, tsubst_flags_t);
static void perform_typedefs_access_check (tree tmpl, tree targs);
-static void append_type_to_template_for_access_check_1 (tree, tree, tree);
+static void append_type_to_template_for_access_check_1 (tree, tree, tree,
+ location_t);
static hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
static tree listify (tree);
static tree listify_autos (tree, tree);
return error_mark_node;
}
+/* Create a template info node. */
+
+tree
+build_template_info (tree template_decl, tree template_args)
+{
+ tree result = make_node (TEMPLATE_INFO);
+ TI_TEMPLATE (result) = template_decl;
+ TI_ARGS (result) = template_args;
+ return result;
+}
+
/* Return the template info node corresponding to T, whatever T is. */
tree
function, member class or static data member of a class template
shall be declared in the namespace of which the class template is
a member. */
+ if (current_scope() != DECL_CONTEXT (tmpl)
+ && !at_namespace_scope_p ())
+ {
+ error ("specialization of %qD must appear at namespace scope", tmpl);
+ return false;
+ }
if (is_associated_namespace (current_namespace, tpl_ns))
/* Same or super-using namespace. */
return true;
if (!TYPE_P (arg))
STRIP_NOPS (arg);
+ if (TREE_CODE (arg) == ARGUMENT_PACK_SELECT)
+ /* We can get one of these when re-hashing a previous entry in the middle
+ of substituting into a pack expansion. Just look through it. */
+ arg = ARGUMENT_PACK_SELECT_FROM_PACK (arg);
+
code = TREE_CODE (arg);
tclass = TREE_CODE_CLASS (code);
case EXPR_PACK_EXPANSION:
return iterative_hash_template_arg (PACK_EXPANSION_PATTERN (arg), val);
- case ARGUMENT_PACK_SELECT:
- /* We can get one of these when re-hashing a previous entry in the middle
- of substituting into a pack expansion. Just look through it... */
- arg = ARGUMENT_PACK_SELECT_FROM_PACK (arg);
- /* ...and fall through. */
case TYPE_ARGUMENT_PACK:
case NONTYPE_ARGUMENT_PACK:
return iterative_hash_template_arg (ARGUMENT_PACK_ARGS (arg), val);
val = iterative_hash_object (code, val);
return iterative_hash_template_arg (TREE_OPERAND (arg, 2), val);
+ case ARRAY_TYPE:
+ /* layout_type sets structural equality for arrays of
+ incomplete type, so we can't rely on the canonical type
+ for hashing. */
+ val = iterative_hash_template_arg (TREE_TYPE (arg), val);
+ return iterative_hash_template_arg (TYPE_DOMAIN (arg), val);
+
default:
switch (tclass)
{
return !uses_template_parms (CLASSTYPE_TI_ARGS (type));
}
-/* Print the list of candidate FNS in an error message. */
+/* Print the list of functions at FNS, going through all the overloads
+ for each element of the list. Alternatively, FNS can not be a
+ TREE_LIST, in which case it will be printed together with all the
+ overloads.
-void
-print_candidates (tree fns)
+ MORE and *STR should respectively be FALSE and NULL when the function
+ is called from the outside. They are used internally on recursive
+ calls. print_candidates manages the two parameters and leaves NULL
+ in *STR when it ends. */
+
+static void
+print_candidates_1 (tree fns, bool more, const char **str)
{
- tree fn;
- tree f;
+ tree fn, fn2;
+ char *spaces = NULL;
+
+ for (fn = fns; fn; fn = OVL_NEXT (fn))
+ if (TREE_CODE (fn) == TREE_LIST)
+ {
+ gcc_assert (!OVL_NEXT (fn) && !is_overloaded_fn (fn));
+ for (fn2 = fn; fn2 != NULL_TREE; fn2 = TREE_CHAIN (fn2))
+ print_candidates_1 (TREE_VALUE (fn2),
+ TREE_CHAIN (fn2) || more, str);
+ }
+ else
+ {
+ if (!*str)
+ {
+ /* Pick the prefix string. */
+ if (!more && !OVL_NEXT (fns))
+ {
+ error ("candidate is: %+#D", OVL_CURRENT (fn));
+ continue;
+ }
- const char *str = "candidates are:";
+ *str = _("candidates are:");
+ spaces = get_spaces (*str);
+ }
+ error ("%s %+#D", *str, OVL_CURRENT (fn));
+ *str = spaces ? spaces : *str;
+ }
- if (is_overloaded_fn (fns))
+ if (!more)
{
- for (f = fns; f; f = OVL_NEXT (f))
- {
- error ("%s %+#D", str, OVL_CURRENT (f));
- str = " ";
- }
- }
- else for (fn = fns; fn != NULL_TREE; fn = TREE_CHAIN (fn))
- {
- for (f = TREE_VALUE (fn); f; f = OVL_NEXT (f))
- error ("%s %+#D", str, OVL_CURRENT (f));
- str = " ";
+ free (spaces);
+ *str = NULL;
}
}
+/* Print the list of candidate FNS in an error message. */
+
+void
+print_candidates (tree fns)
+{
+ const char *str = NULL;
+ print_candidates_1 (fns, false, &str);
+ gcc_assert (str == NULL);
+}
+
/* Returns the template (one of the functions given by TEMPLATE_ID)
which can be specialized to match the indicated DECL with the
explicit template args given in TEMPLATE_ID. The DECL may be
{
error ("template-id %qD for %q+D does not match any template "
"declaration", template_id, decl);
+ if (header_count && header_count != template_count + 1)
+ inform (input_location, "saw %d %<template<>%>, need %d for "
+ "specializing a member function template",
+ header_count, template_count + 1);
return error_mark_node;
}
else if ((templates && TREE_CHAIN (templates))
}
/* Set up the DECL_TEMPLATE_INFO for DECL. */
- DECL_TEMPLATE_INFO (decl) = tree_cons (tmpl, targs, NULL_TREE);
+ DECL_TEMPLATE_INFO (decl) = build_template_info (tmpl, targs);
/* Inherit default function arguments from the template
DECL is specializing. */
bool
function_parameter_expanded_from_pack_p (tree param_decl, tree pack)
{
- if (DECL_ARTIFICIAL (param_decl)
- || !function_parameter_pack_p (pack))
- return false;
-
- gcc_assert (DECL_NAME (param_decl) && DECL_NAME (pack));
+ if (DECL_ARTIFICIAL (param_decl)
+ || !function_parameter_pack_p (pack))
+ return false;
- /* The parameter pack and its pack arguments have the same
- DECL_PARM_INDEX. */
- return DECL_PARM_INDEX (pack) == DECL_PARM_INDEX (param_decl);
+ /* The parameter pack and its pack arguments have the same
+ DECL_PARM_INDEX. */
+ return DECL_PARM_INDEX (pack) == DECL_PARM_INDEX (param_decl);
}
/* Determine whether ARGS describes a variadic template args list,
case UNION_TYPE:
case ENUMERAL_TYPE:
if (TYPE_TEMPLATE_INFO (t))
- cp_walk_tree (&TREE_VALUE (TYPE_TEMPLATE_INFO (t)),
+ cp_walk_tree (&TI_ARGS (TYPE_TEMPLATE_INFO (t)),
&find_parameter_packs_r, ppd, ppd->visited);
*walk_subtrees = 0;
{
if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE
|| (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_DESCENDANTS (index))
- != TEMPLATE_PARM_LEVEL (index) - levels))
+ != TEMPLATE_PARM_LEVEL (index) - levels)
+ || !same_type_p (type, TREE_TYPE (TEMPLATE_PARM_DESCENDANTS (index))))
{
tree orig_decl = TEMPLATE_PARM_DECL (index);
tree decl, t;
|| (!packed_args && i < nargs - 1))
{
if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
- error ("parameter pack argument %qE must be at the end of the template argument list", arg);
+ error ("parameter pack argument %qE must be at the "
+ "end of the template argument list", arg);
else
- error ("parameter pack argument %qT must be at the end of the template argument list", arg);
-
- if (packed_args)
- TREE_VEC_ELT (packed_args, j) = error_mark_node;
+ error ("parameter pack argument %qT must be at the "
+ "end of the template argument list", arg);
}
}
DECL_TI_TEMPLATE (decl) = new_tmpl;
SET_DECL_TEMPLATE_SPECIALIZATION (new_tmpl);
DECL_TEMPLATE_INFO (new_tmpl)
- = tree_cons (tmpl, args, NULL_TREE);
+ = build_template_info (tmpl, args);
register_specialization (new_tmpl,
most_general_template (tmpl),
tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
if (TREE_CODE (parm) == TEMPLATE_DECL)
DECL_CONTEXT (parm) = tmpl;
+
+ if (TREE_CODE (TREE_TYPE (parm)) == TEMPLATE_TYPE_PARM)
+ DECL_CONTEXT (TYPE_NAME (TREE_TYPE (parm))) = tmpl;
}
}
if (DECL_TEMPLATE_INFO (tmpl))
args = add_outermost_template_args (DECL_TI_ARGS (tmpl), args);
- info = tree_cons (tmpl, args, NULL_TREE);
+ info = build_template_info (tmpl, args);
if (DECL_IMPLICIT_TYPEDEF_P (decl))
SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);
val = error_mark_node;
else if (val == error_mark_node && (complain & tf_error))
error ("could not convert template argument %qE to %qT", orig_arg, t);
+
+ if (TREE_CODE (val) == SCOPE_REF)
+ {
+ /* Strip typedefs from the SCOPE_REF. */
+ tree type = strip_typedefs (TREE_TYPE (val));
+ tree scope = strip_typedefs (TREE_OPERAND (val, 0));
+ val = build_qualified_name (type, scope, TREE_OPERAND (val, 1),
+ QUALIFIED_NAME_IS_TEMPLATE (val));
+ }
}
return val;
found = CLASSTYPE_TI_TEMPLATE (found);
}
- SET_TYPE_TEMPLATE_INFO (t, tree_cons (found, arglist, NULL_TREE));
+ SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist));
elt.spec = t;
slot = (spec_entry **) htab_find_slot_with_hash (type_specializations,
case ENUMERAL_TYPE:
if (!TYPE_TEMPLATE_INFO (t))
*walk_subtrees = 0;
- else if (for_each_template_parm (TREE_VALUE (TYPE_TEMPLATE_INFO (t)),
+ else if (for_each_template_parm (TI_ARGS (TYPE_TEMPLATE_INFO (t)),
fn, data, pfd->visited,
pfd->include_nondeduced_p))
return error_mark_node;
static void
perform_typedefs_access_check (tree tmpl, tree targs)
{
- tree t;
+ location_t saved_location;
+ int i;
+ qualified_typedef_usage_t *iter;
if (!tmpl
|| (!CLASS_TYPE_P (tmpl)
&& TREE_CODE (tmpl) != FUNCTION_DECL))
return;
- for (t = get_types_needing_access_check (tmpl); t; t = TREE_CHAIN (t))
+ saved_location = input_location;
+ for (i = 0;
+ VEC_iterate (qualified_typedef_usage_t,
+ get_types_needing_access_check (tmpl),
+ i, iter);
+ ++i)
{
- tree type_decl = TREE_PURPOSE (t);
- tree type_scope = TREE_VALUE (t);
+ tree type_decl = iter->typedef_decl;
+ tree type_scope = iter->context;
if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope))
continue;
if (uses_template_parms (type_scope))
type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE);
+ /* Make access check error messages point to the location
+ of the use of the typedef. */
+ input_location = iter->locus;
perform_or_defer_access_check (TYPE_BINFO (type_scope),
type_decl, type_decl);
}
+ input_location = saved_location;
}
tree
{
tree pattern;
tree pack, packs = NULL_TREE, unsubstituted_packs = NULL_TREE;
- tree first_arg_pack; int i, len = -1;
+ int i, len = -1;
tree result;
int incomplete = 0;
bool very_local_specializations = false;
incomplete = 1;
if (len < 0)
- {
- len = my_len;
- first_arg_pack = arg_pack;
- }
+ len = my_len;
else if (len != my_len)
{
if (incomplete)
gcc_assert (DECL_LANG_SPECIFIC (r) != 0);
TREE_CHAIN (r) = NULL_TREE;
- DECL_TEMPLATE_INFO (r) = build_tree_list (t, args);
+ DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
if (TREE_CODE (decl) == TYPE_DECL)
{
if (gen_tmpl)
{
DECL_TEMPLATE_INFO (r)
- = tree_cons (gen_tmpl, argvec, NULL_TREE);
+ = build_template_info (gen_tmpl, argvec);
SET_DECL_IMPLICIT_INSTANTIATION (r);
register_specialization (r, gen_tmpl, argvec, false, hash);
/* Create a new node for the specialization we need. */
r = copy_decl (t);
if (type == NULL_TREE)
- type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ {
+ if (is_typedef_decl (t))
+ type = DECL_ORIGINAL_TYPE (t);
+ else
+ type = TREE_TYPE (t);
+ type = tsubst (type, args, complain, in_decl);
+ }
if (TREE_CODE (r) == VAR_DECL)
{
/* Even if the original location is out of scope, the
}
determine_visibility (r);
}
- /* Preserve a typedef that names a type. */
- else if (TREE_CODE (r) == TYPE_DECL
- && DECL_ORIGINAL_TYPE (t)
- && type != error_mark_node)
- {
- DECL_ORIGINAL_TYPE (r) = tsubst (DECL_ORIGINAL_TYPE (t),
- args, complain, in_decl);
- TREE_TYPE (r) = type = build_variant_type_copy (type);
- TYPE_NAME (type) = r;
- }
if (!local_p)
{
DECL_EXTERNAL (r) = 1;
register_specialization (r, gen_tmpl, argvec, false, hash);
- DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE);
+ DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec);
SET_DECL_IMPLICIT_INSTANTIATION (r);
}
else if (cp_unevaluated_operand)
apply_late_template_attributes (&r, DECL_ATTRIBUTES (r),
(int) ATTR_FLAG_TYPE_IN_PLACE,
args, complain, in_decl);
+
+ /* Preserve a typedef that names a type. */
+ if (is_typedef_decl (r))
+ {
+ DECL_ORIGINAL_TYPE (r) = NULL_TREE;
+ set_underlying_type (r);
+ }
+
layout_decl (r, 0);
}
break;
return error_mark_node;
TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (r)
- = tree_cons (TYPE_TI_TEMPLATE (t), argvec, NULL_TREE);
+ = build_template_info (TYPE_TI_TEMPLATE (t), argvec);
}
}
break;
{
if (TREE_CODE (type) == VOID_TYPE)
error ("forming reference to void");
- else
- error ("forming %s to reference type %qT",
- (code == POINTER_TYPE) ? "pointer" : "reference",
- type);
+ else if (code == POINTER_TYPE)
+ error ("forming pointer to reference type %qT", type);
+ else
+ error ("forming reference to reference type %qT", type);
last_loc = input_location;
}
r = convert_from_reference (r);
}
else
- r = build_x_indirect_ref (r, "unary *", complain);
+ r = build_x_indirect_ref (r, RO_UNARY_STAR, complain);
return r;
}
stmt_expr = finish_stmt_expr (stmt_expr, false);
cur_stmt_expr = old_stmt_expr;
+ /* If the resulting list of expression statement is empty,
+ fold it further into void_zero_node. */
+ if (empty_expr_stmt_p (stmt_expr))
+ stmt_expr = void_zero_node;
+
return stmt_expr;
}
if (ambiguous_p)
{
- const char *str = "candidates are:";
+ const char *str;
+ char *spaces = NULL;
error ("ambiguous class template instantiation for %q#T", type);
+ str = TREE_CHAIN (list) ? _("candidates are:") : _("candidate is:");
for (t = list; t; t = TREE_CHAIN (t))
- {
- error ("%s %+#T", str, TREE_TYPE (t));
- str = " ";
- }
+ {
+ error ("%s %+#T", spaces ? spaces : str, TREE_TYPE (t));
+ spaces = spaces ? spaces : get_spaces (str);
+ }
+ free (spaces);
return error_mark_node;
}
return NULL_TREE;
}
-/* For a given template T, return the list of typedefs referenced
+/* For a given template T, return the vector of typedefs referenced
in T for which access check is needed at T instantiation time.
T is either a FUNCTION_DECL or a RECORD_TYPE.
Those typedefs were added to T by the function
append_type_to_template_for_access_check. */
-tree
+VEC(qualified_typedef_usage_t,gc)*
get_types_needing_access_check (tree t)
{
- tree ti, result = NULL_TREE;
+ tree ti;
+ VEC(qualified_typedef_usage_t,gc) *result = NULL;
if (!t || t == error_mark_node)
- return t;
+ return NULL;
if (!(ti = get_template_info (t)))
- return NULL_TREE;
+ return NULL;
if (CLASS_TYPE_P (t)
|| TREE_CODE (t) == FUNCTION_DECL)
{
if (!TI_TEMPLATE (ti))
- return NULL_TREE;
+ return NULL;
result = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti);
}
T is either a FUNCTION_DECL or a RECORD_TYPE.
TYPE_DECL is a TYPE_DECL node representing a typedef.
SCOPE is the scope through which TYPE_DECL is accessed.
+ LOCATION is the location of the usage point of TYPE_DECL.
This function is a subroutine of
append_type_to_template_for_access_check. */
static void
append_type_to_template_for_access_check_1 (tree t,
tree type_decl,
- tree scope)
+ tree scope,
+ location_t location)
{
+ qualified_typedef_usage_t typedef_usage;
tree ti;
if (!t || t == error_mark_node)
gcc_assert (TI_TEMPLATE (ti));
- TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti) =
- tree_cons (type_decl, scope, TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti));
+ typedef_usage.typedef_decl = type_decl;
+ typedef_usage.context = scope;
+ typedef_usage.locus = location;
+
+ VEC_safe_push (qualified_typedef_usage_t, gc,
+ TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti),
+ &typedef_usage);
}
/* Append TYPE_DECL to the template TEMPL.
TEMPL is either a class type, a FUNCTION_DECL or a a TEMPLATE_DECL.
At TEMPL instanciation time, TYPE_DECL will be checked to see
if it can be accessed through SCOPE.
+ LOCATION is the location of the usage point of TYPE_DECL.
e.g. consider the following code snippet:
template<class U> struct S
{
- C::myint mi;
+ C::myint mi; // <-- usage point of the typedef C::myint
};
S<char> s;
void
append_type_to_template_for_access_check (tree templ,
tree type_decl,
- tree scope)
+ tree scope,
+ location_t location)
{
- tree node;
+ qualified_typedef_usage_t *iter;
+ int i;
gcc_assert (type_decl && (TREE_CODE (type_decl) == TYPE_DECL));
/* Make sure we don't append the type to the template twice. */
- for (node = get_types_needing_access_check (templ);
- node;
- node = TREE_CHAIN (node))
- {
- tree decl = TREE_PURPOSE (node);
- tree type_scope = TREE_VALUE (node);
-
- if (decl == type_decl && type_scope == scope)
- return;
- }
+ for (i = 0;
+ VEC_iterate (qualified_typedef_usage_t,
+ get_types_needing_access_check (templ),
+ i, iter);
+ ++i)
+ if (iter->typedef_decl == type_decl && scope == iter->context)
+ return;
- append_type_to_template_for_access_check_1 (templ, type_decl, scope);
+ append_type_to_template_for_access_check_1 (templ, type_decl,
+ scope, location);
}
/* Set up the hash tables for template instantiations. */