aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mmitchell@usa.net>1998-01-19 22:41:40 +0000
committerJason Merrill <jason@gcc.gnu.org>1998-01-19 17:41:40 -0500
commit756506468674bd03d9a3b8fa25f8b33bd49878b3 (patch)
treedc2cfa2b2cd56480d694d16d1dfc486ff448d071
parent685885b773c21a431e87d59de0620b0098fc6dc2 (diff)
downloadgcc-756506468674bd03d9a3b8fa25f8b33bd49878b3.zip
gcc-756506468674bd03d9a3b8fa25f8b33bd49878b3.tar.gz
gcc-756506468674bd03d9a3b8fa25f8b33bd49878b3.tar.bz2
decl.c (start_decl): Don't allow duplicate definitions of static data members.
* decl.c (start_decl): Don't allow duplicate definitions of static data members. * call.c (build_user_type_conversion_1): Handle user-defined template conversion operators correctly. * decl2.c (build_expr_from_tree): Issue an error message if the object in a COMPONENT_REF is a TEMPLATE_DECL. * typeck.c (incomplete_type_error): Handle TEMPLATE_TYPE_PARMs. * class.c (is_local_class): New function. * cp-tree.h (is_local_class): Declare it. (last_tree): Likewise. (begin_tree): Likewise. (end_tree): Likewise. (lookup_template_class): Change prototype. * decl.c (cp_finish_decl): Check for NULL where necesary. Consider FUNCTION_DECLS to declare objects with top-level binding, when calling make_decl_rtl. (grokdeclarator): Give members of local classes internal linkage. (start_function): Remove declaration of last_tree. (finish_function): Set flag_keep_inline_functions around call to rest_of_compilation if we are processing a member function in a local class. (start_method): Call push_template_decl for member functions of local classes in template functions. * decl2.c (import_export_decl): Don't give external linkage to instantiations of templates with internal linkage. * parse.y (last_tree): Remove declaration. (template_type): Pass extra parameter to lookup_template_class. (self_template_type): Likewise. (structsp): Move call to reset_specialization into left_curly. (left_curly): Call reset_specialization, and begin_tree. * pt.c (saved_trees): New variable. (mangle_class_name_for_template): Change prototype. Use additional function context to name local classes in templates correctly. (classtype_mangled_name): Pass the context. (push_template_decl): Handle local classes and templates, and member functions for such classes. (convert_nontype_parameter): Fix handling of pointer-to-member constants. (lookup_template_class): Handle local classes in templates. (tsubst): Likewise. Don't assume that template instantiations have external linkage; pay attention to the template declaration. (mark_decl_instantiated): Likewise. (begin_tree): New function. (end_tree): Likewise. * decl.c (xref_basetypes): Don't call complete_type for basetypes that involve template parameters; that can lead to infinite recursion unnecessarily. * pt.c (register_specialization): Do not register specializations that aren't ready to be registered yet. (check_explicit_specialization): Handle explicit specialization of constructors and destructors. (build_template_decl): New function. (push_template_delc): Handle out-of-class specializations of member templates. * pt.c (check_explicit_specialization): Set up the template information before registering the specialization. (coerce_template_parms): Fix thinko. (tsubst): Handle specializations of member templates correctly. * class.c (finish_struct_methods): Remove calls to check_explicit_specialization from here. (finish_struct): And insert them here. * cp-tree.h (perform_qualification_conversions): New function. (perform_array_to_pointer_conversion): Likewise. (begin_explicit_instantiation): Likewise. (end_explicit_instantiation): Likewise. (determine_specialization): Renamed from determine_explicit_specialization. (comp_template_parms): New function. (processing_explicit_instantiation): New variable. * cvt.c (perform_qualification_conversions): New function. (perform_array_to_pointer_conversion): Likewise. * decl.c (duplicate_decls): Don't consider template functions alike unless they have the same parameters. Refine handling of instantiation/specialization mismatches. (start_decl): Don't call pushdecl for template specializations, since they don't affect overloading. (start_function): Likewise (grokfndecl): Call check_explicit_specialization a little later. Don't call duplicate_decls for memberm template specializations. (grokdeclarator): Don't update template_count for classes that are themselves specializations. Remove use of `2' as parameter to grokfndecl since that value isn't used. * lex.c (cons_up_default_function): Save and restore processing_explicit_instantiation around calls to grokfield. * parse.y (finish_member_template_decl): New function. (component_decl_1): Use it. (fn.def2): Likewise. (template_arg_list_opt): New nonterminal. (template_type): Use it. (self_template_type): Likewise. (template_id): Likewise. (object_template_id): Likewise. (notype_template_declarator): Likwise. (begin_explicit_instantiation): Likewise. (end_explicit_instantiation): Likewise. (explicit_instantiation): Use them. * pt.c (coerce_template_parms): Add parameters. (processing_explicit_instantiation): New variable. (convert_nontype_parameter): New function. (determine_overloaded_function): Likewise. (begin_explicit_instantiation): Likewise. (end_explicit_instantiation): Likewise. (retrieve_specialization): Likewise. (register_specialization): Likewise. (processing_explicit_specialization): Removed. (determine_specialization): Handle specializations of member functions of template class instantiations. (check_explicit_specialization): Refine to conform to standard. (comp_template_parms): New function. (coerce_template_parms): Call convert_nontype_parameter. (tsubst): Refine handling of member templates. Use register_specialization. (instantiate_template): Use retrieve_specialization. (do_decl_instantiation): Likewise. (instantiate_decl): Likewise. (type_unification): Improve handling of explict template arguments. * tree.c (mapcar): Return error_mark_node, rather than aborting, on VAR_DECLS, FUNCTION_DECLS, and CONST_DECLS. * typeck.c (build_unary_op): Call determine_specialization, rather than determine_explicit_specialization. From-SVN: r17426
-rw-r--r--gcc/cp/ChangeLog133
-rw-r--r--gcc/cp/call.c7
-rw-r--r--gcc/cp/class.c136
-rw-r--r--gcc/cp/cp-tree.h16
-rw-r--r--gcc/cp/cvt.c131
-rw-r--r--gcc/cp/decl.c217
-rw-r--r--gcc/cp/decl2.c23
-rw-r--r--gcc/cp/error.c116
-rw-r--r--gcc/cp/lex.c6
-rw-r--r--gcc/cp/parse.y194
-rw-r--r--gcc/cp/pt.c1479
-rw-r--r--gcc/cp/tree.c6
-rw-r--r--gcc/cp/typeck.c8
-rw-r--r--gcc/cp/typeck2.c4
14 files changed, 1884 insertions, 592 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e6e78f6..aa4b3cb 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,136 @@
+Mon Jan 19 22:40:03 1998 Mark Mitchell <mmitchell@usa.net>
+
+ * decl.c (start_decl): Don't allow duplicate definitions of static
+ data members.
+
+ * call.c (build_user_type_conversion_1): Handle user-defined
+ template conversion operators correctly.
+
+ * decl2.c (build_expr_from_tree): Issue an error message if the
+ object in a COMPONENT_REF is a TEMPLATE_DECL.
+
+ * typeck.c (incomplete_type_error): Handle TEMPLATE_TYPE_PARMs.
+
+ * class.c (is_local_class): New function.
+ * cp-tree.h (is_local_class): Declare it.
+ (last_tree): Likewise.
+ (begin_tree): Likewise.
+ (end_tree): Likewise.
+ (lookup_template_class): Change prototype.
+ * decl.c (cp_finish_decl): Check for NULL where necesary.
+ Consider FUNCTION_DECLS to declare objects with top-level binding,
+ when calling make_decl_rtl.
+ (grokdeclarator): Give members of local classes internal linkage.
+ (start_function): Remove declaration of last_tree.
+ (finish_function): Set flag_keep_inline_functions around call to
+ rest_of_compilation if we are processing a member function in a
+ local class.
+ (start_method): Call push_template_decl for member functions of
+ local classes in template functions.
+ * decl2.c (import_export_decl): Don't give external linkage to
+ instantiations of templates with internal linkage.
+ * parse.y (last_tree): Remove declaration.
+ (template_type): Pass extra parameter to lookup_template_class.
+ (self_template_type): Likewise.
+ (structsp): Move call to reset_specialization into left_curly.
+ (left_curly): Call reset_specialization, and begin_tree.
+ * pt.c (saved_trees): New variable.
+ (mangle_class_name_for_template): Change prototype. Use
+ additional function context to name local classes in templates
+ correctly.
+ (classtype_mangled_name): Pass the context.
+ (push_template_decl): Handle local classes and templates, and
+ member functions for such classes.
+ (convert_nontype_parameter): Fix handling of pointer-to-member
+ constants.
+ (lookup_template_class): Handle local classes in templates.
+ (tsubst): Likewise. Don't assume that template instantiations
+ have external linkage; pay attention to the template declaration.
+ (mark_decl_instantiated): Likewise.
+ (begin_tree): New function.
+ (end_tree): Likewise.
+
+ * decl.c (xref_basetypes): Don't call complete_type for basetypes
+ that involve template parameters; that can lead to infinite
+ recursion unnecessarily.
+
+ * pt.c (register_specialization): Do not register specializations
+ that aren't ready to be registered yet.
+ (check_explicit_specialization): Handle explicit specialization of
+ constructors and destructors.
+ (build_template_decl): New function.
+ (push_template_delc): Handle out-of-class specializations of
+ member templates.
+
+ * pt.c (check_explicit_specialization): Set up the template
+ information before registering the specialization.
+ (coerce_template_parms): Fix thinko.
+ (tsubst): Handle specializations of member templates correctly.
+
+ * class.c (finish_struct_methods): Remove calls to
+ check_explicit_specialization from here.
+ (finish_struct): And insert them here.
+ * cp-tree.h (perform_qualification_conversions): New function.
+ (perform_array_to_pointer_conversion): Likewise.
+ (begin_explicit_instantiation): Likewise.
+ (end_explicit_instantiation): Likewise.
+ (determine_specialization): Renamed from
+ determine_explicit_specialization.
+ (comp_template_parms): New function.
+ (processing_explicit_instantiation): New variable.
+ * cvt.c (perform_qualification_conversions): New function.
+ (perform_array_to_pointer_conversion): Likewise.
+ * decl.c (duplicate_decls): Don't consider template functions
+ alike unless they have the same parameters. Refine handling of
+ instantiation/specialization mismatches.
+ (start_decl): Don't call pushdecl for template specializations,
+ since they don't affect overloading.
+ (start_function): Likewise
+ (grokfndecl): Call check_explicit_specialization a little later.
+ Don't call duplicate_decls for memberm template specializations.
+ (grokdeclarator): Don't update template_count for classes that are
+ themselves specializations. Remove use of `2' as parameter to
+ grokfndecl since that value isn't used.
+ * lex.c (cons_up_default_function): Save and restore
+ processing_explicit_instantiation around calls to grokfield.
+ * parse.y (finish_member_template_decl): New function.
+ (component_decl_1): Use it.
+ (fn.def2): Likewise.
+ (template_arg_list_opt): New nonterminal.
+ (template_type): Use it.
+ (self_template_type): Likewise.
+ (template_id): Likewise.
+ (object_template_id): Likewise.
+ (notype_template_declarator): Likwise.
+ (begin_explicit_instantiation): Likewise.
+ (end_explicit_instantiation): Likewise.
+ (explicit_instantiation): Use them.
+ * pt.c (coerce_template_parms): Add parameters.
+ (processing_explicit_instantiation): New variable.
+ (convert_nontype_parameter): New function.
+ (determine_overloaded_function): Likewise.
+ (begin_explicit_instantiation): Likewise.
+ (end_explicit_instantiation): Likewise.
+ (retrieve_specialization): Likewise.
+ (register_specialization): Likewise.
+ (processing_explicit_specialization): Removed.
+ (determine_specialization): Handle specializations of member
+ functions of template class instantiations.
+ (check_explicit_specialization): Refine to conform to standard.
+ (comp_template_parms): New function.
+ (coerce_template_parms): Call convert_nontype_parameter.
+ (tsubst): Refine handling of member templates. Use
+ register_specialization.
+ (instantiate_template): Use retrieve_specialization.
+ (do_decl_instantiation): Likewise.
+ (instantiate_decl): Likewise.
+ (type_unification): Improve handling of explict template
+ arguments.
+ * tree.c (mapcar): Return error_mark_node, rather than aborting,
+ on VAR_DECLS, FUNCTION_DECLS, and CONST_DECLS.
+ * typeck.c (build_unary_op): Call determine_specialization, rather
+ than determine_explicit_specialization.
+
Mon Jan 19 13:18:51 1998 Jason Merrill <jason@yorick.cygnus.com>
* cvt.c (build_up_reference): A TARGET_EXPR has side effects.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 848a821..ca0e5b4 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4356,8 +4356,11 @@ build_user_type_conversion_1 (totype, expr, flags)
if (TREE_CODE (totype) == REFERENCE_TYPE)
convflags |= LOOKUP_NO_TEMP_BIND;
- ics = implicit_conversion
- (totype, TREE_TYPE (TREE_TYPE (fn)), 0, convflags);
+ if (TREE_CODE (fn) != TEMPLATE_DECL)
+ ics = implicit_conversion
+ (totype, TREE_TYPE (TREE_TYPE (fn)), 0, convflags);
+ else
+ ics = implicit_conversion (totype, totype, 0, convflags);
if (TREE_CODE (totype) == REFERENCE_TYPE && ics && ICS_BAD_FLAG (ics))
/* ignore the near match. */;
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 87a0eeb..7dd43f0 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -2107,53 +2107,6 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
obstack_free (current_obstack, baselink_vec);
}
- /* Now, figure out what any member template specializations were
- specializing. */
- for (i = 0; i < TREE_VEC_LENGTH (method_vec); ++i)
- {
- tree fn;
- for (fn = TREE_VEC_ELT (method_vec, i);
- fn != NULL_TREE;
- fn = DECL_CHAIN (fn))
- if (DECL_TEMPLATE_SPECIALIZATION (fn))
- {
- tree f;
- tree spec_args;
-
- /* If there is a template, and t uses template parms, we
- are dealing with a specialization of a member
- template in a template class, and we must grab the
- template, rather than the function. */
- if (DECL_TI_TEMPLATE (fn) && uses_template_parms (t))
- f = DECL_TI_TEMPLATE (fn);
- else
- f = fn;
-
- /* We want the specialization arguments, which will be the
- innermost ones. */
- if (DECL_TI_ARGS (f)
- && TREE_CODE (DECL_TI_ARGS (f)) == TREE_VEC)
- spec_args
- = TREE_VEC_ELT (DECL_TI_ARGS (f), 0);
- else
- spec_args = DECL_TI_ARGS (f);
-
- check_explicit_specialization
- (lookup_template_function (DECL_NAME (f), spec_args),
- f, 0, 1);
-
- /* Now, the assembler name will be correct for fn, so we
- make its RTL. */
- DECL_RTL (f) = 0;
- make_decl_rtl (f, NULL_PTR, 1);
- if (f != fn)
- {
- DECL_RTL (fn) = 0;
- make_decl_rtl (fn, NULL_PTR, 1);
- }
- }
- }
-
return method_vec;
}
@@ -4350,10 +4303,13 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
{
tree fields = NULL_TREE;
tree *tail = &TYPE_METHODS (t);
+ tree specializations = NULL_TREE;
+ tree *specialization_tail = &specializations;
tree name = TYPE_NAME (t);
tree x, last_x = NULL_TREE;
tree access;
tree dummy = NULL_TREE;
+ tree next_x = NULL_TREE;
if (TREE_CODE (name) == TYPE_DECL)
{
@@ -4402,8 +4358,10 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
access = access_private_node;
}
- for (x = TREE_VALUE (list_of_fieldlists); x; x = TREE_CHAIN (x))
+ for (x = TREE_VALUE (list_of_fieldlists); x; x = next_x)
{
+ next_x = TREE_CHAIN (x);
+
TREE_PRIVATE (x) = access == access_private_node;
TREE_PROTECTED (x) = access == access_protected_node;
@@ -4441,8 +4399,23 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
|| DECL_FUNCTION_TEMPLATE_P (x))
{
DECL_CLASS_CONTEXT (x) = t;
+
if (last_x)
- TREE_CHAIN (last_x) = TREE_CHAIN (x);
+ TREE_CHAIN (last_x) = next_x;
+
+ if (DECL_TEMPLATE_SPECIALIZATION (x))
+ /* We don't enter the specialization into the class
+ method vector since specializations don't affect
+ overloading. Instead we keep track of the
+ specializations, and process them after the method
+ vector is complete. */
+ {
+ *specialization_tail = x;
+ specialization_tail = &TREE_CHAIN (x);
+ TREE_CHAIN (x) = NULL_TREE;
+ continue;
+ }
+
/* Link x onto end of TYPE_METHODS. */
*tail = x;
tail = &TREE_CHAIN (x);
@@ -4525,6 +4498,53 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
TYPE_BEING_DEFINED (t) = 0;
+ /* Now, figure out what any member template specializations were
+ specializing. */
+ for (x = specializations; x != NULL_TREE; x = TREE_CHAIN (x))
+ {
+ tree spec_args;
+ tree fn;
+
+ if (uses_template_parms (t))
+ /* If t is a template class, and x is a specialization, then x
+ is itself really a template. Due to the vagaries of the
+ parser, however, we will have a handle to a function
+ declaration, rather than the template declaration, at this
+ point. */
+ {
+ my_friendly_assert (DECL_TEMPLATE_INFO (x) != NULL_TREE, 0);
+ my_friendly_assert (DECL_TI_TEMPLATE (x) != NULL_TREE, 0);
+ fn = DECL_TI_TEMPLATE (x);
+ }
+ else
+ fn = x;
+
+ /* We want the specialization arguments, which will be the
+ innermost ones. */
+ if (DECL_TI_ARGS (fn) && TREE_CODE (DECL_TI_ARGS (fn)) == TREE_VEC)
+ spec_args
+ = TREE_VEC_ELT (DECL_TI_ARGS (fn), 0);
+ else
+ spec_args = DECL_TI_ARGS (fn);
+
+ check_explicit_specialization
+ (lookup_template_function (DECL_NAME (fn), spec_args),
+ fn, 0, 1 | (8 * (int) TREE_CHAIN (DECL_TEMPLATE_INFO (fn))));
+
+ TREE_CHAIN (DECL_TEMPLATE_INFO (fn)) = NULL_TREE;
+
+ /* Now, the assembler name will be correct for fn, so we
+ make its RTL. */
+ DECL_RTL (fn) = 0;
+ make_decl_rtl (fn, NULL_PTR, 1);
+
+ if (x != fn)
+ {
+ DECL_RTL (x) = 0;
+ make_decl_rtl (x, NULL_PTR, 1);
+ }
+ }
+
if (current_class_type)
popclass (0);
else
@@ -5484,3 +5504,21 @@ build_self_reference ()
pushdecl_class_level (value);
return value;
}
+
+
+/* Returns non-zero iff the TYPE is a local class; i.e., if it is
+ declared in a function context, or within a local class. */
+
+int
+is_local_class (type)
+ tree type;
+{
+ if (type == NULL_TREE || TYPE_CONTEXT (type) == NULL_TREE)
+ return 0;
+
+ if (TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL)
+ return 1;
+
+ return is_local_class (TYPE_CONTEXT (type));
+}
+
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e7856f0..73b185d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1539,6 +1539,7 @@ extern tree null_node;
extern tree current_template_parms;
extern HOST_WIDE_INT processing_template_decl;
+extern tree last_tree;
/* The template currently being instantiated, and where the instantiation
was triggered. */
@@ -1983,6 +1984,7 @@ extern void maybe_push_cache_obstack PROTO((void));
extern unsigned HOST_WIDE_INT skip_rtti_stuff PROTO((tree *));
extern tree build_self_reference PROTO((void));
extern void warn_hidden PROTO((tree));
+extern int is_local_class PROTO((tree));
/* in cvt.c */
extern tree convert_to_reference PROTO((tree, tree, int, int, tree));
@@ -1998,6 +2000,8 @@ extern tree build_type_conversion PROTO((enum tree_code, tree, tree, int));
extern tree build_expr_type_conversion PROTO((int, tree, int));
extern int build_default_binary_type_conversion PROTO((enum tree_code, tree *, tree *));
extern tree type_promotes_to PROTO((tree));
+extern tree perform_qualification_conversions PROTO((tree, tree));
+extern tree perform_array_to_pointer_conversion PROTO((tree));
/* decl.c */
/* resume_binding_level */
@@ -2317,14 +2321,16 @@ extern void begin_template_parm_list PROTO((void));
extern void begin_specialization PROTO((void));
extern void reset_specialization PROTO((void));
extern void end_specialization PROTO((void));
-extern tree determine_explicit_specialization PROTO((tree, tree, tree *, int, int));
-extern int check_explicit_specialization PROTO((tree, tree, int, int));
+extern void begin_explicit_instantiation PROTO((void));
+extern void end_explicit_instantiation PROTO((void));
+extern tree determine_specialization PROTO((tree, tree, tree *, int, int));
+extern int check_explicit_specialization PROTO((tree, tree, int, int));
extern tree process_template_parm PROTO((tree, tree));
extern tree end_template_parm_list PROTO((tree));
extern void end_template_decl PROTO((void));
extern tree current_template_args PROTO((void));
extern void push_template_decl PROTO((tree));
-extern tree lookup_template_class PROTO((tree, tree, tree));
+extern tree lookup_template_class PROTO((tree, tree, tree, tree));
extern tree lookup_template_function PROTO((tree, tree));
extern int uses_template_parms PROTO((tree));
extern tree instantiate_class_template PROTO((tree));
@@ -2344,6 +2350,8 @@ extern tree do_poplevel PROTO((void));
extern tree get_bindings PROTO((tree, tree));
/* CONT ... */
extern void add_tree PROTO((tree));
+extern void begin_tree PROTO((void));
+extern void end_tree PROTO((void));
extern void add_maybe_template PROTO((tree, tree));
extern void pop_tinst_level PROTO((void));
extern tree most_specialized PROTO((tree, tree));
@@ -2351,7 +2359,9 @@ extern tree most_specialized_class PROTO((tree, tree));
extern int more_specialized_class PROTO((tree, tree));
extern void do_pushlevel PROTO((void));
extern int is_member_template PROTO((tree));
+extern int comp_template_parms PROTO((tree, tree));
extern int processing_specialization;
+extern int processing_explicit_instantiation;
/* in repo.c */
extern void repo_template_used PROTO((tree));
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 687ac5c..341b83a 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -1682,3 +1682,134 @@ type_promotes_to (type)
return cp_build_type_variant (type, constp, volatilep);
}
+
+
+/* The routines below this point are carefully written to conform to
+ the standard. They use the same terminology, and follow the rules
+ closely. Although they are used only in pt.c at the moment, they
+ should presumably be used everywhere in the future. */
+
+tree
+perform_qualification_conversions (type, expr)
+ tree type;
+ tree expr;
+{
+ tree expr_type = TREE_TYPE (expr);
+ tree t1;
+ tree t2;
+ int j;
+ int all_have_const = 1;
+
+ if (comptypes (type, expr_type, 1))
+ /* The two types are already the same, so there is nothing to do. */
+ return expr;
+
+ j = 0;
+ t1 = expr_type;
+ t2 = type;
+
+ while (1)
+ {
+ if (TREE_CODE (type) != TREE_CODE (expr_type))
+ return error_mark_node;
+
+ if (j > 0
+ && TREE_CODE (type) == POINTER_TYPE)
+ {
+ if (TYPE_READONLY (t1) > TYPE_READONLY (t2)
+ || TYPE_VOLATILE (t1) > TYPE_VOLATILE (t2))
+ /* For every j>0, if const is in cv1,j the const is in
+ cv2,j, and similarly for volatile. */
+ return error_mark_node;
+ }
+
+ if (!all_have_const
+ && (TYPE_READONLY (t1) != TYPE_READONLY (t2)
+ || TYPE_READONLY (t1) != TYPE_READONLY (t2)))
+ /* If the cv1,j and cv2,j are different, then const is in every
+ cv2,k for 0<k<j. */
+ return error_mark_node;
+
+ if (j > 0 && !TYPE_READONLY (t2))
+ all_have_const = 0;
+
+ if (TREE_CODE (type) != POINTER_TYPE)
+ {
+ if (j == 0)
+ /* The two things to be converted weren't even pointer
+ types. */
+ return error_mark_node;
+
+ if (TYPE_PTRMEMFUNC_P (type))
+ {
+ t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+ t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+ }
+
+ if (comptypes (TYPE_MAIN_VARIANT (t1),
+ TYPE_MAIN_VARIANT (t2), 1))
+ return build1 (NOP_EXPR, type, expr);
+ else
+ /* The pointers were not similar. */
+ return error_mark_node;
+ }
+
+ if (TYPE_PTRMEM_P (type)
+ && !comptypes (TYPE_OFFSET_BASETYPE (TREE_TYPE (t1)),
+ TYPE_OFFSET_BASETYPE (TREE_TYPE (t2)),
+ 1))
+ /* One type is X::* and the other is Y::*. */
+ return error_mark_node;
+
+ if (TYPE_PTRMEM_P (type))
+ {
+ t1 = TREE_TYPE (TREE_TYPE (t1));
+ t2 = TREE_TYPE (TREE_TYPE (t2));
+ }
+ else
+ {
+ t1 = TREE_TYPE (t1);
+ t2 = TREE_TYPE (t2);
+ }
+ }
+}
+
+
+/* Perform array-to-pointer conversion on EXPR, if appropriate.
+ Return the converted expression, or EXPR if no
+ conversion was performed, or error_mark_node if the conversion was
+ attempted, but failed. (For example, if an attempt is made to take
+ the address of a non-addressable object.) */
+
+tree
+perform_array_to_pointer_conversion (expr)
+ tree expr;
+{
+ tree result = expr;
+
+ if (TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE)
+ {
+ tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (expr)));
+
+ /* This section is copied from decay_conversion. */
+ if (TREE_CODE (expr) == VAR_DECL)
+ {
+ /* ??? This is not really quite correct
+ in that the type of the operand of ADDR_EXPR
+ is not the target type of the type of the ADDR_EXPR itself.
+ Question is, can this lossage be avoided? */
+ result = build1 (ADDR_EXPR, type, expr);
+ if (mark_addressable (expr) == 0)
+ return error_mark_node;
+ TREE_CONSTANT (result) = staticp (expr);
+ TREE_SIDE_EFFECTS (result) = 0; /* Default would be, same as
+ EXPR. */
+ }
+ else
+ /* This way is better for a COMPONENT_REF since it can
+ simplify the offset for a component. */
+ result = build_unary_op (ADDR_EXPR, expr, 1);
+ }
+
+ return result;
+}
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 8ffcc9d..7bdc607 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2529,7 +2529,9 @@ duplicate_decls (newdecl, olddecl)
else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL
&& TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL
&& compparms (TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl))),
- TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))), 3))
+ TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))), 3)
+ && comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
+ DECL_TEMPLATE_PARMS (olddecl)))
{
cp_error ("new declaration `%#D'", newdecl);
cp_error_at ("ambiguates old declaration `%#D'", olddecl);
@@ -2563,19 +2565,31 @@ duplicate_decls (newdecl, olddecl)
cp_error_at ("previous declaration as `%#D'", olddecl);
}
}
- else if ((TREE_CODE (olddecl) == FUNCTION_DECL
- && DECL_TEMPLATE_SPECIALIZATION (olddecl)
- && (!DECL_TEMPLATE_SPECIALIZATION (newdecl)
- || (DECL_TI_TEMPLATE (newdecl)
- != DECL_TI_TEMPLATE (olddecl))))
- || (TREE_CODE (newdecl) == FUNCTION_DECL
- && DECL_TEMPLATE_SPECIALIZATION (newdecl)
- && (!DECL_TEMPLATE_SPECIALIZATION (olddecl)
- || (DECL_TI_TEMPLATE (olddecl) != DECL_TI_TEMPLATE
- (newdecl)))))
+ else if (TREE_CODE (newdecl) == FUNCTION_DECL
+ && ((DECL_TEMPLATE_SPECIALIZATION (olddecl)
+ && (!DECL_TEMPLATE_INFO (newdecl)
+ || (DECL_TI_TEMPLATE (newdecl)
+ != DECL_TI_TEMPLATE (olddecl))))
+ || (DECL_TEMPLATE_SPECIALIZATION (newdecl)
+ && (!DECL_TEMPLATE_INFO (olddecl)
+ || (DECL_TI_TEMPLATE (olddecl)
+ != DECL_TI_TEMPLATE (newdecl))))))
/* It's OK to have a template specialization and a non-template
with the same type, or to have specializations of two
- different templates with the same type. */
+ different templates with the same type. Note that if one is a
+ specialization, and the other is an instantiation of the same
+ template, that we do not exit at this point. That situation
+ can occur if we instantiate a template class, and then
+ specialize one of its methods. This situation is legal, but
+ the declarations must be merged in the usual way. */
+ return 0;
+ else if (TREE_CODE (newdecl) == FUNCTION_DECL
+ && ((DECL_TEMPLATE_INSTANTIATION (olddecl)
+ && !DECL_USE_TEMPLATE (newdecl))
+ || (DECL_TEMPLATE_INSTANTIATION (newdecl)
+ && !DECL_USE_TEMPLATE (olddecl))))
+ /* One of the declarations is a template instantiation, and the
+ other is not a template at all. That's OK. */
return 0;
else
{
@@ -2860,9 +2874,29 @@ duplicate_decls (newdecl, olddecl)
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
- if (DECL_TEMPLATE_INSTANTIATION (olddecl) &&
- !DECL_TEMPLATE_INSTANTIATION (newdecl))
- DECL_USE_TEMPLATE (olddecl) = DECL_USE_TEMPLATE (newdecl);
+ if (DECL_TEMPLATE_INSTANTIATION (olddecl)
+ && !DECL_TEMPLATE_INSTANTIATION (newdecl))
+ {
+ /* If newdecl is not a specialization, then it is not a
+ template-related function at all. And that means that we
+ shoud have exited above, returning 0. */
+ my_friendly_assert (DECL_TEMPLATE_SPECIALIZATION (newdecl),
+ 0);
+
+ if (TREE_USED (olddecl))
+ /* From [temp.expl.spec]:
+
+ If a template, a member template or the member of a class
+ template is explicitly specialized then that
+ specialization shall be declared before the first use of
+ that specialization that would cause an implicit
+ instantiation to take place, in every translation unit in
+ which such a use occurs. */
+ cp_error ("explicit specialization of %D after first use",
+ olddecl);
+
+ SET_DECL_TEMPLATE_SPECIALIZATION (olddecl);
+ }
DECL_THIS_INLINE (newdecl) |= DECL_THIS_INLINE (olddecl);
/* If either decl says `inline', this fn is inline, unless its
@@ -2922,8 +2956,8 @@ duplicate_decls (newdecl, olddecl)
if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
- DECL_TEMPLATE_INSTANTIATIONS (newdecl)
- = DECL_TEMPLATE_INSTANTIATIONS (olddecl);
+ DECL_TEMPLATE_SPECIALIZATIONS (newdecl)
+ = DECL_TEMPLATE_SPECIALIZATIONS (olddecl);
if (DECL_CHAIN (newdecl) == NULL_TREE)
DECL_CHAIN (newdecl) = DECL_CHAIN (olddecl);
}
@@ -2965,6 +2999,38 @@ duplicate_decls (newdecl, olddecl)
#define ROUND(x) ((x + obstack_alignment_mask (&permanent_obstack)) \
& ~ obstack_alignment_mask (&permanent_obstack))
+ if (DECL_TEMPLATE_INSTANTIATION (newdecl))
+ {
+ /* If newdecl is a template instantiation, it is possible that
+ the following sequence of events has occurred:
+
+ o A friend function was declared in a class template. The
+ class template was instantiated.
+
+ o The instantiation of the friend declaration was
+ recorded on the instantiation list, and is newdecl.
+
+ o Later, however, instantiate_class_template called pushdecl
+ on the newdecl to perform name injection. But, pushdecl in
+ turn called duplicate_decls when it discovered that another
+ declaration of a global function with the same name already
+ existed.
+
+ o Here, in duplicate_decls, we decided to clobber newdecl.
+
+ If we're going to do that, we'd better make sure that
+ olddecl, and not newdecl, is on the list of
+ instantiations so that if we try to do the instantiation
+ again we won't get the clobbered declaration. */
+
+ tree tmpl = DECL_TI_TEMPLATE (newdecl);
+ tree decls = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+
+ for (; decls; decls = TREE_CHAIN (decls))
+ if (TREE_VALUE (decls) == newdecl)
+ TREE_VALUE (decls) = olddecl;
+ }
+
if ((char *)newdecl + ROUND (function_size)
+ ROUND (sizeof (struct lang_decl))
== obstack_next_free (&permanent_obstack))
@@ -6024,6 +6090,13 @@ start_decl (declarator, declspecs, initialized)
context, DECL_NAME (decl));
DECL_CONTEXT (decl) = DECL_CONTEXT (field);
}
+ /* Static data member are tricky; an in-class initialization
+ still doesn't provide a definition, so the in-class
+ declaration will have DECL_EXTERNAL set, but will have an
+ initialization. Thus, duplicate_decls won't warn
+ about this situation, and so we check here. */
+ if (DECL_INITIAL (decl) && DECL_INITIAL (field))
+ cp_error ("duplicate initialization of %D", decl);
if (duplicate_decls (decl, field))
decl = field;
}
@@ -6056,7 +6129,13 @@ start_decl (declarator, declspecs, initialized)
if ((TREE_CODE (decl) != PARM_DECL && DECL_CONTEXT (decl) != NULL_TREE)
|| (TREE_CODE (decl) == TEMPLATE_DECL && !global_bindings_p ())
- || TREE_CODE (type) == LANG_TYPE)
+ || TREE_CODE (type) == LANG_TYPE
+ /* The declaration of template specializations does not affect
+ the functions available for overload resolution, so we do not
+ call pushdecl. */
+ || (!flag_guiding_decls
+ && TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_TEMPLATE_SPECIALIZATION (decl)))
tem = decl;
else
tem = pushdecl (decl);
@@ -6397,9 +6476,12 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
if (minimal_parse_mode && ! DECL_ARTIFICIAL (decl))
{
tree stmt = DECL_VINDEX (decl);
- DECL_VINDEX (decl) = NULL_TREE;
- TREE_OPERAND (stmt, 2) = copy_to_permanent (init);
- add_tree (stmt);
+ if (stmt != NULL_TREE)
+ {
+ DECL_VINDEX (decl) = NULL_TREE;
+ TREE_OPERAND (stmt, 2) = copy_to_permanent (init);
+ add_tree (stmt);
+ }
}
goto finish_end0;
@@ -6685,7 +6767,11 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
|| TREE_CODE (decl) == RESULT_DECL)
{
/* ??? FIXME: What about nested classes? */
- int toplev = toplevel_bindings_p () || pseudo_global_level_p ();
+ /* We check for FUNCTION_DECL here so that member functions of
+ local classes, which will have internal linkage, are not
+ given bizarre names by make_decl_rtl. */
+ int toplev = toplevel_bindings_p () || pseudo_global_level_p ()
+ || TREE_CODE (decl) == FUNCTION_DECL;
int was_temp
= (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type)
&& allocation_temporary_p ());
@@ -7367,12 +7453,12 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
break;
}
- /* Caller will do the rest of this. */
- check_explicit_specialization (orig_declarator, decl,
- template_count,
- funcdef_flag ? 2 :
- (friendp ? 3 : 0));
+ if (friendp &&
+ TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)
+ /* A friend declaration of the form friend void f<>(). */
+ SET_DECL_IMPLICIT_INSTANTIATION (decl);
+ /* Caller will do the rest of this. */
if (check < 0)
return decl;
@@ -7391,6 +7477,11 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
grokclassfn (ctype, declarator, decl, flags, quals);
+ check_explicit_specialization (orig_declarator, decl,
+ template_count,
+ funcdef_flag ? 2 :
+ (friendp ? 3 : 0));
+
if (check)
{
tmp = check_classfn (ctype, decl);
@@ -7433,12 +7524,17 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
if (ctype != NULL_TREE)
grokclassfn (ctype, cname, decl, flags, quals);
+ check_explicit_specialization (orig_declarator, decl,
+ template_count,
+ funcdef_flag ? 2 :
+ (friendp ? 3 : 0));
+
if (ctype != NULL_TREE && check)
{
tmp = check_classfn (ctype, decl);
if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL)
- tmp = DECL_TEMPLATE_RESULT(tmp);
+ tmp = DECL_TEMPLATE_RESULT (tmp);
if (tmp && DECL_STATIC_FUNCTION_P (tmp)
&& TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
@@ -7466,19 +7562,27 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
methods, though. */
if (! current_function_decl)
{
- /* FIXME: this should only need to look at
- IDENTIFIER_GLOBAL_VALUE. */
- tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
- if (tmp == NULL_TREE)
- IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl)) = decl;
- else if (TREE_CODE (tmp) != TREE_CODE (decl))
- cp_error ("inconsistent declarations for `%D'", decl);
- else
+ if (!DECL_TEMPLATE_SPECIALIZATION (decl))
{
- duplicate_decls (decl, tmp);
- decl = tmp;
- /* avoid creating circularities. */
- DECL_CHAIN (decl) = NULL_TREE;
+ /* We don't do this for specializations since the
+ equivalent checks will be done later. Also, at this
+ point the DECL_ASSEMBLER_NAME is not yet fully
+ accurate. */
+
+ /* FIXME: this should only need to look at
+ IDENTIFIER_GLOBAL_VALUE. */
+ tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
+ if (tmp == NULL_TREE)
+ IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl)) = decl;
+ else if (TREE_CODE (tmp) != TREE_CODE (decl))
+ cp_error ("inconsistent declarations for `%D'", decl);
+ else
+ {
+ duplicate_decls (decl, tmp);
+ decl = tmp;
+ /* avoid creating circularities. */
+ DECL_CHAIN (decl) = NULL_TREE;
+ }
}
if (attrlist)
@@ -9169,7 +9273,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
t = ctype;
while (t != NULL_TREE)
{
- if (CLASSTYPE_TEMPLATE_INFO (t))
+ if (CLASSTYPE_TEMPLATE_INFO (t) &&
+ !CLASSTYPE_TEMPLATE_SPECIALIZATION (t))
template_count += 1;
t = TYPE_MAIN_DECL (t);
if (DECL_LANG_SPECIFIC (t))
@@ -9595,7 +9700,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
}
/* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */
- publicp = (! friendp || ! staticp);
+ publicp = (! friendp || ! staticp) && !is_local_class (ctype);
decl = grokfndecl (ctype, type,
TREE_CODE (declarator) != TEMPLATE_ID_EXPR
? declarator : dname,
@@ -9811,7 +9916,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
decl = grokfndecl (ctype, type, original_name, declarator,
virtualp, flags, quals, raises, attrlist,
- friendp ? 2 : 1, friendp,
+ 1, friendp,
publicp, inlinep, funcdef_flag,
template_count);
if (decl == NULL_TREE)
@@ -10926,8 +11031,8 @@ xref_basetypes (code_type_node, name, ref, binfo)
}
#if 1
/* This code replaces similar code in layout_basetypes. */
- else if (TYPE_SIZE (complete_type (basetype)) == NULL_TREE
- && ! (current_template_parms && uses_template_parms (basetype)))
+ else if (! (current_template_parms && uses_template_parms (basetype))
+ && TYPE_SIZE (complete_type (basetype)) == NULL_TREE)
{
cp_error ("base class `%T' has incomplete type", basetype);
continue;
@@ -11506,7 +11611,10 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
push_template_decl (decl1);
else if (pre_parsed_p == 0)
{
- decl1 = pushdecl (decl1);
+ /* A specialization is not used to guide overload resolution. */
+ if (flag_guiding_decls
+ || !DECL_TEMPLATE_SPECIALIZATION (decl1))
+ decl1 = pushdecl (decl1);
DECL_MAIN_VARIANT (decl1) = decl1;
fntype = TREE_TYPE (decl1);
}
@@ -11637,7 +11745,6 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
if (processing_template_decl)
{
- extern tree last_tree;
++minimal_parse_mode;
last_tree = DECL_SAVED_TREE (decl1)
= build_nt (EXPR_STMT, void_zero_node);
@@ -12361,9 +12468,21 @@ finish_function (lineno, call_poplevel, nested)
if (! processing_template_decl)
{
+ int saved_flag_keep_inline_functions =
+ flag_keep_inline_functions;
+
/* So we can tell if jump_optimize sets it to 1. */
can_reach_end = 0;
+ if (DECL_CONTEXT (fndecl) != NULL_TREE
+ && is_local_class (DECL_CONTEXT (fndecl)))
+ /* Trick rest_of_compilation into not deferring output of this
+ function, even if it is inline, since the rtl_obstack for
+ this function is the function_obstack of the enclosing
+ function and will be deallocated when the enclosing
+ function is gone. See save_tree_status. */
+ flag_keep_inline_functions = 1;
+
/* Run the optimizers and output the assembler code for this
function. */
@@ -12384,6 +12503,8 @@ finish_function (lineno, call_poplevel, nested)
else
rest_of_compilation (fndecl);
+ flag_keep_inline_functions = saved_flag_keep_inline_functions;
+
if (DECL_SAVED_INSNS (fndecl) && ! TREE_ASM_WRITTEN (fndecl))
{
/* Set DECL_EXTERNAL so that assemble_external will be called as
@@ -12529,7 +12650,7 @@ start_method (declspecs, declarator)
if (flag_default_inline)
DECL_INLINE (fndecl) = 1;
- if (processing_template_decl && ! current_function_decl)
+ if (processing_template_decl)
push_template_decl (fndecl);
/* We read in the parameters on the maybepermanent_obstack,
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 971a3e4..f10390d 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -2785,7 +2785,11 @@ import_export_decl (decl)
if (DECL_IMPLICIT_INSTANTIATION (decl)
&& (flag_implicit_templates || DECL_THIS_INLINE (decl)))
{
- if (TREE_CODE (decl) == FUNCTION_DECL)
+ if (!TREE_PUBLIC (decl))
+ /* Templates are allowed to have internal linkage. See
+ [basic.link]. */
+ ;
+ else if (TREE_CODE (decl) == FUNCTION_DECL)
comdat_linkage (decl);
else
DECL_COMDAT (decl) = 1;
@@ -3600,9 +3604,20 @@ build_expr_from_tree (t)
}
case COMPONENT_REF:
- return build_x_component_ref
- (build_expr_from_tree (TREE_OPERAND (t, 0)),
- TREE_OPERAND (t, 1), NULL_TREE, 1);
+ {
+ tree object = build_expr_from_tree (TREE_OPERAND (t, 0));
+
+ if (object != NULL_TREE
+ && TREE_CODE (object) == TEMPLATE_DECL)
+ {
+ cp_error ("invalid use of %D", object);
+ object = error_mark_node;
+ }
+
+ return build_x_component_ref
+ (object,
+ TREE_OPERAND (t, 1), NULL_TREE, 1);
+ }
case THROW_EXPR:
return build_throw (build_expr_from_tree (TREE_OPERAND (t, 0)));
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index d2cad74..cc264e6 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -952,71 +952,89 @@ dump_function_name (t)
else
dump_decl (name, 0);
- if (DECL_LANG_SPECIFIC (t)
- && (DECL_TEMPLATE_SPECIALIZATION (t) || DECL_IMPLICIT_INSTANTIATION (t))
- && (DECL_CLASS_CONTEXT (t) == NULL_TREE || is_member_template (t)))
+ if (DECL_LANG_SPECIFIC (t) && DECL_USE_TEMPLATE (t))
{
- tree args = DECL_TEMPLATE_INFO (t)
- ? DECL_TI_ARGS (t) : NULL_TREE;
-
- OB_PUTC ('<');
-
- /* Be careful only to print things when we have them, so as not
- to crash producing error messages. */
- if (args)
+ tree args = DECL_TEMPLATE_INFO (t) ? DECL_TI_ARGS (t) : NULL_TREE;
+
+ if (args != NULL_TREE
+ && DECL_CONTEXT (t) != NULL_TREE
+ && uses_template_parms (DECL_CONTEXT (t))
+ /* This next clause checks that there is only one level of
+ template arguments. In that case, they are the
+ arguments for the class context. */
+ && (TREE_CODE (args) == TREE_LIST
+ || (TREE_CODE (args) == TREE_VEC
+ && TREE_VEC_ELT (args, 0) != NULL_TREE
+ && TREE_CODE (TREE_VEC_ELT (args, 0)) != TREE_VEC)))
+ /* We have something like this:
+
+ template <class T> struct S { void f(); };
+
+ and we are printing S<int>::f(). This is a template
+ instantiation, but we don't print anything after the f. */
+ ;
+ else
{
- if (TREE_CODE (args) == TREE_LIST)
- {
- tree arg;
- int need_comma = 0;
+ OB_PUTC ('<');
- for (arg = args; arg; arg = TREE_CHAIN (arg))
+ /* Be careful only to print things when we have them, so as not
+ to crash producing error messages. */
+ if (args)
+ {
+ if (TREE_CODE (args) == TREE_LIST)
{
- tree a = TREE_VALUE (arg);
-
- if (need_comma)
- OB_PUTS (", ");
+ tree arg;
+ int need_comma = 0;
- if (a)
+ for (arg = args; arg; arg = TREE_CHAIN (arg))
{
- if (TREE_CODE_CLASS (TREE_CODE (a)) == 't')
- dump_type (a, 0);
- else
- dump_expr (a, 0);
- }
+ tree a = TREE_VALUE (arg);
+
+ if (need_comma)
+ OB_PUTS (", ");
+
+ if (a)
+ {
+ if (TREE_CODE_CLASS (TREE_CODE (a)) == 't')
+ dump_type (a, 0);
+ else
+ dump_expr (a, 0);
+ }
- need_comma = 1;
+ need_comma = 1;
+ }
}
- }
- else if (TREE_CODE (args) == TREE_VEC)
- {
- int i;
- int need_comma = 0;
-
- if (TREE_VEC_LENGTH (args) > 0
- && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
- args = TREE_VEC_ELT (args, 0);
-
- for (i = 0; i < TREE_VEC_LENGTH (args); i++)
+ else if (TREE_CODE (args) == TREE_VEC)
{
- tree a = TREE_VEC_ELT (args, i);
+ int i;
+ int need_comma = 0;
- if (need_comma)
- OB_PUTS (", ");
+ if (TREE_VEC_LENGTH (args) > 0
+ && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+ args = TREE_VEC_ELT (args,
+ TREE_VEC_LENGTH (args) - 1);
- if (a)
+ for (i = 0; i < TREE_VEC_LENGTH (args); i++)
{
- if (TREE_CODE_CLASS (TREE_CODE (a)) == 't')
- dump_type (a, 0);
- else
- dump_expr (a, 0);
- }
+ tree a = TREE_VEC_ELT (args, i);
+
+ if (need_comma)
+ OB_PUTS (", ");
+
+ if (a)
+ {
+ if (TREE_CODE_CLASS (TREE_CODE (a)) == 't')
+ dump_type (a, 0);
+ else
+ dump_expr (a, 0);
+ }
- need_comma = 1;
+ need_comma = 1;
+ }
}
}
+ OB_PUTC ('>');
}
- OB_PUTC ('>');
}
}
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 88068e3..1114a63 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -1995,15 +1995,21 @@ cons_up_default_function (type, full_name, kind)
{
tree declarator = make_call_declarator (name, args, NULL_TREE, NULL_TREE);
int saved_processing_specialization;
+ int saved_processing_explicit_instantiation;
if (retref)
declarator = build_parse_node (ADDR_EXPR, declarator);
/* The following is in case we're generating the default
implementation in the midst of handling a specialization. */
saved_processing_specialization = processing_specialization;
+ saved_processing_explicit_instantiation =
+ processing_explicit_instantiation;
processing_specialization = 0;
+ processing_explicit_instantiation = 0;
fn = grokfield (declarator, declspecs, NULL_TREE, NULL_TREE, NULL_TREE);
processing_specialization = saved_processing_specialization;
+ processing_explicit_instantiation =
+ saved_processing_explicit_instantiation;
}
if (fn == void_type_node)
diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y
index 4365513..054479e 100644
--- a/gcc/cp/parse.y
+++ b/gcc/cp/parse.y
@@ -56,7 +56,6 @@ extern int errno;
extern int end_of_file;
extern int current_class_depth;
-extern tree last_tree;
/* FSF LOCAL dje prefix attributes */
extern tree strip_attrs PROTO((tree));
@@ -73,6 +72,7 @@ extern tree strip_attrs PROTO((tree));
static char *cond_stmt_keyword;
static tree empty_parms PROTO((void));
+static tree finish_member_template_decl PROTO((tree, tree));
/* Nonzero if we have an `extern "C"' acting as an extern specifier. */
int have_extern_spec;
@@ -94,6 +94,32 @@ empty_parms ()
parms = NULL_TREE;
return parms;
}
+
+
+static tree
+finish_member_template_decl (template_arguments, decl)
+ tree template_arguments;
+ tree decl;
+{
+ if (template_arguments)
+ end_template_decl();
+ else
+ end_specialization();
+
+ if (decl && DECL_TEMPLATE_INFO (decl) &&
+ !DECL_TEMPLATE_SPECIALIZATION (decl))
+ {
+ check_member_template (DECL_TI_TEMPLATE (decl));
+ return DECL_TI_TEMPLATE (decl);
+ }
+
+ if (decl)
+ return decl;
+
+ cp_error ("invalid member template declaration");
+ return NULL_TREE;
+}
+
%}
%start program
@@ -260,7 +286,7 @@ empty_parms ()
%type <ttype> template_header template_parm_list template_parm
%type <ttype> template_type_parm
%type <code> template_close_bracket
-%type <ttype> template_type template_arg_list template_arg
+%type <ttype> template_type template_arg_list template_arg_list_opt template_arg
%type <ttype> condition xcond paren_cond_or_null
%type <ttype> type_name nested_name_specifier nested_type ptr_to_mem
%type <ttype> complete_type_name notype_identifier nonnested_type
@@ -716,26 +742,7 @@ fn.def2:
| constructor_declarator
{ $$ = start_method (NULL_TREE, $$); goto rest_of_mdef; }
| template_header fn.def2
- {
- if ($1)
- end_template_decl ();
- else
- end_specialization ();
-
- if ($2 && DECL_TEMPLATE_INFO ($2)
- && !DECL_TEMPLATE_SPECIALIZATION ($2))
- {
- $$ = DECL_TI_TEMPLATE ($2);
- check_member_template ($$);
- }
- else if ($2)
- $$ = $2;
- else
- {
- cp_error("invalid member template declaration");
- $$ = NULL_TREE;
- }
- }
+ { $$ = finish_member_template_decl ($1, $2); }
;
return_id:
@@ -848,54 +855,57 @@ identifier_defn:
;
explicit_instantiation:
- TEMPLATE typespec ';'
- { do_type_instantiation ($2.t, NULL_TREE);
- yyungetc (';', 1); }
- | TEMPLATE typed_declspecs declarator
- { tree specs = strip_attrs ($2.t);
- do_decl_instantiation (specs, $3, NULL_TREE); }
- | TEMPLATE notype_declarator
- { do_decl_instantiation (NULL_TREE, $2, NULL_TREE); }
- | TEMPLATE constructor_declarator
- { do_decl_instantiation (NULL_TREE, $2, NULL_TREE); }
- | SCSPEC TEMPLATE typespec ';'
- { do_type_instantiation ($3.t, $1);
+ TEMPLATE begin_explicit_instantiation typespec ';'
+ { do_type_instantiation ($3.t, NULL_TREE);
yyungetc (';', 1); }
- | SCSPEC TEMPLATE typed_declspecs declarator
+ end_explicit_instantiation
+ | TEMPLATE begin_explicit_instantiation typed_declspecs declarator
{ tree specs = strip_attrs ($3.t);
- do_decl_instantiation (specs, $4, $1); }
- | SCSPEC TEMPLATE notype_declarator
- { do_decl_instantiation (NULL_TREE, $3, $1); }
- | SCSPEC TEMPLATE constructor_declarator
- { do_decl_instantiation (NULL_TREE, $3, $1); }
- ;
+ do_decl_instantiation (specs, $4, NULL_TREE); }
+ end_explicit_instantiation
+ | TEMPLATE begin_explicit_instantiation notype_declarator
+ { do_decl_instantiation (NULL_TREE, $3, NULL_TREE); }
+ end_explicit_instantiation
+ | TEMPLATE begin_explicit_instantiation constructor_declarator
+ { do_decl_instantiation (NULL_TREE, $3, NULL_TREE); }
+ end_explicit_instantiation
+ | SCSPEC TEMPLATE begin_explicit_instantiation typespec ';'
+ { do_type_instantiation ($4.t, $1);
+ yyungetc (';', 1); }
+ end_explicit_instantiation
+ | SCSPEC TEMPLATE begin_explicit_instantiation typed_declspecs
+ declarator
+ { tree specs = strip_attrs ($4.t);
+ do_decl_instantiation (specs, $5, $1); }
+ end_explicit_instantiation
+ | SCSPEC TEMPLATE begin_explicit_instantiation notype_declarator
+ { do_decl_instantiation (NULL_TREE, $4, $1); }
+ end_explicit_instantiation
+ | SCSPEC TEMPLATE begin_explicit_instantiation constructor_declarator
+ { do_decl_instantiation (NULL_TREE, $4, $1); }
+ end_explicit_instantiation
+ ;
+
+begin_explicit_instantiation:
+ { begin_explicit_instantiation(); }
+
+end_explicit_instantiation:
+ { end_explicit_instantiation(); }
/* The TYPENAME expansions are to deal with use of a template class name as
a template within the class itself, where the template decl is hidden by
a type decl. Got all that? */
template_type:
- PTYPENAME '<' template_arg_list template_close_bracket
+ PTYPENAME '<' template_arg_list_opt template_close_bracket
{
- $$ = lookup_template_class ($1, $3, NULL_TREE);
+ $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
if ($$ != error_mark_node)
$$ = TYPE_STUB_DECL ($$);
}
- | PTYPENAME '<' template_close_bracket
+ | TYPENAME '<' template_arg_list_opt template_close_bracket
{
- $$ = lookup_template_class ($1, NULL_TREE, NULL_TREE);
- if ($$ != error_mark_node)
- $$ = TYPE_STUB_DECL ($$);
- }
- | TYPENAME '<' template_arg_list template_close_bracket
- {
- $$ = lookup_template_class ($1, $3, NULL_TREE);
- if ($$ != error_mark_node)
- $$ = TYPE_STUB_DECL ($$);
- }
- | TYPENAME '<' template_close_bracket
- {
- $$ = lookup_template_class ($1, NULL_TREE, NULL_TREE);
+ $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
if ($$ != error_mark_node)
$$ = TYPE_STUB_DECL ($$);
}
@@ -903,15 +913,9 @@ template_type:
;
self_template_type:
- SELFNAME '<' template_arg_list template_close_bracket
+ SELFNAME '<' template_arg_list_opt template_close_bracket
{
- $$ = lookup_template_class ($1, $3, NULL_TREE);
- if ($$ != error_mark_node)
- $$ = TYPE_STUB_DECL ($$);
- }
- | SELFNAME '<' template_close_bracket
- {
- $$ = lookup_template_class ($1, NULL_TREE, NULL_TREE);
+ $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
if ($$ != error_mark_node)
$$ = TYPE_STUB_DECL ($$);
}
@@ -927,8 +931,14 @@ template_close_bracket:
}
;
+template_arg_list_opt:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | template_arg_list
+ ;
+
template_arg_list:
- template_arg
+ template_arg
{ $$ = build_tree_list (NULL_TREE, $$); }
| template_arg_list ',' template_arg
{ $$ = chainon ($$, build_tree_list (NULL_TREE, $3)); }
@@ -1297,22 +1307,19 @@ do_id:
{ $$ = do_identifier ($<ttype>-1, 1); }
template_id:
- PFUNCNAME '<' do_id template_arg_list template_close_bracket
+ PFUNCNAME '<' do_id template_arg_list_opt template_close_bracket
{ $$ = lookup_template_function ($3, $4); }
- | PFUNCNAME '<' do_id template_close_bracket
- { $$ = lookup_template_function ($3, NULL_TREE); }
- | operator_name '<' do_id template_arg_list template_close_bracket
+ | operator_name '<' do_id template_arg_list_opt template_close_bracket
{ $$ = lookup_template_function ($3, $4); }
- | operator_name '<' do_id template_close_bracket
- { $$ = lookup_template_function ($3, NULL_TREE); }
;
object_template_id:
- TEMPLATE identifier '<' template_arg_list template_close_bracket
+ TEMPLATE identifier '<' template_arg_list_opt template_close_bracket
{ $$ = lookup_template_function ($2, $4); }
- | TEMPLATE PFUNCNAME '<' template_arg_list template_close_bracket
+ | TEMPLATE PFUNCNAME '<' template_arg_list_opt template_close_bracket
{ $$ = lookup_template_function ($2, $4); }
- | TEMPLATE operator_name '<' template_arg_list template_close_bracket
+ | TEMPLATE operator_name '<' template_arg_list_opt
+ template_close_bracket
{ $$ = lookup_template_function ($2, $4); }
;
@@ -1333,7 +1340,7 @@ expr_or_declarator:
;
notype_template_declarator:
- IDENTIFIER '<' template_arg_list template_close_bracket
+ IDENTIFIER '<' template_arg_list_opt template_close_bracket
{ $$ = lookup_template_function ($1, $3); }
| NSNAME '<' template_arg_list template_close_bracket
{ $$ = lookup_template_function ($1, $3); }
@@ -2261,7 +2268,6 @@ structsp:
$$.new_type_flag = 0; }
/* C++ extensions, merged with C to avoid shift/reduce conflicts */
| class_head left_curly
- { reset_specialization(); }
opt.component_decl_list '}' maybe_attribute
{
int semi;
@@ -2285,7 +2291,7 @@ structsp:
;
else
{
- $<ttype>$ = finish_struct ($1, $4, $6, semi);
+ $<ttype>$ = finish_struct ($1, $3, $5, semi);
if (semi) note_got_semicolon ($<ttype>$);
}
@@ -2304,10 +2310,13 @@ structsp:
}
pending_inlines
{
- $$.t = $<ttype>7;
+ $$.t = $<ttype>6;
$$.new_type_flag = 1;
if (current_class_type == NULL_TREE)
clear_inline_text_obstack ();
+
+ /* Undo the begin_tree in left_curly. */
+ end_tree ();
}
| class_head %prec EMPTY
{
@@ -2670,6 +2679,12 @@ left_curly:
if (t && IDENTIFIER_TEMPLATE (t))
overload_template_name (t, 1);
#endif
+ reset_specialization();
+
+ /* In case this is a local class within a template
+ function, we save the current tree structure so
+ that we can get it back later. */
+ begin_tree ();
}
;
@@ -2791,26 +2806,7 @@ component_decl_1:
| using_decl
{ $$ = do_class_using_decl ($1); }
| template_header component_decl_1
- {
- if ($1)
- end_template_decl ();
- else
- end_specialization ();
-
- if ($2 && DECL_TEMPLATE_INFO ($2)
- && !DECL_TEMPLATE_SPECIALIZATION ($2))
- {
- $$ = DECL_TI_TEMPLATE ($2);
- check_member_template ($$);
- }
- else if ($2)
- $$ = $2;
- else
- {
- cp_error("invalid member template declaration");
- $$ = NULL_TREE;
- }
- }
+ { $$ = finish_member_template_decl ($1, $2); }
/* The case of exactly one component is handled directly by component_decl. */
/* ??? Huh? ^^^ */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9476d12..b76a763 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -61,8 +61,11 @@ static tree *maybe_template_tail = &maybe_templates;
int minimal_parse_mode;
int processing_specialization;
+int processing_explicit_instantiation;
static int template_header_count;
+static tree saved_trees;
+
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
@@ -70,19 +73,19 @@ static int unify PROTO((tree, tree *, int, tree, tree, int *, int));
static void add_pending_template PROTO((tree));
static int push_tinst_level PROTO((tree));
static tree classtype_mangled_name PROTO((tree));
-static char *mangle_class_name_for_template PROTO((char *, tree, tree));
+static char *mangle_class_name_for_template PROTO((char *, tree, tree, tree));
static tree tsubst_expr_values PROTO((tree, tree));
static int comp_template_args PROTO((tree, tree));
static int list_eq PROTO((tree, tree));
static tree get_class_bindings PROTO((tree, tree, tree));
-static tree coerce_template_parms PROTO((tree, tree, tree));
+static tree coerce_template_parms PROTO((tree, tree, tree, int, int));
static tree tsubst_enum PROTO((tree, tree, int, tree *));
static tree add_to_template_args PROTO((tree, tree));
static int type_unification_real PROTO((tree, tree *, tree, tree, int*,
int, int, int));
-static int processing_explicit_specialization PROTO((int));
static void note_template_header PROTO((int));
static tree maybe_fold_nontype_arg PROTO((tree));
+static tree convert_nontype_parameter PROTO((tree, tree));
/* Restore the template parameter context. */
@@ -140,8 +143,19 @@ end_member_template_processing ()
poplevel (0, 0, 0);
}
-/* Returns non-zero iff T is a member template function. Works if T
- is either a FUNCTION_DECL or a TEMPLATE_DECL. */
+/* Returns non-zero iff T is a member template function. We must be
+ careful as in
+
+ template <class T> class C { void f(); }
+
+ Here, f is a template function, and a member, but not a member
+ template. This function does not concern itself with the origin of
+ T, only its present state. So if we have
+
+ template <class T> class C { template <class U> void f(U); }
+
+ then neither C<int>::f<char> nor C<T>::f<double> is considered
+ to be a member template. */
int
is_member_template (t)
@@ -151,7 +165,7 @@ is_member_template (t)
if (TREE_CODE (t) != FUNCTION_DECL
&& !DECL_FUNCTION_TEMPLATE_P (t))
- /* Anything that isn't a template or a template function is
+ /* Anything that isn't a function or a template function is
certainly not a member template. */
return 0;
@@ -175,33 +189,27 @@ is_member_template (t)
int template_class_levels = 0;
tree ctx = DECL_CLASS_CONTEXT (t);
- if (CLASSTYPE_TEMPLATE_INFO (ctx))
- {
- tree args;
+ /* NB - The code below does not yet handle template class
+ members, e.g.
+
+ template <class T> class C { template <class U> class D; }}
- /* Here, we should really count the number of levels
- deep ctx is, making sure not to count any levels that
- are just specializations. Since there are no member
- template classes yet, we don't have to do all that. */
+ correctly. In that case, the D should have level 2. */
- if (!CLASSTYPE_TEMPLATE_SPECIALIZATION (ctx))
+ if (CLASSTYPE_TEMPLATE_INFO (ctx))
+ {
+ tree args = CLASSTYPE_TI_ARGS (ctx);
+ int i;
+
+ if (args == NULL_TREE)
template_class_levels = 1;
- else
- {
- int i;
-
- args = CLASSTYPE_TI_ARGS (ctx);
-
- if (args == NULL_TREE)
- template_class_levels = 1;
- else
- for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
- if (uses_template_parms (TREE_VEC_ELT (args, i)))
- {
- template_class_levels++;
- break;
- }
- }
+ else
+ for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
+ if (uses_template_parms (TREE_VEC_ELT (args, i)))
+ {
+ template_class_levels++;
+ break;
+ }
}
if (parm_levels > template_class_levels)
@@ -298,68 +306,145 @@ note_template_header (specialization)
}
-/* Returns non-zero iff a declarator, in which the number of template
- types that appeared was TEMPLATE_COUNT, is an explicit
- specialization. */
+/* We're beginning an explicit instantiation. */
-static int
-processing_explicit_specialization (template_count)
- int template_count;
+void
+begin_explicit_instantiation ()
{
- /* A function declaration is an explicit specialization of a member
- template if all of the following conditions hold:
-
- o There was a template <...> preceeding the declaration.
- o The last template <...> was in fact template <>.
- o The number of template <...>'s preceeding the declaration, less
- the number of template classes with arguments specified used to
- qualify the function name, is 1.
+ ++processing_explicit_instantiation;
+}
- For example:
- template <> void S<int>::foo();
- template <class T> template <> void S<T>::foo();
- template <> struct S<int> { ... template <> void foo(); }
+void
+end_explicit_instantiation ()
+{
+ my_friendly_assert(processing_explicit_instantiation > 0, 0);
+ --processing_explicit_instantiation;
+}
- The first of these is not a specialization of S<int>::foo() (it
- is instead a specialization of S<T>::foo), while the next two are
- specializations of member template functions. */
- return processing_specialization
- && template_header_count > template_count;
+/* Retrieve the specialization (in the sense of [temp.spec] - a
+ specialization is either an instantiation or an explicit
+ specialization) of TMPL for the given template ARGS. If there is
+ no such specialization, return NULL_TREE. The ARGS are a vector of
+ arguments, or a vector of vectors of arguments, in the case of
+ templates with more than one level of parameters. */
+
+static tree
+retrieve_specialization (tmpl, args)
+ tree tmpl;
+ tree args;
+{
+ tree s;
+
+ my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
+
+ for (s = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+ s != NULL_TREE;
+ s = TREE_CHAIN (s))
+ if (comp_template_args (TREE_PURPOSE (s), args))
+ return TREE_VALUE (s);
+
+ return NULL_TREE;
}
-/* Returns the template function specialized by TEMPLATE_ID, or
- NULL_TREE if there is none.
- The TEMPLATE_ID is a TEMPLATE_ID_EXPR. The TYPE is
- the type it has been declared to have. Return the TEMPLATE_DECL
- that is being specialized, and put the specialization arguments in
- *TARGS. If no appropriate specialization can be found, NULL_TREE is
- returned, and *TARGS is assigned NULL_TREE. If complain is
- non-zero, error messages are printed where appropriate. */
-
+
+/* Register the specialization SPEC as a specialization of TMPL with
+ the indicated ARGS. */
+
+static void
+register_specialization (spec, tmpl, args)
+ tree spec;
+ tree tmpl;
+ tree args;
+{
+ tree s;
+
+ my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
+
+ if (TREE_CODE (spec) != TEMPLATE_DECL
+ && list_length (DECL_TEMPLATE_PARMS (tmpl)) > 1)
+ /* Avoid registering function declarations as
+ specializations of member templates, as would otherwise
+ happen with out-of-class specializations of member
+ templates. */
+ return;
+
+ for (s = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+ s != NULL_TREE;
+ s = TREE_CHAIN (s))
+ if (comp_template_args (TREE_PURPOSE (s), args))
+ {
+ tree fn = TREE_VALUE (s);
+
+ if (DECL_TEMPLATE_SPECIALIZATION (spec))
+ {
+ if (DECL_TEMPLATE_INSTANTIATION (fn))
+ {
+ if (TREE_USED (fn)
+ || DECL_EXPLICIT_INSTANTIATION (fn))
+ {
+ cp_error ("specialization of %D after instantiation",
+ fn);
+ return;
+ }
+ else
+ {
+ /* This situation should occur only if the first
+ specialization is an implicit instantiation,
+ the second is an explicit specialization, and
+ the implicit instantiation has not yet been
+ used. That situation can occur if we have
+ implicitly instantiated a member function of
+ class type, and then specialized it later. */
+
+ /* FIXME: Should we call duplicate_decls here? */
+ TREE_VALUE (s) = spec;
+ return;
+ }
+ }
+ else if (DECL_TEMPLATE_SPECIALIZATION (fn))
+ {
+ if (DECL_INITIAL (fn))
+ cp_error ("duplicate specialization of %D", fn);
+
+ /* FIXME: Should we call duplicate_decls here? */
+ TREE_VALUE (s) = spec;
+ return;
+ }
+ }
+ }
+
+ DECL_TEMPLATE_SPECIALIZATIONS (tmpl)
+ = perm_tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
+}
+
+
+/* Returns the template (one of the functions given by TEMPLATE_ID)
+ which can be specialized to have the indicated TYPE with the
+ explicit template args given in TEMPLATE_ID. TARGS_IN. The
+ template args (those explicitly specified and those deduced) are
+ output in a newly created vector *TARGS_OUT. If it is impossible
+ to determine the result, an error message is issued, unless
+ COMPLAIN is 0. */
+
tree
-determine_explicit_specialization (template_id, type, targs_out,
- need_member_template,
- complain)
+determine_specialization (template_id, type, targs_out,
+ need_member_template,
+ complain)
tree template_id;
tree type;
tree* targs_out;
int need_member_template;
int complain;
{
- int i;
- int overloaded;
- tree fns;
+ tree fns = TREE_OPERAND (template_id, 0);
+ tree targs_in = TREE_OPERAND (template_id, 1);
tree matching_fns = NULL_TREE;
- tree result;
tree fn;
-
- my_friendly_assert (TREE_CODE (template_id) == TEMPLATE_ID_EXPR
- && TREE_OPERAND (template_id, 0), 0);
-
- fns = TREE_OPERAND (template_id, 0);
+ int overloaded;
+ int i;
if (is_overloaded_fn (fns))
fn = get_first_fn (fns);
@@ -367,30 +452,38 @@ determine_explicit_specialization (template_id, type, targs_out,
fn = NULL_TREE;
overloaded = really_overloaded_fn (fns);
-
for (; fn != NULL_TREE;
fn = overloaded ? DECL_CHAIN (fn) : NULL_TREE)
{
int dummy = 0;
tree targs;
-
- if (TREE_CODE (fn) != TEMPLATE_DECL
+ tree t;
+ tree tmpl;
+
+ if (!need_member_template
+ && TREE_CODE (fn) == FUNCTION_DECL
+ && DECL_USE_TEMPLATE (fn)
+ && DECL_TI_TEMPLATE (fn))
+ tmpl = DECL_TI_TEMPLATE (fn);
+ else if (TREE_CODE (fn) != TEMPLATE_DECL
|| (need_member_template && !is_member_template (fn)))
continue;
+ else
+ tmpl = fn;
- if (list_length (TREE_OPERAND (template_id, 1)) > DECL_NTPARMS (fn))
+ if (list_length (targs_in) > DECL_NTPARMS (tmpl))
continue;
- targs = make_scratch_vec (DECL_NTPARMS (fn));
+ targs = make_scratch_vec (DECL_NTPARMS (tmpl));
/* We allow incomplete unification here, because we are going to
check all the functions. */
- i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn),
+ i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
&TREE_VEC_ELT (targs, 0),
type
- ? TYPE_ARG_TYPES (TREE_TYPE (fn)) : NULL_TREE,
+ ? TYPE_ARG_TYPES (TREE_TYPE (tmpl)) : NULL_TREE,
type ? TYPE_ARG_TYPES (type) : NULL_TREE,
- TREE_OPERAND (template_id, 1),
+ targs_in,
&dummy, 1, 1);
if (i == 0)
@@ -399,9 +492,9 @@ determine_explicit_specialization (template_id, type, targs_out,
match. */
if (type != NULL_TREE)
{
- tree tmpl_return_type = tsubst (TREE_TYPE (TREE_TYPE (fn)),
+ tree tmpl_return_type = tsubst (TREE_TYPE (TREE_TYPE (tmpl)),
targs,
- DECL_NTPARMS (fn),
+ DECL_NTPARMS (tmpl),
NULL_TREE);
if (tmpl_return_type != TREE_TYPE (type))
@@ -412,35 +505,37 @@ determine_explicit_specialization (template_id, type, targs_out,
problem. */
cp_error ("Return type of explicit specialization of");
cp_error ("`%D' is `%T', but should be `%T'.",
- fn, TREE_TYPE (type), tmpl_return_type);
+ tmpl, TREE_TYPE (type), tmpl_return_type);
*targs_out = NULL_TREE;
return NULL_TREE;
}
}
- matching_fns = scratch_tree_cons (fn, targs, matching_fns);
+ matching_fns = scratch_tree_cons (tmpl, targs, matching_fns);
}
}
-
+
if (matching_fns == NULL_TREE)
{
if (complain)
cp_error ("`%D' does not match any template declaration.",
template_id);
-
+
*targs_out = NULL_TREE;
return NULL_TREE;
}
-
+
if (TREE_CHAIN (matching_fns) != NULL_TREE)
{
if (complain)
{
- tree fn;
+ tree tmpl;
cp_error ("Ambiguous explicit specialization. Candidates are:");
- for (fn = matching_fns; fn != NULL_TREE; fn = TREE_CHAIN (fn))
- cp_error (" %D", TREE_PURPOSE (fn));
+ for (tmpl = matching_fns;
+ tmpl != NULL_TREE;
+ tmpl = TREE_CHAIN (tmpl))
+ cp_error (" %D", TREE_PURPOSE (tmpl));
}
*targs_out = NULL_TREE;
@@ -454,14 +549,50 @@ determine_explicit_specialization (template_id, type, targs_out,
/* Check to see if the function just declared, as indicated in
- DECLARATOR, and in DECL, is a specialization. Check that the
- specialization is OK. If FLAGS == 1, we are being called by
- finish_struct_methods. If FLAGS == 2, we are being called by
- grokfndecl, and the function has a definition, or is a friend. If
- FLAGS == 3, this is a friend declaration.
- Returns 0 if the decl is not an explicit specialization or
- instantiation, 1 if it is an explicit specialization, and 2 if it
- is an explicit instantiation. */
+ DECLARATOR, and in DECL, is a specialization of a function
+ template. We may also discover that the declaration is an explicit
+ instantiation at this point.
+
+ Returns:
+
+ 0: The function is not an explicit specialization or instantiation.
+ 1: The function is an explicit specialization.
+ 2: The function is an explicit instantiation.
+
+ FLAGS is a bitmask consisting of the following flags:
+
+ 1: We are being called by finish_struct. (We are unable to
+ determine what template is specialized by an in-class
+ declaration until the class definition is complete, so
+ finish_struct_methods calls this function again later to finish
+ the job.)
+ 2: The function has a definition.
+ 4: The function is a friend.
+ 8: The function is known to be a specialization of a member
+ template.
+
+ The TEMPLATE_COUNT is the number of references to qualifying
+ template classes that appeared in the name of the function. For
+ example, in
+
+ template <class T> struct S { void f(); };
+ void S<int>::f();
+
+ the TEMPLATE_COUNT would be 1. However, explicitly specialized
+ classes are not counted in the TEMPLATE_COUNT, so that in
+
+ template <class T> struct S {};
+ template <> struct S<int> { void f(); }
+ template <>
+ void S<int>::f();
+
+ the TEMPLATE_COUNT would be 0. (Note that this declaration is
+ illegal; there should be no template <>.)
+
+ If the function is a specialization, it is marked as such via
+ DECL_TEMPLATE_SPECIALIZATION. Furthermore, its DECL_TEMPLATE_INFO
+ is set up correctly, and it is added to the list of specializations
+ for that template. */
int
check_explicit_specialization (declarator, decl, template_count, flags)
@@ -470,49 +601,122 @@ check_explicit_specialization (declarator, decl, template_count, flags)
int template_count;
int flags;
{
- int finish_member = flags == 1;
- int have_def = flags == 2;
- int is_friend = flags == 3;
+ int finish_member = flags & 1;
+ int have_def = flags & 2;
+ int is_friend = flags & 4;
+ int specialization = 0;
+ int member_specialization = flags & 8;
+
+ tree ctype = DECL_CLASS_CONTEXT (decl);
+ tree dname = DECL_NAME (decl);
- if (processing_explicit_specialization (template_count)
- || finish_member
- || TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
+ if (!finish_member)
{
- tree tmpl = NULL_TREE;
- tree dname = DECL_NAME (decl);
- tree ctype = DECL_CLASS_CONTEXT (decl);
- tree targs;
+ if (processing_specialization)
+ {
+ /* The last template header was of the form template <>. */
+
+ if (template_header_count > template_count)
+ {
+ /* There were more template headers than qualifying template
+ classes. */
+ if (template_header_count - template_count > 1)
+ /* There shouldn't be that many template parameter
+ lists. There can be at most one parameter list for
+ every qualifying class, plus one for the function
+ itself. */
+ cp_error ("too many template parameter lists in declaration of `%D'", decl);
- /* We've come across a declarator that looks like: U f<T1,
- T2, ...>(A1, A2, ..). This is an explicit template
- specialization. Check that:
-
- o The explicitly specified parameters together with those
- that can be deduced by template argument deduction
- uniquely determine a particular specialization.
-
- See [temp.expl.spec]. */
+ SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+ if (ctype)
+ member_specialization = 1;
+ else
+ specialization = 1;
+ }
+ else if (template_header_count == template_count)
+ {
+ /* The counts are equal. So, this might be a
+ specialization, but it is not a specialization of a
+ member template. It might be something like
+
+ template <class T> struct S {
+ void f(int i);
+ };
+ template <>
+ void S<int>::f(int i) {} */
+ specialization = 1;
+ SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+ }
+ else
+ {
+ /* This cannot be an explicit specialization. There are not
+ enough headers for all of the qualifying classes. For
+ example, we might have:
+
+ template <>
+ void S<int>::T<char>::f();
+
+ But, we're missing another template <>. */
+ cp_error("too few template parameter lists in declaration of `%D'", decl);
+ return 0;
+ }
+ }
+ else if (processing_explicit_instantiation)
+ {
+ if (template_header_count)
+ cp_error ("template parameter list used in explicit instantiation");
+
+ if (have_def)
+ cp_error ("definition provided for explicit instantiation");
- if (!finish_member
- && TREE_CODE (declarator) == TEMPLATE_ID_EXPR
- && !processing_explicit_specialization (template_count)
- && !is_friend)
+ SET_DECL_EXPLICIT_INSTANTIATION (decl);
+
+ /* We don't try to figure out what's being explicitly
+ instantiated at this point, since do_decl_instantiation
+ will do that later. */
+ return 2;
+ }
+ else if ((ctype != NULL_TREE
+ && !TYPE_BEING_DEFINED (ctype)
+ && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype))
+ || TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
{
- if (! have_def && ! template_header_count && ! ctype)
- /* This is not an explict specialization. It must be
- an explicit instantiation. */
- return 2;
- else if (template_header_count > template_count
- && !processing_specialization)
+ /* The first part of the above clause catches illegal code
+ that looks like this:
+
+ template <class T> struct S { void f(); }
+ void S<int>::f() {} // Missing template <>
+
+ We disable this check when the type is being defined to
+ avoid complaining about default compiler-generated
+ constructors, destructors, and assignment operators.
+ Since the type is an instantiation, not a specialization,
+ these are the only functions that can be defined before
+ the class is complete.
+
+ The second part handles bogus declarations like
+ template <> template <class T>
+ void f<int>(); */
+
+ if (template_header_count > template_count)
{
cp_error ("template-id `%D' in declaration of primary template",
declarator);
return 0;
}
- else if (pedantic || uses_template_parms (decl))
- pedwarn ("explicit specialization not preceded by `template <>'");
+
+ cp_error ("explicit specialization not preceded by `template <>'");
+ return 0;
}
+ }
+ if (specialization || member_specialization)
+ {
+ tree tmpl = NULL_TREE;
+ tree targs = NULL_TREE;
+ tree targs_in;
+
+ /* Make sure that the declarator is a TEMPLATE_ID_EXPR. */
if (TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
{
tree fns;
@@ -524,7 +728,8 @@ check_explicit_specialization (declarator, decl, template_count, flags)
else
fns = dname;
- declarator = lookup_template_function (fns, NULL_TREE);
+ declarator =
+ lookup_template_function (fns, NULL_TREE);
}
if (TREE_CODE (TREE_OPERAND (declarator, 0)) == LOOKUP_EXPR)
@@ -536,50 +741,81 @@ check_explicit_specialization (declarator, decl, template_count, flags)
return 1;
}
- if (ctype
- && TREE_CODE (TREE_OPERAND (declarator, 0)) == IDENTIFIER_NODE)
+ if (ctype != NULL_TREE && TYPE_BEING_DEFINED (ctype))
+ {
+ /* Since finish_struct_1 has not been called yet, we
+ can't call lookup_fnfields. We note that this
+ template is a specialization, and proceed, letting
+ finish_struct fix this up later. */
+ DECL_TEMPLATE_INFO (decl)
+ = perm_tree_cons (NULL_TREE,
+ TREE_OPERAND (declarator, 1),
+ /* We remember whether or not this was a
+ member specialization by recording
+ this value, temporarily, in the
+ TREE_CHAIN field. Nobody looks at
+ this, and we clear it in
+ finish_struct. */
+ (tree) member_specialization);
+ return 1;
+ }
+ else if (ctype != NULL_TREE
+ && (TREE_CODE (TREE_OPERAND (declarator, 0)) ==
+ IDENTIFIER_NODE))
{
+ /* Find the list of functions in ctype that have the same
+ name as the declared function. */
+ tree name = TREE_OPERAND (declarator, 0);
tree fns;
-
- if (TYPE_BEING_DEFINED (ctype) && !finish_member)
+
+ if (name == constructor_name (ctype)
+ || name == constructor_name_full (ctype))
{
- /* Since finish_struct_1 has not been called yet, we
- can't call lookup_fnfields. We note that this
- template is a specialization, and proceed, letting
- finish_struct_methods fix this up later. */
- SET_DECL_TEMPLATE_SPECIALIZATION (decl);
- DECL_TEMPLATE_INFO (decl)
- = perm_tree_cons (NULL_TREE,
- TREE_OPERAND (declarator, 1),
- NULL_TREE);
- return 1;
- }
+ int is_constructor = DECL_CONSTRUCTOR_P (decl);
+
+ if (is_constructor ? !TYPE_HAS_CONSTRUCTOR (ctype)
+ : !TYPE_HAS_DESTRUCTOR (ctype))
+ {
+ /* From [temp.expl.spec]:
+
+ If such an explicit specialization for the member
+ of a class template names an implicitly-declared
+ special member function (clause _special_), the
+ program is ill-formed. */
+ cp_error ("specialization of implicitly-declared special member function");
+
+ return 1;
+ }
- fns = lookup_fnfields (TYPE_BINFO (ctype),
- TREE_OPERAND (declarator, 0),
- 1);
+ fns = TREE_VEC_ELT(CLASSTYPE_METHOD_VEC (ctype),
+ is_constructor ? 0 : 1);
+ }
+ else
+ fns = lookup_fnfields (TYPE_BINFO (ctype), name,
+ 1);
if (fns == NULL_TREE)
{
- cp_error ("No member template `%s' declared in `%T'",
- IDENTIFIER_POINTER (TREE_OPERAND (declarator,
- 0)),
+ cp_error ("no member function `%s' declared in `%T'",
+ IDENTIFIER_POINTER (name),
ctype);
return 1;
}
else
TREE_OPERAND (declarator, 0) = fns;
}
-
- tmpl =
- determine_explicit_specialization
- (declarator, TREE_TYPE (decl), &targs,
- TREE_CODE (decl) == TEMPLATE_DECL, 1);
+
+ /* Figure out what exactly is being specialized at this point. */
+ tmpl = determine_specialization (declarator,
+ TREE_TYPE (decl), &targs,
+ member_specialization,
+ 1);
if (tmpl)
{
/* Mangle the function name appropriately. */
- if (name_mangling_version >= 1)
+ if ((member_specialization || ctype == NULL_TREE)
+ && name_mangling_version >= 1)
{
tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (tmpl));
@@ -606,16 +842,9 @@ check_explicit_specialization (declarator, decl, template_count, flags)
SET_DECL_IMPLICIT_INSTANTIATION (decl);
DECL_TEMPLATE_INFO (decl)
= perm_tree_cons (tmpl, targs, NULL_TREE);
- return 1;
+ return 2;
}
- /* This function declaration is a template specialization.
- Record that fact. */
- SET_DECL_TEMPLATE_SPECIALIZATION (decl);
- DECL_TEMPLATE_SPECIALIZATIONS (tmpl)
- = perm_tree_cons (targs, decl,
- DECL_TEMPLATE_SPECIALIZATIONS
- (tmpl));
/* If DECL_TI_TEMPLATE (decl), the decl is an
instantiation of a specialization of a member template.
(In other words, there was a member template, in a
@@ -635,13 +864,70 @@ check_explicit_specialization (declarator, decl, template_count, flags)
if (!(DECL_TEMPLATE_INFO (decl) && DECL_TI_TEMPLATE (decl)))
DECL_TEMPLATE_INFO (decl)
= perm_tree_cons (tmpl, targs, NULL_TREE);
+
+ register_specialization (decl, tmpl, targs);
+
return 1;
}
}
-
+
return 0;
}
-
+
+
+/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
+ parameters. These are represented in the same format used for
+ DECL_TEMPLATE_PARMS. */
+
+int comp_template_parms (parms1, parms2)
+ tree parms1;
+ tree parms2;
+{
+ tree p1;
+ tree p2;
+
+ if (parms1 == parms2)
+ return 1;
+
+ for (p1 = parms1, p2 = parms2;
+ p1 != NULL_TREE && p2 != NULL_TREE;
+ p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2))
+ {
+ tree t1 = TREE_VALUE (p1);
+ tree t2 = TREE_VALUE (p2);
+ int i;
+
+ my_friendly_assert (TREE_CODE (t1) == TREE_VEC, 0);
+ my_friendly_assert (TREE_CODE (t2) == TREE_VEC, 0);
+
+ if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
+ return 0;
+
+ for (i = 0; i < TREE_VEC_LENGTH (t2); ++i)
+ {
+ tree parm1 = TREE_VALUE (TREE_VEC_ELT (t1, i));
+ tree parm2 = TREE_VALUE (TREE_VEC_ELT (t2, i));
+
+ if (TREE_CODE (parm1) != TREE_CODE (parm2))
+ return 0;
+
+ if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM)
+ continue;
+ else if (!comptypes (TREE_TYPE (parm1),
+ TREE_TYPE (parm2), 1))
+ return 0;
+ }
+ }
+
+ if ((p1 != NULL_TREE) != (p2 != NULL_TREE))
+ /* One set of parameters has more parameters lists than the
+ other. */
+ return 0;
+
+ return 1;
+}
+
+
/* Process information from new template parameter NEXT and append it to the
LIST being built. */
@@ -805,6 +1091,25 @@ current_template_args ()
return args;
}
+
+static tree
+build_template_decl (decl, parms)
+ tree decl;
+ tree parms;
+{
+ tree tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE);
+ DECL_TEMPLATE_PARMS (tmpl) = parms;
+ DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl);
+ if (DECL_LANG_SPECIFIC (decl))
+ {
+ DECL_CLASS_CONTEXT (tmpl) = DECL_CLASS_CONTEXT (decl);
+ DECL_STATIC_FUNCTION_P (tmpl) =
+ DECL_STATIC_FUNCTION_P (decl);
+ }
+
+ return tmpl;
+}
+
void
push_template_decl (decl)
@@ -851,25 +1156,19 @@ push_template_decl (decl)
args = current_template_args ();
- if (! ctx || TYPE_BEING_DEFINED (ctx))
+ if (! ctx || TREE_CODE (ctx) == FUNCTION_DECL
+ || TYPE_BEING_DEFINED (ctx))
{
- tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE);
- DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
- DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl);
- if (DECL_LANG_SPECIFIC (decl))
+ tmpl = build_template_decl (decl, current_template_parms);
+
+ if (DECL_LANG_SPECIFIC (decl)
+ && DECL_TEMPLATE_SPECIALIZATION (decl))
{
- DECL_CLASS_CONTEXT (tmpl) = DECL_CLASS_CONTEXT (decl);
- DECL_STATIC_FUNCTION_P (tmpl) =
- DECL_STATIC_FUNCTION_P (decl);
-
- if (DECL_TEMPLATE_SPECIALIZATION (decl))
- {
- /* A specialization of a member template of a template
- class. */
- SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
- DECL_TEMPLATE_INFO (tmpl) = DECL_TEMPLATE_INFO (decl);
- DECL_TEMPLATE_INFO (decl) = NULL_TREE;
- }
+ /* A specialization of a member template of a template
+ class. */
+ SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
+ DECL_TEMPLATE_INFO (tmpl) = DECL_TEMPLATE_INFO (decl);
+ DECL_TEMPLATE_INFO (decl) = NULL_TREE;
}
}
else
@@ -892,6 +1191,31 @@ push_template_decl (decl)
if (is_member_template (tmpl))
{
+ if (DECL_TEMPLATE_INFO (decl) && DECL_TI_ARGS (decl)
+ && DECL_TEMPLATE_SPECIALIZATION (decl))
+ {
+ tree new_tmpl;
+
+ /* The declaration is a specialization of a member
+ template, declared outside the class. Therefore, the
+ innermost template arguments will be NULL, so we
+ replace them with the arguments determined by the
+ earlier call to check_explicit_specialization. */
+ args = DECL_TI_ARGS (decl);
+
+ new_tmpl
+ = build_template_decl (decl, current_template_parms);
+ DECL_TEMPLATE_RESULT (new_tmpl) = decl;
+ TREE_TYPE (new_tmpl) = TREE_TYPE (decl);
+ DECL_TI_TEMPLATE (decl) = new_tmpl;
+ SET_DECL_TEMPLATE_SPECIALIZATION (new_tmpl);
+ DECL_TEMPLATE_INFO (new_tmpl) =
+ perm_tree_cons (tmpl, args, NULL_TREE);
+
+ register_specialization (new_tmpl, tmpl, args);
+ return;
+ }
+
a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
t = DECL_INNERMOST_TEMPLATE_PARMS (DECL_TI_TEMPLATE (decl));
if (TREE_VEC_LENGTH (t)
@@ -952,7 +1276,8 @@ push_template_decl (decl)
if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
{
CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (tmpl)) = info;
- DECL_NAME (decl) = classtype_mangled_name (TREE_TYPE (decl));
+ if (!ctx || TREE_CODE (ctx) != FUNCTION_DECL)
+ DECL_NAME (decl) = classtype_mangled_name (TREE_TYPE (decl));
}
else if (! DECL_LANG_SPECIFIC (decl))
cp_error ("template declaration of `%#D'", decl);
@@ -960,17 +1285,359 @@ push_template_decl (decl)
DECL_TEMPLATE_INFO (decl) = info;
}
+
+/* Attempt to determine which of the overloaded functions given by
+ FNS has the indicated TYPE. If this cannot be determined
+ unambiguously, return error_mark_node. */
+
+static tree
+determine_overloaded_function (type, fns)
+ tree type;
+ tree fns;
+{
+ tree fn;
+
+ my_friendly_assert (fns != NULL_TREE, 0);
+
+ if (!is_overloaded_fn (fns))
+ return error_mark_node;
+
+ if (really_overloaded_fn (fns))
+ {
+ fn = instantiate_type (type, fns, 0);
+ if (fn == error_mark_node)
+ /* We couldn't resolve the overloading. */
+ return error_mark_node;
+ }
+ else
+ fn = get_first_fn (fns);
+
+ my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
+
+ return fn;
+}
+
+
+/* Attempt to convert the non-type template parameter EXPR to the
+ indicated TYPE. If the conversion is successful, return the
+ converted value. If the conversion is unsuccesful, return
+ NULL_TREE if we issued an error message, or error_mark_node if we
+ did not. We issue error messages for out-and-out bad template
+ parameters, but not simply because the conversion failed, since we
+ might be just trying to do argument deduction. By the time this
+ function is called, neither TYPE nor EXPR may make use of template
+ parameters. */
+
+static tree
+convert_nontype_parameter (type, expr)
+ tree type;
+ tree expr;
+{
+ tree expr_type = TREE_TYPE (expr);
+
+ /* A template-argument for a non-type, non-template
+ template-parameter shall be one of:
+
+ --an integral constant-expression of integral or enumeration
+ type; or
+
+ --the name of a non-type template-parameter; or
+
+ --the name of an object or function with external linkage,
+ including function templates and function template-ids but
+ excluding non- tatic class members, expressed as id-expression;
+ or
+
+ --the address of an object or function with external linkage,
+ including function templates and function template-ids but
+ excluding non-static class members, expressed as & id-expression
+ where the & is optional if the name refers to a function or
+ array; or
+
+ --a pointer to member expressed as described in _expr.unary.op_. */
+
+ if (INTEGRAL_TYPE_P (expr_type)
+ || TYPE_PTRMEM_P (expr_type)
+ || TYPE_PTRMEMFUNC_P (expr_type))
+ {
+ if (!TREE_CONSTANT (expr)
+ /* FIXME: Should this case be handled by fold()? Why not? */
+ && !(TREE_CODE (expr) == VAR_DECL && TREE_READONLY (expr)))
+ {
+ cp_error ("non-constant `%E' cannot be used as template argument",
+ expr);
+ return NULL_TREE;
+ }
+ }
+ else if (TYPE_PTR_P (expr_type)
+ /* If expr is the address of an overloaded function, we
+ will get the unknown_type_node at this point. */
+ || expr_type == unknown_type_node)
+ {
+ tree referent;
+
+ if (TREE_CODE (expr) != ADDR_EXPR)
+ {
+ bad_argument:
+ cp_error ("`%E' is not a valid template argument", expr);
+ error ("it must be %s%s with external linkage",
+ TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE
+ ? "a pointer to " : "",
+ TREE_CODE (TREE_TYPE (TREE_TYPE (expr))) == FUNCTION_TYPE
+ ? "a function" : "an object");
+ return NULL_TREE;
+ }
+
+ referent = TREE_OPERAND (expr, 0);
+ STRIP_NOPS (referent);
+
+ if (TREE_CODE (referent) == STRING_CST)
+ {
+ cp_error ("string literal %E is not a valid template argument",
+ referent);
+ error ("because it is the address of an object with static linkage");
+ return NULL_TREE;
+ }
+
+ if (is_overloaded_fn (referent))
+ /* We'll check that it has external linkage later. */
+ ;
+ else if (TREE_CODE (referent) != VAR_DECL)
+ goto bad_argument;
+ else if (!TREE_PUBLIC (referent))
+ {
+ cp_error ("address of non-extern `%E' cannot be used as template argument", referent);
+ return error_mark_node;
+ }
+ }
+ else if (TREE_CODE (expr_type) == VAR_DECL)
+ {
+ if (!TREE_PUBLIC (expr))
+ goto bad_argument;
+ }
+ else if (is_overloaded_fn (expr))
+ /* OK for now. We'll check that it has external linkage later. */
+ ;
+ else
+ {
+ cp_error ("object `%E' cannot be used as template argument", expr);
+ return NULL_TREE;
+ }
+
+ switch (TREE_CODE (type))
+ {
+ case INTEGER_TYPE:
+ case BOOLEAN_TYPE:
+ case ENUMERAL_TYPE:
+ /* For a non-type template-parameter of integral or enumeration
+ type, integral promotions (_conv.prom_) and integral
+ conversions (_conv.integral_) are applied. */
+ if (!INTEGRAL_TYPE_P (expr_type))
+ return error_mark_node;
+
+ /* It's safe to call digest_init in this case; we know we're
+ just converting one integral constant expression to another. */
+ return digest_init (type, expr, (tree*) 0);
+
+ case POINTER_TYPE:
+ {
+ tree type_pointed_to = TREE_TYPE (type);
+
+ if (TYPE_PTRMEM_P (type))
+ /* For a non-type template-parameter of type pointer to data
+ member, qualification conversions (_conv.qual_) are
+ applied. */
+ return perform_qualification_conversions (type, expr);
+ else if (TREE_CODE (type_pointed_to) == FUNCTION_TYPE)
+ {
+ /* For a non-type template-parameter of type pointer to
+ function, only the function-to-pointer conversion
+ (_conv.func_) is applied. If the template-argument
+ represents a set of overloaded functions (or a pointer to
+ such), the matching function is selected from the set
+ (_over.over_). */
+ tree fns;
+ tree fn;
+
+ if (TYPE_PTRFN_P (expr_type) ||
+ expr_type == unknown_type_node)
+ fns = TREE_OPERAND (expr, 0);
+ else
+ fns = expr;
+
+ fn = determine_overloaded_function (type_pointed_to, fns);
+
+ if (fn == error_mark_node)
+ return error_mark_node;
+
+ if (!TREE_PUBLIC (fn))
+ {
+ if (really_overloaded_fn (fns))
+ return error_mark_node;
+ else
+ goto bad_argument;
+ }
+
+ expr = build_unary_op (ADDR_EXPR, fn, 0);
+
+ my_friendly_assert (comptypes (type, TREE_TYPE (expr), 1),
+ 0);
+ return expr;
+ }
+ else
+ {
+ /* For a non-type template-parameter of type pointer to
+ object, qualification conversions (_conv.qual_) and the
+ array-to-pointer conversion (_conv.array_) are applied.
+ [Note: In particular, neither the null pointer conversion
+ (_conv.ptr_) nor the derived-to-base conversion
+ (_conv.ptr_) are applied. Although 0 is a valid
+ template-argument for a non-type template-parameter of
+ integral type, it is not a valid template-argument for a
+ non-type template-parameter of pointer type.] */
+ expr = perform_array_to_pointer_conversion (expr);
+
+ if (expr == error_mark_node)
+ return error_mark_node;
+ else
+ return perform_qualification_conversions (type, expr);
+ }
+ }
+ break;
+
+ case REFERENCE_TYPE:
+ {
+ tree type_referred_to = TREE_TYPE (type);
+
+ if (TREE_CODE (type_referred_to) == FUNCTION_TYPE)
+ {
+ /* For a non-type template-parameter of type reference to
+ function, no conversions apply. If the
+ template-argument represents a set of overloaded
+ functions, the matching function is selected from the
+ set (_over.over_). */
+ tree fns = expr;
+ tree fn;
+
+ fn = determine_overloaded_function (type_referred_to, fns);
+
+ if (!TREE_PUBLIC (fn))
+ {
+ if (really_overloaded_fn (fns))
+ /* Don't issue an error here; we might get a different
+ function if the overloading had worked out
+ differently. */
+ return error_mark_node;
+ else
+ goto bad_argument;
+ }
+
+ if (fn == error_mark_node)
+ return error_mark_node;
+
+ my_friendly_assert (comptypes (type, TREE_TYPE (fn), 1),
+ 0);
+
+ return fn;
+ }
+ else
+ {
+ /* For a non-type template-parameter of type reference to
+ object, no conversions apply. The type referred to by the
+ reference may be more cv-qualified than the (otherwise
+ identical) type of the template-argument. The
+ template-parameter is bound directly to the
+ template-argument, which must be an lvalue. */
+ if (!comptypes (TYPE_MAIN_VARIANT (expr_type),
+ TYPE_MAIN_VARIANT (type), 1)
+ || (TYPE_READONLY (expr_type) >
+ TYPE_READONLY (type_referred_to))
+ || (TYPE_VOLATILE (expr_type) >
+ TYPE_VOLATILE (type_referred_to))
+ || !real_lvalue_p (expr))
+ return error_mark_node;
+ else
+ return expr;
+ }
+ }
+ break;
+
+ case RECORD_TYPE:
+ {
+ tree fns;
+ tree fn;
+
+ my_friendly_assert (TYPE_PTRMEMFUNC_P (type), 0);
+
+ /* For a non-type template-parameter of type pointer to member
+ function, no conversions apply. If the template-argument
+ represents a set of overloaded member functions, the
+ matching member function is selected from the set
+ (_over.over_). */
+
+ if (!TYPE_PTRMEMFUNC_P (expr_type) &&
+ expr_type != unknown_type_node)
+ return error_mark_node;
+
+ if (TREE_CODE (expr) == CONSTRUCTOR)
+ {
+ /* A ptr-to-member constant. */
+ if (!comptypes (type, expr_type, 1))
+ return error_mark_node;
+ else
+ return expr;
+ }
+
+ if (TREE_CODE (expr) != ADDR_EXPR)
+ return error_mark_node;
+
+ fns = TREE_OPERAND (expr, 0);
+
+ fn = determine_overloaded_function (TREE_TYPE (TREE_TYPE (type)),
+ fns);
+
+ if (fn == error_mark_node)
+ return error_mark_node;
+
+ expr = build_unary_op (ADDR_EXPR, fn, 0);
+
+ my_friendly_assert (comptypes (type, TREE_TYPE (expr), 1),
+ 0);
+ return expr;
+ }
+ break;
+
+ default:
+ /* All non-type parameters must have one of these types. */
+ my_friendly_abort (0);
+ break;
+ }
+
+ return error_mark_node;
+}
+
/* Convert all template arguments to their appropriate types, and return
a vector containing the resulting values. If any error occurs, return
- error_mark_node. */
+ error_mark_node, and, if COMPLAIN is non-zero, issue an error message.
+ Some error messages are issued even if COMPLAIN is zero; for
+ instance, if a template argument is composed from a local class.
+
+ If REQUIRE_ALL_ARGUMENTS is non-zero, all arguments must be
+ provided in ARGLIST, or else trailing parameters must have default
+ values. If REQUIRE_ALL_ARGUMENTS is zero, we will attempt argument
+ deduction for any unspecified trailing arguments. */
static tree
-coerce_template_parms (parms, arglist, in_decl)
+coerce_template_parms (parms, arglist, in_decl,
+ complain,
+ require_all_arguments)
tree parms, arglist;
tree in_decl;
+ int complain;
+ int require_all_arguments;
{
int nparms, nargs, i, lost = 0;
- tree vec;
+ tree vec = NULL_TREE;
if (arglist == NULL_TREE)
nargs = 0;
@@ -983,12 +1650,19 @@ coerce_template_parms (parms, arglist, in_decl)
if (nargs > nparms
|| (nargs < nparms
+ && require_all_arguments
&& TREE_PURPOSE (TREE_VEC_ELT (parms, nargs)) == NULL_TREE))
{
- error ("incorrect number of parameters (%d, should be %d)",
- nargs, nparms);
- if (in_decl)
- cp_error_at ("in template expansion for decl `%D'", in_decl);
+ if (complain)
+ {
+ error ("incorrect number of parameters (%d, should be %d)",
+ nargs, nparms);
+
+ if (in_decl)
+ cp_error_at ("in template expansion for decl `%D'",
+ in_decl);
+ }
+
return error_mark_node;
}
@@ -997,9 +1671,11 @@ coerce_template_parms (parms, arglist, in_decl)
else
{
vec = make_tree_vec (nparms);
+
for (i = 0; i < nparms; i++)
{
tree arg;
+ tree parm = TREE_VEC_ELT (parms, i);
if (arglist)
{
@@ -1011,13 +1687,15 @@ coerce_template_parms (parms, arglist, in_decl)
else
arg = TREE_VALUE (arg);
}
- else if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (parms, i)))
- == TYPE_DECL)
- arg = tsubst (TREE_PURPOSE (TREE_VEC_ELT (parms, i)),
- vec, i, in_decl);
+ else if (TREE_PURPOSE (parm) == NULL_TREE)
+ {
+ my_friendly_assert (!require_all_arguments, 0);
+ break;
+ }
+ else if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL)
+ arg = tsubst (TREE_PURPOSE (parm), vec, i, in_decl);
else
- arg = tsubst_expr (TREE_PURPOSE (TREE_VEC_ELT (parms, i)),
- vec, i, in_decl);
+ arg = tsubst_expr (TREE_PURPOSE (parm), vec, i, in_decl);
TREE_VEC_ELT (vec, i) = arg;
}
@@ -1029,6 +1707,20 @@ coerce_template_parms (parms, arglist, in_decl)
tree val = 0;
int is_type, requires_type;
+ if (arg == NULL_TREE)
+ /* We're out of arguments. */
+ {
+ my_friendly_assert (!require_all_arguments, 0);
+ break;
+ }
+
+ if (arg == error_mark_node)
+ {
+ cp_error ("template argument %d is invalid", i + 1);
+ lost++;
+ continue;
+ }
+
is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't';
requires_type = TREE_CODE (parm) == TYPE_DECL;
@@ -1037,6 +1729,7 @@ coerce_template_parms (parms, arglist, in_decl)
{
cp_pedwarn ("to refer to a type member of a template parameter,");
cp_pedwarn (" use `typename %E'", arg);
+
arg = make_typename_type (TREE_OPERAND (arg, 0),
TREE_OPERAND (arg, 1));
is_type = 1;
@@ -1045,13 +1738,16 @@ coerce_template_parms (parms, arglist, in_decl)
{
if (in_decl)
{
- cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
- i, in_decl);
- if (is_type)
- cp_error (" expected a constant of type `%T', got `%T'",
- TREE_TYPE (parm), arg);
- else
- cp_error (" expected a type, got `%E'", arg);
+ if (complain)
+ {
+ cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
+ i + 1, in_decl);
+ if (is_type)
+ cp_error (" expected a constant of type `%T', got `%T'",
+ TREE_TYPE (parm), arg);
+ else
+ cp_error (" expected a type, got `%E'", arg);
+ }
}
lost++;
TREE_VEC_ELT (vec, i) = error_mark_node;
@@ -1076,70 +1772,30 @@ coerce_template_parms (parms, arglist, in_decl)
{
tree t = tsubst (TREE_TYPE (parm), vec,
TREE_VEC_LENGTH (vec), in_decl);
+
if (processing_template_decl)
- val = maybe_fold_nontype_arg (arg);
+ arg = maybe_fold_nontype_arg (arg);
+
+ if (!uses_template_parms (arg) && !uses_template_parms (t))
+ /* We used to call digest_init here. However, digest_init
+ will report errors, which we don't want when complain
+ is zero. More importantly, digest_init will try too
+ hard to convert things: for example, `0' should not be
+ converted to pointer type at this point according to
+ the standard. Accepting this is not merely an
+ extension, since deciding whether or not these
+ conversions can occur is part of determining which
+ function template to call, or whether a given epxlicit
+ argument specification is legal. */
+ val = convert_nontype_parameter (t, arg);
else
val = arg;
- if (!uses_template_parms (val) && !uses_template_parms (t))
- val = digest_init (t, val, (tree *) 0);
-
- if (val == error_mark_node
- || (processing_template_decl && uses_template_parms (val)))
- ;
-
- /* 14.2: Other template-arguments must be constant-expressions,
- addresses of objects or functions with external linkage, or of
- static class members. */
- else if (IS_AGGR_TYPE (TREE_TYPE (val)))
- {
- cp_error ("object `%E' cannot be used as template argument", arg);
- val = error_mark_node;
- }
- else if (!TREE_CONSTANT (val))
- {
- cp_error ("non-constant `%E' cannot be used as template argument",
- arg);
- val = error_mark_node;
- }
- else if (POINTER_TYPE_P (TREE_TYPE (val))
- && ! integer_zerop (val)
- && TREE_CODE (TREE_TYPE (TREE_TYPE (val))) != OFFSET_TYPE
- && TREE_CODE (TREE_TYPE (TREE_TYPE (val))) != METHOD_TYPE)
- {
- t = val;
- STRIP_NOPS (t);
- if (TREE_CODE (t) == ADDR_EXPR)
- {
- tree a = TREE_OPERAND (t, 0);
- STRIP_NOPS (a);
- if (TREE_CODE (a) == STRING_CST)
- {
- cp_error ("string literal %E is not a valid template argument", a);
- error ("because it is the address of an object with static linkage");
- val = error_mark_node;
- }
- else if (TREE_CODE (a) != VAR_DECL
- && TREE_CODE (a) != FUNCTION_DECL)
- goto bad;
- else if (! TREE_PUBLIC (a))
- {
- cp_error ("address of non-extern `%E' cannot be used as template argument", a);
- val = error_mark_node;
- }
- }
- else
- {
- bad:
- cp_error ("`%E' is not a valid template argument", t);
- error ("it must be %s%s with external linkage",
- TREE_CODE (TREE_TYPE (val)) == POINTER_TYPE
- ? "a pointer to " : "",
- TREE_CODE (TREE_TYPE (TREE_TYPE (val))) == FUNCTION_TYPE
- ? "a function" : "an object");
- val = error_mark_node;
- }
- }
+ if (val == NULL_TREE)
+ val = error_mark_node;
+ else if (val == error_mark_node && complain)
+ cp_error ("could not convert template argument `%E' to `%T'",
+ arg, t);
}
if (val == error_mark_node)
@@ -1192,9 +1848,10 @@ comp_template_args (oldargs, newargs)
for the instantiation. */
static char *
-mangle_class_name_for_template (name, parms, arglist)
+mangle_class_name_for_template (name, parms, arglist, ctx)
char *name;
tree parms, arglist;
+ tree ctx;
{
static struct obstack scratch_obstack;
static char *scratch_firstobj;
@@ -1219,6 +1876,12 @@ mangle_class_name_for_template (name, parms, arglist)
#define cat(s) obstack_grow (&scratch_obstack, (s), strlen (s))
#endif
+ if (ctx)
+ {
+ char* s = fndecl_as_string(ctx, 0);
+ cat (s);
+ cat ("::");
+ }
cat (name);
ccat ('<');
nparms = TREE_VEC_LENGTH (parms);
@@ -1284,7 +1947,9 @@ classtype_mangled_name (t)
char *mangled_name = mangle_class_name_for_template
(IDENTIFIER_POINTER (name),
DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (t)),
- CLASSTYPE_TI_ARGS (t));
+ CLASSTYPE_TI_ARGS (t),
+ (DECL_CONTEXT (t) && TREE_CODE (t) == FUNCTION_DECL) ?
+ DECL_CONTEXT (t) : NULL_TREE);
tree id = get_identifier (mangled_name);
IDENTIFIER_TEMPLATE (id) = name;
return id;
@@ -1346,12 +2011,17 @@ lookup_template_function (fns, arglist)
to keep it from being reclaimed when the decl storage is reclaimed.
IN_DECL, if non-NULL, is the template declaration we are trying to
- instantiate. */
+ instantiate.
+
+ If the template class is really a local class in a template
+ function, then the FUNCTION_CONTEXT is the function in which it is
+ being instantiated. */
tree
-lookup_template_class (d1, arglist, in_decl)
+lookup_template_class (d1, arglist, in_decl, function_context)
tree d1, arglist;
tree in_decl;
+ tree function_context;
{
tree template, parmlist;
char *mangled_name;
@@ -1394,7 +2064,8 @@ lookup_template_class (d1, arglist, in_decl)
{
parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
- arglist = coerce_template_parms (parmlist, arglist, template);
+ arglist = coerce_template_parms (parmlist, arglist, template,
+ 1, 1);
if (arglist == error_mark_node)
return error_mark_node;
if (uses_template_parms (arglist))
@@ -1425,18 +2096,35 @@ lookup_template_class (d1, arglist, in_decl)
}
mangled_name = mangle_class_name_for_template (IDENTIFIER_POINTER (d1),
- parmlist, arglist);
+ parmlist,
+ arglist,
+ function_context);
id = get_identifier (mangled_name);
IDENTIFIER_TEMPLATE (id) = d1;
maybe_push_to_top_level (uses_template_parms (arglist));
t = xref_tag_from_type (TREE_TYPE (template), id, 1);
+
+ if (function_context != NULL_TREE)
+ {
+ /* Set up the context for the type_decl correctly. Note
+ that we must clear DECL_ASSEMBLER_NAME to fool
+ build_overload_name into creating a new name. */
+ tree type_decl = TYPE_STUB_DECL (t);
+
+ TYPE_CONTEXT (t) = function_context;
+ DECL_CONTEXT (type_decl) = function_context;
+ DECL_ASSEMBLER_NAME (type_decl) = DECL_NAME (type_decl);
+ DECL_ASSEMBLER_NAME (type_decl) =
+ get_identifier (build_overload_name (t, 1, 1));
+ }
+
pop_from_top_level ();
}
else
{
tree ctx = lookup_template_class (TYPE_CONTEXT (TREE_TYPE (template)),
- arglist, in_decl);
+ arglist, in_decl, NULL_TREE);
id = d1;
arglist = CLASSTYPE_TI_ARGS (ctx);
@@ -2114,7 +2802,15 @@ tsubst (t, args, nargs, in_decl)
if (uses_template_parms (t))
{
tree argvec = tsubst (CLASSTYPE_TI_ARGS (t), args, nargs, in_decl);
- tree r = lookup_template_class (t, argvec, in_decl);
+ tree context;
+ tree r;
+
+ context = (TYPE_CONTEXT (t)
+ && TREE_CODE (TYPE_CONTEXT (t)) == FUNCTION_DECL)
+ ? tsubst (TYPE_CONTEXT (t), args, nargs, in_decl) : NULL_TREE;
+
+ r = lookup_template_class (t, argvec, in_decl, context);
+
return cp_build_type_variant (r, TYPE_READONLY (t),
TYPE_VOLATILE (t));
}
@@ -2230,12 +2926,9 @@ tsubst (t, args, nargs, in_decl)
int i;
/* We might already have an instance of this template. */
- tree instances = DECL_TEMPLATE_INSTANTIATIONS (t);
- tree ctx = tsubst (DECL_CLASS_CONTEXT (t), args, nargs, in_decl);
-
- for (; instances; instances = TREE_CHAIN (instances))
- if (DECL_CLASS_CONTEXT (TREE_VALUE (instances)) == ctx)
- return TREE_VALUE (instances);
+ spec = retrieve_specialization (t, args);
+ if (spec != NULL_TREE)
+ return spec;
/* Make a new template decl. It will be similar to the
original, but will record the current template arguments.
@@ -2265,12 +2958,64 @@ tsubst (t, args, nargs, in_decl)
parms = TREE_CHAIN (parms))
TREE_CHAIN (parms) = copy_node (TREE_CHAIN (parms));
- /* Record this partial instantiation. */
- DECL_TEMPLATE_INSTANTIATIONS (t)
- = perm_tree_cons (NULL_TREE, tmpl,
- DECL_TEMPLATE_INSTANTIATIONS (t));
-
+ /* What should we do with the specializations of this member
+ template? Are they specializations of this new template,
+ or instantiations of the templates they previously were?
+ this new template? And where should their
+ DECL_TI_TEMPLATES point? */
DECL_TEMPLATE_SPECIALIZATIONS (tmpl) = NULL_TREE;
+ for (spec = DECL_TEMPLATE_SPECIALIZATIONS (t);
+ spec != NULL_TREE;
+ spec = TREE_CHAIN (spec))
+ {
+ /* It helps to consider example here. Consider:
+
+ template <class T>
+ struct S {
+ template <class U>
+ void f(U u);
+
+ template <>
+ void f(T* t) {}
+ };
+
+ Now, for example, we are instantiating S<int>::f(U u).
+ We want to make a template:
+
+ template <class U>
+ void S<int>::f(U);
+
+ It will have a specialization, for the case U = int*, of
+ the form:
+
+ template <>
+ void S<int>::f<int*>(int*);
+
+ This specialization will be an instantiation of
+ the specialization given in the declaration of S, with
+ argument list int*. */
+
+ tree fn = TREE_VALUE (spec);
+ tree spec_args;
+ tree new_fn;
+
+ if (!DECL_TEMPLATE_SPECIALIZATION (fn))
+ /* Instantiations are on the same list, but they're of
+ no concern to us. */
+ continue;
+
+ spec_args = tsubst (DECL_TI_ARGS (fn), args, nargs,
+ in_decl);
+ new_fn = tsubst (DECL_RESULT (fn), args, nargs,
+ in_decl);
+ DECL_TEMPLATE_SPECIALIZATIONS (tmpl) =
+ perm_tree_cons (spec_args, new_fn,
+ DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
+ }
+
+ /* Record this partial instantiation. */
+ register_specialization (tmpl, t, args);
+
return tmpl;
}
@@ -2302,13 +3047,10 @@ tsubst (t, args, nargs, in_decl)
if (DECL_TEMPLATE_INFO (t) != NULL_TREE)
{
tree tmpl = DECL_TI_TEMPLATE (t);
- tree decls = DECL_TEMPLATE_INSTANTIATIONS (tmpl);
+ tree spec = retrieve_specialization (tmpl, args);
- for (; decls; decls = TREE_CHAIN (decls))
- if (TREE_TYPE (TREE_VALUE (decls)) == type
- && DECL_CLASS_CONTEXT (TREE_VALUE (decls)) == ctx
- && comp_template_args (TREE_PURPOSE (decls), args))
- return TREE_VALUE (decls);
+ if (spec)
+ return spec;
}
/* We do NOT check for matching decls pushed separately at this
@@ -2390,16 +3132,46 @@ tsubst (t, args, nargs, in_decl)
we re-use the parms from the original template, which
have level 2. When this is fixed we can remove the
add_to_template_args from instantiate_template. */
- tree tparms = DECL_TEMPLATE_PARMS (tmpl);
-
- while (tparms && TREE_CHAIN (tparms) != NULL_TREE)
- tparms = TREE_CHAIN (tparms);
-
+ tree tparms;
+ tree targs;
+
+ if (!DECL_TEMPLATE_SPECIALIZATION (tmpl))
+ {
+ tparms = DECL_TEMPLATE_PARMS (tmpl);
+
+ while (tparms && TREE_CHAIN (tparms) != NULL_TREE)
+ tparms = TREE_CHAIN (tparms);
+
+ targs =
+ (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC
+ ? TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1)
+ : args);
+ }
+ else
+ {
+ /* If the template is a specialization, then it is
+ a member template specialization. We have
+ something like:
+
+ template <class T> struct S {
+ template <int i> void f();
+ template <> void f<7>();
+ };
+
+ and now we are forming S<double>::f<7>.
+ Therefore, the template parameters of interest
+ are those that are specialized by the template
+ (i.e., the int), not those we are using to
+ instantiate the template, i.e. the double. */
+ tparms = DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (tmpl));
+ targs = DECL_TI_ARGS (tmpl);
+ }
+
my_friendly_assert (tparms != NULL_TREE
&& TREE_CODE (tparms) == TREE_LIST,
0);
tparms = TREE_VALUE (tparms);
-
+
arg_types = TYPE_ARG_TYPES (TREE_TYPE (tmpl));
if (member && TREE_CODE (type) == FUNCTION_TYPE)
arg_types = hash_tree_chain
@@ -2410,11 +3182,7 @@ tsubst (t, args, nargs, in_decl)
= build_template_decl_overload
(DECL_NAME (r), arg_types,
TREE_TYPE (TREE_TYPE (tmpl)),
- tparms,
- TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC
- ? TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1) :
- args,
- member);
+ tparms, targs, member);
}
}
DECL_RTL (r) = 0;
@@ -2426,7 +3194,7 @@ tsubst (t, args, nargs, in_decl)
DECL_INITIAL (r) = NULL_TREE;
TREE_STATIC (r) = 0;
- TREE_PUBLIC (r) = 1;
+ TREE_PUBLIC (r) = TREE_PUBLIC (t);
DECL_EXTERNAL (r) = 1;
DECL_INTERFACE_KNOWN (r) = 0;
DECL_DEFER_OUTPUT (r) = 0;
@@ -2471,22 +3239,32 @@ tsubst (t, args, nargs, in_decl)
if (DECL_TEMPLATE_INFO (t) != NULL_TREE)
{
tree tmpl = DECL_TI_TEMPLATE (t);
- tree *declsp = &DECL_TEMPLATE_INSTANTIATIONS (tmpl);
tree argvec = tsubst (DECL_TI_ARGS (t), args, nargs, in_decl);
if (DECL_TEMPLATE_INFO (tmpl) && DECL_TI_ARGS (tmpl))
- argvec = add_to_template_args (DECL_TI_ARGS (tmpl), argvec);
+ {
+ if (!DECL_TEMPLATE_SPECIALIZATION (tmpl))
+ argvec = add_to_template_args (DECL_TI_ARGS (tmpl), argvec);
+ else
+ /* In this case, we are instantiating a
+ specialization. The innermost template args are
+ already given by the specialization. */
+ argvec = add_to_template_args (argvec, DECL_TI_ARGS (tmpl));
+ }
DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
- *declsp = perm_tree_cons (argvec, r, *declsp);
/* If we have a preexisting version of this function, don't expand
the template version, use the other instead. */
- if (TREE_STATIC (r) || DECL_TEMPLATE_SPECIALIZATION (r))
+ if (TREE_STATIC (r) ||
+ (DECL_TEMPLATE_SPECIALIZATION (r) &&
+ /* FIXME: Explain this condition. */
+ !DECL_TEMPLATE_SPECIALIZATION (tmpl)))
SET_DECL_TEMPLATE_SPECIALIZATION (r);
else
SET_DECL_IMPLICIT_INSTANTIATION (r);
+ register_specialization (r, tmpl, argvec);
}
/* Like grokfndecl. If we don't do this, pushdecl will mess up our
@@ -3469,14 +4247,11 @@ instantiate_template (tmpl, targ_ptr)
if (DECL_FUNCTION_TEMPLATE_P (tmpl))
{
- tree specs;
+ /* Check to see if we already have this specialization. */
+ tree spec = retrieve_specialization (tmpl, targ_ptr);
- /* Check to see if there is a matching specialization. */
- for (specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
- specs != NULL_TREE;
- specs = TREE_CHAIN (specs))
- if (comp_template_args (TREE_PURPOSE (specs), targ_ptr))
- return TREE_VALUE (specs);
+ if (spec != NULL_TREE)
+ return spec;
}
push_obstacks (&permanent_obstack, &permanent_obstack);
@@ -3605,22 +4380,38 @@ type_unification (tparms, targs, parms, args, targs_in, nsubsts,
int *nsubsts, strict, allow_incomplete;
{
int ntparms = TREE_VEC_LENGTH (tparms);
- tree t;
+ tree arg;
+ tree parm;
int i;
int r;
bzero ((char *) targs, sizeof (tree) * ntparms);
- /* Insert any explicit template arguments. They are encoded as the
- operands of NOP_EXPRs so that unify can tell that they are
- explicit arguments. */
- for (i = 0, t = targs_in; t != NULL_TREE; t = TREE_CHAIN (t), ++i)
- targs[i] = build1 (NOP_EXPR, NULL_TREE, TREE_VALUE (t));
+ if (targs_in != NULL_TREE)
+ {
+ tree arg_vec;
+ arg_vec = coerce_template_parms (tparms, targs_in, NULL_TREE, 0,
+ 0);
+
+ if (arg_vec == error_mark_node)
+ return 1;
+ for (i = 0;
+ i < TREE_VEC_LENGTH (arg_vec)
+ && TREE_VEC_ELT (arg_vec, i) != NULL_TREE;
+ ++i)
+ /* Insert the template argument. It is encoded as the operands
+ of NOP_EXPRs so that unify can tell that it is an explicit
+ arguments. */
+ targs[i] = build1 (NOP_EXPR, NULL_TREE, TREE_VEC_ELT (arg_vec, i));
+ }
+
r = type_unification_real (tparms, targs, parms, args, nsubsts, 0,
strict, allow_incomplete);
- for (i = 0, t = targs_in; t != NULL_TREE; t = TREE_CHAIN (t), ++i)
+ for (i = 0, arg = targs_in;
+ arg != NULL_TREE;
+ arg = TREE_CHAIN (arg), ++i)
if (TREE_CODE (targs[i]) == NOP_EXPR)
targs[i] = TREE_OPERAND (targs[i], 0);
@@ -4032,7 +4823,11 @@ mark_decl_instantiated (result, extern_p)
{
if (DECL_TEMPLATE_INSTANTIATION (result))
SET_DECL_EXPLICIT_INSTANTIATION (result);
- TREE_PUBLIC (result) = 1;
+
+ if (TREE_CODE (result) != FUNCTION_DECL)
+ /* The TREE_PUBLIC flag for function declarations will have been
+ set correctly by tsubst. */
+ TREE_PUBLIC (result) = 1;
if (! extern_p)
{
@@ -4041,7 +4836,7 @@ mark_decl_instantiated (result, extern_p)
/* For WIN32 we also want to put explicit instantiations in
linkonce sections. */
- if (supports_one_only () && ! SUPPORTS_WEAK)
+ if (supports_one_only () && ! SUPPORTS_WEAK && TREE_PUBLIC (result))
make_decl_one_only (result);
}
else if (TREE_CODE (result) == FUNCTION_DECL)
@@ -4290,11 +5085,12 @@ do_decl_instantiation (declspecs, declarator, storage)
}
else if (DECL_FUNCTION_MEMBER_P (decl))
{
- if (DECL_TEMPLATE_INSTANTIATION (decl))
+ if (DECL_TEMPLATE_INSTANTIATION (decl) && DECL_RTL (decl))
result = decl;
else if (name = DECL_ASSEMBLER_NAME (decl),
fn = IDENTIFIER_GLOBAL_VALUE (name),
- fn && DECL_TEMPLATE_INSTANTIATION (fn))
+ fn && DECL_TEMPLATE_INSTANTIATION (fn)
+ && DECL_RTL (fn))
result = fn;
else
{
@@ -4517,14 +5313,11 @@ instantiate_decl (d)
if (TREE_CODE (d) == FUNCTION_DECL)
{
- tree specs;
-
- /* Check to see if there is a matching specialization. */
- for (specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
- specs != NULL_TREE;
- specs = TREE_CHAIN (specs))
- if (comp_template_args (TREE_PURPOSE (specs), args))
- return TREE_VALUE (specs);
+ tree spec = retrieve_specialization (tmpl, args);
+
+ if (spec != NULL_TREE
+ && DECL_TEMPLATE_SPECIALIZATION (spec))
+ return spec;
}
/* This needs to happen before any tsubsting. */
@@ -4727,6 +5520,24 @@ add_tree (t)
last_tree = TREE_CHAIN (last_tree) = t;
}
+
+void
+begin_tree ()
+{
+ saved_trees = tree_cons (NULL_TREE, last_tree, saved_trees);
+ last_tree = NULL_TREE;
+}
+
+
+void
+end_tree ()
+{
+ my_friendly_assert (saved_trees != NULL_TREE, 0);
+
+ last_tree = TREE_VALUE (saved_trees);
+ saved_trees = TREE_CHAIN (saved_trees);
+}
+
/* D is an undefined function declaration in the presence of templates with
the same name, listed in FNS. If one of them can produce D as an
instantiation, remember this so we can instantiate it at EOF if D has
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 6b8c54e..365ee4d 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1464,7 +1464,11 @@ mapcar (t, func)
case VAR_DECL:
case FUNCTION_DECL:
case CONST_DECL:
- break;
+ /* Rather than aborting, return error_mark_node. This allows us
+ to report a sensible error message on code like this:
+
+ void g() { int i; f<i>(7); } */
+ return error_mark_node;
case PARM_DECL:
{
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 9938355..e3c426d 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -4481,9 +4481,11 @@ build_unary_op (code, xarg, noconvert)
/* We don't require a match here; it's possible that the
context (like a cast to a particular type) will resolve
the particular choice of template. */
- fn = determine_explicit_specialization (arg, NULL_TREE,
- &targs,
- 0, 0);
+ fn = determine_specialization (arg,
+ NULL_TREE,
+ &targs,
+ 0,
+ 0);
if (fn)
{
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index e867e44..92cbcc3 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -247,6 +247,10 @@ incomplete_type_error (value, type)
error ("invalid use of member type (did you forget the `&' ?)");
return;
+ case TEMPLATE_TYPE_PARM:
+ error ("invalid use of template type parameter");
+ return;
+
default:
my_friendly_abort (108);
}