aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/pt.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/pt.c')
-rw-r--r--gcc/cp/pt.c248
1 files changed, 165 insertions, 83 deletions
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 152ac0e3820..b751ad49e74 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -134,6 +134,7 @@ static tree build_template_decl PARAMS ((tree, tree));
static int mark_template_parm PARAMS ((tree, void *));
static tree tsubst_friend_function PARAMS ((tree, tree));
static tree tsubst_friend_class PARAMS ((tree, tree));
+static int can_complete_type_without_circularity PARAMS ((tree));
static tree get_bindings_real PARAMS ((tree, tree, tree, int, int, int));
static int template_decl_level PARAMS ((tree));
static tree maybe_get_template_decl_from_type_decl PARAMS ((tree));
@@ -3302,17 +3303,12 @@ convert_template_argument (parm, arg, args, complain, i, in_decl)
&& TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)
|| TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
|| TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE);
- else if (CLASSTYPE_TEMPLATE_INFO (arg) && !CLASSTYPE_USE_TEMPLATE (arg)
- && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (arg)))
- {
- if (is_base_of_enclosing_class (arg, current_class_type))
- /* This is a template name used within the scope of the
- template. It could be the template, or it could be the
- instantiation. Choose whichever makes sense. */
- is_tmpl_type = requires_tmpl_type;
- else
- is_tmpl_type = 1;
- }
+ else if (CLASSTYPE_IS_TEMPLATE (arg)
+ && is_base_of_enclosing_class (arg, current_class_type))
+ /* This is a template name used within the scope of the
+ template. It could be the template, or it could be the
+ instantiation. Choose whichever makes sense. */
+ is_tmpl_type = requires_tmpl_type;
else
/* It is a non-template class, or a specialization of a template
class, or a non-template member of a template class. */
@@ -3429,6 +3425,16 @@ convert_template_argument (parm, arg, args, complain, i, in_decl)
val, t);
return error_mark_node;
}
+
+ /* In order to avoid all sorts of complications, we do
+ not allow variably-modified types as template
+ arguments. */
+ if (variably_modified_type_p (val))
+ {
+ error ("template-argument `%T' is a variably modified type",
+ val);
+ return error_mark_node;
+ }
}
}
}
@@ -3942,10 +3948,16 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope, complain)
The template parameter level of T and U are one level larger than
of TT. To proper process the default argument of U, say when an
instantiation `TT<int>' is seen, we need to build the full
- arguments containing {int} as the innermost level. Outer levels
- can be obtained from `current_template_args ()'. */
+ arguments containing {int} as the innermost level. Outer levels,
+ available when not appearing as default template argument, can be
+ obtained from `current_template_args ()'.
- if (processing_template_decl)
+ Suppose that TT is later substituted with std::vector. The above
+ instantiation is `TT<int, std::allocator<T> >' with TT at
+ level 1, and T at level 2, while the template arguments at level 1
+ becomes {std::vector} and the inner level 2 is {int}. */
+
+ if (current_template_parms)
arglist = add_to_template_args (current_template_args (), arglist);
arglist2 = coerce_template_parms (parmlist, arglist, template,
@@ -4588,7 +4600,7 @@ tsubst_friend_function (decl, args)
tree template_id, arglist, fns;
tree new_args;
tree tmpl;
- tree ns = CP_DECL_CONTEXT (TYPE_MAIN_DECL (current_class_type));
+ tree ns = decl_namespace_context (TYPE_MAIN_DECL (current_class_type));
/* Friend functions are looked up in the containing namespace scope.
We must enter that scope, to avoid finding member functions of the
@@ -4796,16 +4808,27 @@ tsubst_friend_class (friend_tmpl, args)
{
tree friend_type;
tree tmpl;
+ tree context;
+
+ context = DECL_CONTEXT (friend_tmpl);
+
+ if (context)
+ {
+ if (TREE_CODE (context) == NAMESPACE_DECL)
+ push_nested_namespace (context);
+ else
+ push_nested_class (tsubst (context, args, tf_none, NULL_TREE), 2);
+ }
/* First, we look for a class template. */
tmpl = lookup_name (DECL_NAME (friend_tmpl), /*prefer_type=*/0);
-
+
/* But, if we don't find one, it might be because we're in a
situation like this:
template <class T>
struct S {
- template <class U>
+ template <class U>
friend struct S;
};
@@ -4825,12 +4848,15 @@ tsubst_friend_class (friend_tmpl, args)
of course. We only need the innermost template parameters
because that is all that redeclare_class_template will look
at. */
- tree parms
- = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend_tmpl),
- args, tf_error | tf_warning);
- if (!parms)
- return error_mark_node;
- redeclare_class_template (TREE_TYPE (tmpl), parms);
+ if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (friend_tmpl))
+ > TMPL_ARGS_DEPTH (args))
+ {
+ tree parms;
+ parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend_tmpl),
+ args, tf_error | tf_warning);
+ redeclare_class_template (TREE_TYPE (tmpl), parms);
+ }
+
friend_type = TREE_TYPE (tmpl);
}
else
@@ -4852,9 +4878,36 @@ tsubst_friend_class (friend_tmpl, args)
friend_type = TREE_TYPE (pushdecl_top_level (tmpl));
}
+ if (context)
+ {
+ if (TREE_CODE (context) == NAMESPACE_DECL)
+ pop_nested_namespace (context);
+ else
+ pop_nested_class ();
+ }
+
return friend_type;
}
+/* Returns zero if TYPE cannot be completed later due to circularity.
+ Otherwise returns one. */
+
+static int
+can_complete_type_without_circularity (type)
+ tree type;
+{
+ if (type == NULL_TREE || type == error_mark_node)
+ return 0;
+ else if (COMPLETE_TYPE_P (type))
+ return 1;
+ else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
+ return can_complete_type_without_circularity (TREE_TYPE (type));
+ else if (CLASS_TYPE_P (type) && TYPE_BEING_DEFINED (TYPE_MAIN_VARIANT (type)))
+ return 0;
+ else
+ return 1;
+}
+
tree
instantiate_class_template (type)
tree type;
@@ -5175,7 +5228,20 @@ instantiate_class_template (type)
if (DECL_INITIALIZED_IN_CLASS_P (r))
check_static_variable_definition (r, TREE_TYPE (r));
}
-
+ else if (TREE_CODE (r) == FIELD_DECL)
+ {
+ /* Determine whether R has a valid type and can be
+ completed later. If R is invalid, then it is replaced
+ by error_mark_node so that it will not be added to
+ TYPE_FIELDS. */
+ tree rtype = TREE_TYPE (r);
+ if (!can_complete_type_without_circularity (rtype))
+ {
+ incomplete_type_error (r, rtype);
+ r = error_mark_node;
+ }
+ }
+
/* R will have a TREE_CHAIN if and only if it has already been
processed by finish_member_declaration. This can happen
if, for example, it is a TYPE_DECL for a class-scoped
@@ -5256,6 +5322,8 @@ instantiate_class_template (type)
--processing_template_decl;
}
+ /* Now that TYPE_FIELDS and TYPE_METHODS are set up. We can
+ instantiate templates used by this class. */
for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
if (TREE_CODE (t) == FIELD_DECL)
{
@@ -6016,6 +6084,8 @@ tsubst_decl (t, args, type, complain)
}
r = copy_decl (t);
+ if (TREE_CODE (r) == VAR_DECL)
+ type = complete_type (type);
TREE_TYPE (r) = type;
c_apply_type_quals_to_decl (cp_type_quals (type), r);
DECL_CONTEXT (r) = ctx;
@@ -6029,15 +6099,6 @@ tsubst_decl (t, args, type, complain)
SET_DECL_RTL (r, NULL_RTX);
DECL_SIZE (r) = DECL_SIZE_UNIT (r) = 0;
- /* For __PRETTY_FUNCTION__ we have to adjust the initializer. */
- if (DECL_PRETTY_FUNCTION_P (r))
- {
- const char *const name = (*decl_printable_name)
- (current_function_decl, 2);
- DECL_INITIAL (r) = cp_fname_init (name);
- TREE_TYPE (r) = TREE_TYPE (DECL_INITIAL (r));
- }
-
/* Even if the original location is out of scope, the newly
substituted one is not. */
if (TREE_CODE (r) == VAR_DECL)
@@ -6061,6 +6122,8 @@ tsubst_decl (t, args, type, complain)
TREE_CHAIN (r) = NULL_TREE;
if (TREE_CODE (r) == VAR_DECL && VOID_TYPE_P (type))
cp_error_at ("instantiation of `%D' as type `%T'", r, type);
+ /* Compute the size, alignment, etc. of R. */
+ layout_decl (r, 0);
}
break;
@@ -7080,9 +7143,10 @@ tsubst_copy (t, args, complain, in_decl)
{
tree base = tsubst_copy (TREE_OPERAND (name, 0), args,
complain, in_decl);
- name = TREE_OPERAND (name, 1);
- name = tsubst_copy (TREE_OPERAND (name, 0), args,
- complain, in_decl);
+ name = TREE_OPERAND (TREE_OPERAND (name, 1), 0);
+ if (TREE_CODE (name) == TYPE_DECL)
+ name = TREE_TYPE (name);
+ name = tsubst_copy (name, args, complain, in_decl);
name = build1 (BIT_NOT_EXPR, NULL_TREE, name);
name = build_nt (SCOPE_REF, base, name);
}
@@ -7318,15 +7382,8 @@ tsubst_expr (t, args, complain, in_decl)
{
init = DECL_INITIAL (decl);
decl = tsubst (decl, args, complain, in_decl);
- if (DECL_PRETTY_FUNCTION_P (decl))
- init = DECL_INITIAL (decl);
- else
- init = tsubst_expr (init, args, complain, in_decl);
if (decl != error_mark_node)
{
- if (TREE_CODE (decl) != TYPE_DECL)
- /* Make sure the type is instantiated now. */
- complete_type (TREE_TYPE (decl));
if (init)
DECL_INITIAL (decl) = error_mark_node;
/* By marking the declaration as instantiated, we avoid
@@ -7336,8 +7393,26 @@ tsubst_expr (t, args, complain, in_decl)
do. */
if (TREE_CODE (decl) == VAR_DECL)
DECL_TEMPLATE_INSTANTIATED (decl) = 1;
- maybe_push_decl (decl);
- cp_finish_decl (decl, init, NULL_TREE, 0);
+ if (TREE_CODE (decl) == VAR_DECL
+ && ANON_AGGR_TYPE_P (TREE_TYPE (decl)))
+ /* Anonymous aggregates are a special case. */
+ finish_anon_union (decl);
+ else
+ {
+ maybe_push_decl (decl);
+ if (DECL_PRETTY_FUNCTION_P (decl))
+ {
+ /* For __PRETTY_FUNCTION__ we have to adjust the
+ initializer. */
+ const char *const name
+ = (*decl_printable_name) (current_function_decl, 2);
+ init = cp_fname_init (name);
+ TREE_TYPE (decl) = TREE_TYPE (init);
+ }
+ else
+ init = tsubst_expr (init, args, complain, in_decl);
+ cp_finish_decl (decl, init, NULL_TREE, 0);
+ }
}
}
@@ -7467,6 +7542,11 @@ tsubst_expr (t, args, complain, in_decl)
finish_label_stmt (DECL_NAME (LABEL_STMT_LABEL (t)));
break;
+ case FILE_STMT:
+ input_filename = FILE_STMT_FILENAME (t);
+ add_stmt (build_nt (FILE_STMT, FILE_STMT_FILENAME_NODE (t)));
+ break;
+
case GOTO_STMT:
prep_stmt (t);
tmp = GOTO_DESTINATION (t);
@@ -7482,12 +7562,13 @@ tsubst_expr (t, args, complain, in_decl)
case ASM_STMT:
prep_stmt (t);
- finish_asm_stmt (ASM_CV_QUAL (t),
- tsubst_expr (ASM_STRING (t), args, complain, in_decl),
- tsubst_expr (ASM_OUTPUTS (t), args, complain, in_decl),
- tsubst_expr (ASM_INPUTS (t), args, complain, in_decl),
- tsubst_expr (ASM_CLOBBERS (t), args, complain,
- in_decl));
+ tmp = finish_asm_stmt
+ (ASM_CV_QUAL (t),
+ tsubst_expr (ASM_STRING (t), args, complain, in_decl),
+ tsubst_expr (ASM_OUTPUTS (t), args, complain, in_decl),
+ tsubst_expr (ASM_INPUTS (t), args, complain, in_decl),
+ tsubst_expr (ASM_CLOBBERS (t), args, complain, in_decl));
+ ASM_INPUT_P (tmp) = ASM_INPUT_P (t);
break;
case TRY_BLOCK:
@@ -8477,9 +8558,7 @@ check_cv_quals_for_unify (strict, arg, parm)
{
/* If the cvr quals of parm will not unify with ARG, they'll be
ignored in instantiation, so we have to do the same here. */
- if (TREE_CODE (arg) == REFERENCE_TYPE
- || TREE_CODE (arg) == FUNCTION_TYPE
- || TREE_CODE (arg) == METHOD_TYPE)
+ if (TREE_CODE (arg) == REFERENCE_TYPE)
parm_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
if (!POINTER_TYPE_P (arg) &&
TREE_CODE (arg) != TEMPLATE_TYPE_PARM)
@@ -8704,21 +8783,17 @@ unify (tparms, targs, parm, arg, strict)
return 0;
else if (targ)
return 1;
- }
- /* Make sure that ARG is not a variable-sized array. (Note that
- were talking about variable-sized arrays (like `int[n]'),
- rather than arrays of unknown size (like `int[]').) We'll
- get very confused by such a type since the bound of the array
- will not be computable in an instantiation. Besides, such
- types are not allowed in ISO C++, so we can do as we please
- here. */
- if (TREE_CODE (arg) == ARRAY_TYPE
- && !uses_template_parms (arg)
- && TYPE_DOMAIN (arg)
- && (TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (arg)))
- != INTEGER_CST))
- return 1;
+ /* Make sure that ARG is not a variable-sized array. (Note
+ that were talking about variable-sized arrays (like
+ `int[n]'), rather than arrays of unknown size (like
+ `int[]').) We'll get very confused by such a type since
+ the bound of the array will not be computable in an
+ instantiation. Besides, such types are not allowed in
+ ISO C++, so we can do as we please here. */
+ if (variably_modified_type_p (arg))
+ return 1;
+ }
TREE_VEC_ELT (targs, idx) = arg;
return 0;
@@ -9481,12 +9556,16 @@ do_decl_instantiation (declspecs, declarator, storage)
if (DECL_TEMPLATE_SPECIALIZATION (result))
{
- /* [temp.spec]
+ /* DR 259 [temp.spec].
- No program shall both explicitly instantiate and explicitly
- specialize a template. */
- pedwarn ("explicit instantiation of `%#D' after", result);
- cp_pedwarn_at ("explicit specialization here", result);
+ Both an explicit instantiation and a declaration of an explicit
+ specialization shall not appear in a program unless the explicit
+ instantiation follows a declaration of the explicit specialization.
+
+ For a given set of template parameters, if an explicit
+ instantiation of a template appears after a declaration of an
+ explicit specialization for that template, the explicit
+ instantiation has no effect. */
return;
}
else if (DECL_EXPLICIT_INSTANTIATION (result))
@@ -9616,15 +9695,16 @@ do_type_instantiation (t, storage, complain)
if (CLASSTYPE_TEMPLATE_SPECIALIZATION (t))
{
- /* [temp.spec]
+ /* DR 259 [temp.spec].
- No program shall both explicitly instantiate and explicitly
- specialize a template. */
- if (complain & tf_error)
- {
- error ("explicit instantiation of `%#T' after", t);
- cp_error_at ("explicit specialization here", t);
- }
+ Both an explicit instantiation and a declaration of an explicit
+ specialization shall not appear in a program unless the explicit
+ instantiation follows a declaration of the explicit specialization.
+
+ For a given set of template parameters, if an explicit
+ instantiation of a template appears after a declaration of an
+ explicit specialization for that template, the explicit
+ instantiation has no effect. */
return;
}
else if (CLASSTYPE_EXPLICIT_INSTANTIATION (t))
@@ -10202,8 +10282,10 @@ tsubst_initializer_list (t, argvec)
else
init = convert_from_reference (init);
- *p = build_tree_list (decl, init);
- p = &TREE_CHAIN (*p);
+ *p = expand_member_init (current_class_ref, decl,
+ init ? init : void_type_node);
+ if (*p)
+ p = &TREE_CHAIN (*p);
}
return first;
}