static void perform_typedefs_access_check (tree tmpl, tree targs);
static void append_type_to_template_for_access_check_1 (tree, tree, tree);
static hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
+static bool primary_template_instantiation_p (const_tree);
+static tree listify (tree);
+static tree listify_autos (tree, tree);
/* Make the current scope suitable for access checking when we are
processing T. T can be FUNCTION_DECL for instantiated function
/* Return the template info node corresponding to T, whatever T is. */
tree
-get_template_info (tree t)
+get_template_info (const_tree t)
{
tree tinfo = NULL_TREE;
+ if (!t || t == error_mark_node)
+ return NULL;
+
if (DECL_P (t) && DECL_LANG_SPECIFIC (t))
tinfo = DECL_TEMPLATE_INFO (t);
- if (!tinfo && TREE_CODE (t) == TYPE_DECL)
+ if (!tinfo && DECL_IMPLICIT_TYPEDEF_P (t))
t = TREE_TYPE (t);
if (TAGGED_TYPE_P (t))
{
if (DECL_TEMPLATE_INSTANTIATION (fn))
{
- if (TREE_USED (fn)
+ if (DECL_ODR_USED (fn)
|| DECL_EXPLICIT_INSTANTIATION (fn))
{
error ("specialization of %qD after instantiation",
to the primary function; now copy the inline bits to
the various clones. */
FOR_EACH_CLONE (clone, fn)
- DECL_DECLARED_INLINE_P (clone)
- = DECL_DECLARED_INLINE_P (fn);
+ {
+ DECL_DECLARED_INLINE_P (clone)
+ = DECL_DECLARED_INLINE_P (fn);
+ DECL_SOURCE_LOCATION (clone)
+ = DECL_SOURCE_LOCATION (fn);
+ }
check_specialization_namespace (fn);
return fn;
}
/* Determine whether PARM is a parameter pack. */
+
bool
template_parameter_pack_p (const_tree parm)
{
&& TEMPLATE_TYPE_PARAMETER_PACK (parm));
}
+/* Determine if T is a function parameter pack. */
+
+bool
+function_parameter_pack_p (const_tree t)
+{
+ if (t && TREE_CODE (t) == PARM_DECL)
+ return FUNCTION_PARAMETER_PACK_P (t);
+ return false;
+}
+
+/* Return the function template declaration of PRIMARY_FUNC_TMPL_INST.
+ PRIMARY_FUNC_TMPL_INST is a primary function template instantiation. */
+
+tree
+get_function_template_decl (const_tree primary_func_tmpl_inst)
+{
+ if (! primary_func_tmpl_inst
+ || TREE_CODE (primary_func_tmpl_inst) != FUNCTION_DECL
+ || ! primary_template_instantiation_p (primary_func_tmpl_inst))
+ return NULL;
+
+ return DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (primary_func_tmpl_inst));
+}
+
+/* Return true iff the function parameter PARAM_DECL was expanded
+ from the function parameter pack PACK. */
+
+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));
+
+ /* 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,
i.e., one that is terminated by a template argument pack. */
+
static bool
template_args_variadic_p (tree args)
{
/* Generate a new name for the parameter pack name NAME (an
IDENTIFIER_NODE) that incorporates its */
+
static tree
make_ith_pack_parameter_name (tree name, int i)
{
/* Munge the name to include the parameter index. */
- char numbuf[128];
+#define NUMBUF_LEN 128
+ char numbuf[NUMBUF_LEN];
char* newname;
-
- sprintf(numbuf, "%i", i);
- newname = (char*)alloca (IDENTIFIER_LENGTH (name) + strlen(numbuf) + 2);
- sprintf(newname, "%s#%i", IDENTIFIER_POINTER (name), i);
+ int newname_len;
+
+ snprintf (numbuf, NUMBUF_LEN, "%i", i);
+ newname_len = IDENTIFIER_LENGTH (name)
+ + strlen (numbuf) + 2;
+ newname = (char*)alloca (newname_len);
+ snprintf (newname, newname_len,
+ "%s#%i", IDENTIFIER_POINTER (name), i);
return get_identifier (newname);
}
+/* Return true if T is a primary function
+ or class template instantiation. */
+
+static bool
+primary_template_instantiation_p (const_tree t)
+{
+ if (!t)
+ return false;
+
+ if (TREE_CODE (t) == FUNCTION_DECL)
+ return DECL_LANG_SPECIFIC (t)
+ && DECL_TEMPLATE_INSTANTIATION (t)
+ && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t));
+ else if (CLASS_TYPE_P (t))
+ return CLASSTYPE_TEMPLATE_INSTANTIATION (t)
+ && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t));
+ return false;
+}
+
+/* Return true if PARM is a template template parameter. */
+
+bool
+template_template_parameter_p (const_tree parm)
+{
+ return DECL_TEMPLATE_TEMPLATE_PARM_P (parm);
+}
+
+/* Return the template parameters of T if T is a
+ primary template instantiation, NULL otherwise. */
+
+tree
+get_primary_template_innermost_parameters (const_tree t)
+{
+ tree parms = NULL, template_info = NULL;
+
+ if ((template_info = get_template_info (t))
+ && primary_template_instantiation_p (t))
+ parms = INNERMOST_TEMPLATE_PARMS
+ (DECL_TEMPLATE_PARMS (TI_TEMPLATE (template_info)));
+
+ return parms;
+}
+
+/* Returns the template arguments of T if T is a template instantiation,
+ NULL otherwise. */
+
+tree
+get_template_innermost_arguments (const_tree t)
+{
+ tree args = NULL, template_info = NULL;
+
+ if ((template_info = get_template_info (t))
+ && TI_ARGS (template_info))
+ args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (template_info));
+
+ return args;
+}
+
+/* Return the argument pack elements of T if T is a template argument pack,
+ NULL otherwise. */
+
+tree
+get_template_argument_pack_elems (const_tree t)
+{
+ if (TREE_CODE (t) != TYPE_ARGUMENT_PACK
+ && TREE_CODE (t) != NONTYPE_ARGUMENT_PACK)
+ return NULL;
+
+ return ARGUMENT_PACK_ARGS (t);
+}
+
/* Structure used to track the progress of find_parameter_packs_r. */
struct find_parameter_pack_data
{
pointer_set_destroy (ppd.visited);
/* Create the pack expansion type for the base type. */
- purpose = make_node (TYPE_PACK_EXPANSION);
+ purpose = cxx_make_type (TYPE_PACK_EXPANSION);
SET_PACK_EXPANSION_PATTERN (purpose, TREE_PURPOSE (arg));
PACK_EXPANSION_PARAMETER_PACKS (purpose) = parameter_packs;
for_types = true;
/* Build the PACK_EXPANSION_* node. */
- result = make_node (for_types ? TYPE_PACK_EXPANSION : EXPR_PACK_EXPANSION);
+ result = for_types
+ ? cxx_make_type (TYPE_PACK_EXPANSION)
+ : make_node (EXPR_PACK_EXPANSION);
SET_PACK_EXPANSION_PATTERN (result, arg);
if (TREE_CODE (result) == EXPR_PACK_EXPANSION)
{
tree vec = make_tree_vec (1);
TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
- t = make_node (TYPE_ARGUMENT_PACK);
+ t = cxx_make_type (TYPE_ARGUMENT_PACK);
SET_ARGUMENT_PACK_ARGS (t, vec);
}
}
if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL
|| TREE_CODE (TREE_VALUE (parm)) == TEMPLATE_DECL)
- argument_pack = make_node (TYPE_ARGUMENT_PACK);
+ argument_pack = cxx_make_type (TYPE_ARGUMENT_PACK);
else
{
argument_pack = make_node (NONTYPE_ARGUMENT_PACK);
if (!is_partial_instantiation
&& !PRIMARY_TEMPLATE_P (gen_tmpl)
+ && !LAMBDA_TYPE_P (TREE_TYPE (gen_tmpl))
&& TREE_CODE (CP_DECL_CONTEXT (gen_tmpl)) == NAMESPACE_DECL)
{
found = xref_tag_from_type (TREE_TYPE (gen_tmpl),
the values for the enumeration constants may involve
template parameters. And, no one should be interested
in the enumeration constants for such a type. */
- t = make_node (ENUMERAL_TYPE);
+ t = cxx_make_type (ENUMERAL_TYPE);
SET_SCOPED_ENUM_P (t, SCOPED_ENUM_P (template_type));
}
}
tree parmvec;
tree parmtypevec;
tree argpack = make_node (NONTYPE_ARGUMENT_PACK);
- tree argtypepack = make_node (TYPE_ARGUMENT_PACK);
+ tree argtypepack = cxx_make_type (TYPE_ARGUMENT_PACK);
int i, len = list_length (spec_parm);
/* Fill in PARMVEC and PARMTYPEVEC with all of the parameters. */
return result;
}
+/* Given PARM_DECL PARM, find the corresponding PARM_DECL in the template
+ TMPL. We do this using DECL_PARM_INDEX, which should work even with
+ parameter packs; all parms generated from a function parameter pack will
+ have the same DECL_PARM_INDEX. */
+
+tree
+get_pattern_parm (tree parm, tree tmpl)
+{
+ tree pattern = DECL_TEMPLATE_RESULT (tmpl);
+ tree patparm;
+
+ if (DECL_ARTIFICIAL (parm))
+ {
+ for (patparm = DECL_ARGUMENTS (pattern);
+ patparm; patparm = TREE_CHAIN (patparm))
+ if (DECL_ARTIFICIAL (patparm)
+ && DECL_NAME (parm) == DECL_NAME (patparm))
+ break;
+ }
+ else
+ {
+ patparm = FUNCTION_FIRST_USER_PARM (DECL_TEMPLATE_RESULT (tmpl));
+ patparm = chain_index (DECL_PARM_INDEX (parm)-1, patparm);
+ gcc_assert (DECL_PARM_INDEX (patparm)
+ == DECL_PARM_INDEX (parm));
+ }
+
+ return patparm;
+}
+
/* Substitute ARGS into the vector or list of template arguments T. */
static tree
else if (ARGUMENT_PACK_P (orig_arg))
{
/* Substitute into each of the arguments. */
- new_arg = make_node (TREE_CODE (orig_arg));
+ new_arg = TYPE_P (orig_arg)
+ ? cxx_make_type (TREE_CODE (orig_arg))
+ : make_node (TREE_CODE (orig_arg));
SET_ARGUMENT_PACK_ARGS (
new_arg,
cp_function_chain->x_current_class_ref = saved_class_ref;
}
- pop_access_scope (fn);
-
/* Make sure the default argument is reasonable. */
arg = check_default_argument (type, arg);
+ pop_access_scope (fn);
+
return arg;
}
if (DECL_TEMPLATE_PARM_P (t))
SET_DECL_TEMPLATE_PARM_P (r);
+ /* An argument of a function parameter pack is not a parameter
+ pack. */
+ FUNCTION_PARAMETER_PACK_P (r) = false;
+
if (expanded_types)
/* We're on the Ith parameter of the function parameter
pack. */
DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE);
SET_DECL_IMPLICIT_INSTANTIATION (r);
}
+ else if (cp_unevaluated_operand)
+ {
+ /* We're substituting this var in a decltype outside of its
+ scope, such as for a lambda return type. Don't add it to
+ local_specializations, do perform auto deduction. */
+ tree auto_node = type_uses_auto (type);
+ tree init
+ = tsubst_expr (DECL_INITIAL (t), args, complain, in_decl,
+ /*constant_expression_p=*/false);
+
+ if (auto_node && init && describable_type (init))
+ {
+ type = do_auto_deduction (type, init, auto_node);
+ TREE_TYPE (r) = type;
+ }
+ }
else
register_local_specialization (r, t);
--cp_unevaluated_operand;
--c_inhibit_evaluation_warnings;
- type =
- finish_decltype_type (type,
- DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t));
+ if (DECLTYPE_FOR_LAMBDA_CAPTURE (t))
+ type = lambda_capture_field_type (type);
+ else if (DECLTYPE_FOR_LAMBDA_RETURN (t))
+ type = lambda_return_type (type);
+ else
+ type = finish_decltype_type
+ (type, DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t));
return cp_build_qualified_type_real (type,
cp_type_quals (t)
| cp_type_quals (type),
case TYPE_ARGUMENT_PACK:
case NONTYPE_ARGUMENT_PACK:
{
- tree r = make_node (TREE_CODE (t));
+ tree r = TYPE_P (t)
+ ? cxx_make_type (TREE_CODE (t))
+ : make_node (TREE_CODE (t));
tree packed_out =
tsubst_template_args (ARGUMENT_PACK_ARGS (t),
args,
if (purpose)
purpose = RECUR (purpose);
value = TREE_VALUE (t);
- if (value)
+ if (value && TREE_CODE (value) != LABEL_DECL)
value = RECUR (value);
chain = TREE_CHAIN (t);
if (chain && chain != void_type_node)
RECUR (ASM_STRING (t)),
tsubst_copy_asm_operands (ASM_OUTPUTS (t), args, complain, in_decl),
tsubst_copy_asm_operands (ASM_INPUTS (t), args, complain, in_decl),
- tsubst_copy_asm_operands (ASM_CLOBBERS (t), args, complain, in_decl));
+ tsubst_copy_asm_operands (ASM_CLOBBERS (t), args, complain, in_decl),
+ tsubst_copy_asm_operands (ASM_LABELS (t), args, complain, in_decl));
{
tree asm_expr = tmp;
if (TREE_CODE (asm_expr) == CLEANUP_POINT_EXPR)
}
return t;
+ case LAMBDA_EXPR:
+ {
+ tree r = build_lambda_expr ();
+
+ tree type = tsubst (TREE_TYPE (t), args, complain, NULL_TREE);
+ TREE_TYPE (r) = type;
+ CLASSTYPE_LAMBDA_EXPR (type) = r;
+
+ LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)
+ = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);
+ LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);
+ LAMBDA_EXPR_DISCRIMINATOR (r)
+ = (LAMBDA_EXPR_DISCRIMINATOR (t));
+ LAMBDA_EXPR_CAPTURE_LIST (r)
+ = RECUR (LAMBDA_EXPR_CAPTURE_LIST (t));
+ LAMBDA_EXPR_THIS_CAPTURE (r)
+ = RECUR (LAMBDA_EXPR_THIS_CAPTURE (t));
+ LAMBDA_EXPR_EXTRA_SCOPE (r)
+ = RECUR (LAMBDA_EXPR_EXTRA_SCOPE (t));
+
+ /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */
+ determine_visibility (TYPE_NAME (type));
+ /* Now that we know visibility, instantiate the type so we have a
+ declaration of the op() for later calls to lambda_function. */
+ complete_type (type);
+
+ type = tsubst (LAMBDA_EXPR_RETURN_TYPE (t), args, complain, in_decl);
+ if (type)
+ apply_lambda_return_type (r, type);
+
+ return build_lambda_object (r);
+ }
+
default:
/* Handle Objective-C++ constructs, if appropriate. */
{
}
/* Verify that the instantiated ARGS are valid. For type arguments,
- make sure that the type's linkage is ok. For non-type arguments,
+ make sure that the type is not variably modified. For non-type arguments,
make sure they are constants if they are integral or enumerations.
Emit an error under control of COMPLAIN, and return TRUE on error. */
}
else if (TYPE_P (t))
{
- /* [basic.link]: A name with no linkage (notably, the name
- of a class or enumeration declared in a local scope)
- shall not be used to declare an entity with linkage.
- This implies that names with no linkage cannot be used as
- template arguments. */
- tree nt = no_linkage_check (t, /*relaxed_p=*/false);
-
- if (nt)
- {
- /* DR 488 makes use of a type with no linkage cause
- type deduction to fail. */
- if (complain & tf_error)
- {
- if (TYPE_ANONYMOUS_P (nt))
- error ("%qT is/uses anonymous type", t);
- else
- error ("template argument for %qD uses local type %qT",
- tmpl, t);
- }
- return true;
- }
- /* In order to avoid all sorts of complications, we do not
- allow variably-modified types as template arguments. */
- else if (variably_modified_type_p (t, NULL_TREE))
+ if (variably_modified_type_p (t, NULL_TREE))
{
if (complain & tf_error)
error ("%qT is a variably modified type", t);
TREE_CONSTANT (arg) = 1;
}
else
- arg = make_node (TYPE_ARGUMENT_PACK);
+ arg = cxx_make_type (TYPE_ARGUMENT_PACK);
SET_ARGUMENT_PACK_ARGS (arg, make_tree_vec (0));
TREE_CONSTANT (result) = 1;
}
else
- result = make_node (TYPE_ARGUMENT_PACK);
+ result = cxx_make_type (TYPE_ARGUMENT_PACK);
SET_ARGUMENT_PACK_ARGS (result, new_args);
{
tree elt, elttype;
unsigned i;
+ tree orig_parm = parm;
+
+ /* Replace T with std::initializer_list<T> for deduction. */
+ if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
+ && flag_deduce_init_list)
+ parm = listify (parm);
if (!is_std_init_list (parm))
/* We can only deduce from an initializer list argument if the
if (unify (tparms, targs, elttype, elt, elt_strict))
return 1;
}
+
+ /* If the std::initializer_list<T> deduction worked, replace the
+ deduced A with std::initializer_list<A>. */
+ if (orig_parm != parm)
+ {
+ idx = TEMPLATE_TYPE_IDX (orig_parm);
+ targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
+ targ = listify (targ);
+ TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = targ;
+ }
return 0;
}
return tmpl;
}
+/* Returns true if we need to instantiate this template instance even if we
+ know we aren't going to emit it.. */
+
+bool
+always_instantiate_p (tree decl)
+{
+ /* We always instantiate inline functions so that we can inline them. An
+ explicit instantiation declaration prohibits implicit instantiation of
+ non-inline functions. With high levels of optimization, we would
+ normally inline non-inline functions -- but we're not allowed to do
+ that for "extern template" functions. Therefore, we check
+ DECL_DECLARED_INLINE_P, rather than possibly_inlined_p. */
+ return ((TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_DECLARED_INLINE_P (decl))
+ /* And we need to instantiate static data members so that
+ their initializers are available in integral constant
+ expressions. */
+ || (TREE_CODE (decl) == VAR_DECL
+ && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)));
+}
+
/* Produce the definition of D, a _DECL generated from a template. If
DEFER_OK is nonzero, then we don't have to actually do the
instantiation now; we just have to do it sometime. Normally it is
the instantiation. */
return d;
+ /* Check to see whether we know that this template will be
+ instantiated in some other file, as with "extern template"
+ extension. */
+ external_p = (DECL_INTERFACE_KNOWN (d) && DECL_REALLY_EXTERN (d));
+
+ /* In general, we do not instantiate such templates. */
+ if (external_p && !always_instantiate_p (d))
+ return d;
+
gen_tmpl = most_general_template (tmpl);
gen_args = DECL_TI_ARGS (d);
SET_DECL_IMPLICIT_INSTANTIATION (d);
}
- if (!defer_ok)
+ /* Recheck the substitutions to obtain any warning messages
+ about ignoring cv qualifiers. Don't do this for artificial decls,
+ as it breaks the context-sensitive substitution for lambda op(). */
+ if (!defer_ok && !DECL_ARTIFICIAL (d))
{
- /* Recheck the substitutions to obtain any warning messages
- about ignoring cv qualifiers. */
tree gen = DECL_TEMPLATE_RESULT (gen_tmpl);
tree type = TREE_TYPE (gen);
pop_access_scope (d);
}
- /* Check to see whether we know that this template will be
- instantiated in some other file, as with "extern template"
- extension. */
- external_p = (DECL_INTERFACE_KNOWN (d) && DECL_REALLY_EXTERN (d));
- /* In general, we do not instantiate such templates... */
- if (external_p
- /* ... but we instantiate inline functions so that we can inline
- them. An explicit instantiation declaration prohibits implicit
- instantiation of non-inline functions. With high levels of
- optimization, we would normally inline non-inline functions
- -- but we're not allowed to do that for "extern template" functions.
- Therefore, we check DECL_DECLARED_INLINE_P, rather than
- possibly_inlined_p. And ... */
- && ! (TREE_CODE (d) == FUNCTION_DECL
- && DECL_DECLARED_INLINE_P (d))
- /* ... we instantiate static data members whose values are
- needed in integral constant expressions. */
- && ! (TREE_CODE (d) == VAR_DECL
- && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (d)))
- goto out;
/* Defer all other templates, unless we have been explicitly
forbidden from doing so. */
if (/* If there is no definition, we cannot instantiate the
return au;
}
-/* Replace auto in TYPE with std::initializer_list<auto>. */
+/* Given type ARG, return std::initializer_list<ARG>. */
static tree
-listify_autos (tree type, tree auto_node)
+listify (tree arg)
{
tree std_init_list = namespace_binding
(get_identifier ("initializer_list"), std_node);
tree argvec;
- tree init_auto;
if (!std_init_list || !DECL_CLASS_TEMPLATE_P (std_init_list))
{
- error ("deducing auto from brace-enclosed initializer list requires "
+ error ("deducing from brace-enclosed initializer list requires "
"#include <initializer_list>");
return error_mark_node;
}
argvec = make_tree_vec (1);
- TREE_VEC_ELT (argvec, 0) = auto_node;
- init_auto = lookup_template_class (std_init_list, argvec, NULL_TREE,
- NULL_TREE, 0, tf_warning_or_error);
+ TREE_VEC_ELT (argvec, 0) = arg;
+ return lookup_template_class (std_init_list, argvec, NULL_TREE,
+ NULL_TREE, 0, tf_warning_or_error);
+}
+
+/* Replace auto in TYPE with std::initializer_list<auto>. */
+static tree
+listify_autos (tree type, tree auto_node)
+{
+ tree init_auto = listify (auto_node);
+ tree argvec = make_tree_vec (1);
TREE_VEC_ELT (argvec, 0) = init_auto;
if (processing_template_decl)
argvec = add_to_template_args (current_template_args (), argvec);