summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMark Mitchell <mark@markmitchell.com>1998-05-25 10:28:16 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1998-05-25 10:28:16 +0000
commit67ffc8124f94d059eba8bcda0d1cfa070bc4eae0 (patch)
tree585de9a1e35f1808041f780e2175364e45a326dd /gcc
parentc21f27a76270b3e7d2e23679524d2f39b506cef4 (diff)
downloadgcc-67ffc8124f94d059eba8bcda0d1cfa070bc4eae0.tar.gz
decl2.c (build_anon_union_vars): Don't crash on empty sub-unions.
1998-05-25 Mark Mitchell <mark@markmitchell.com> * decl2.c (build_anon_union_vars): Don't crash on empty sub-unions. * cp-tree.h (processing_template_parmlist): Declare. * decl.c (pushtag): Don't call push_template_decl when we shouldn't. * pt.c (processing_template_parmlist): New variable. (TMPL_ARGS_HAVE_MULTIPLE_LEVELS): New macro. (complete_template_args): Use it. (add_to_template_args): Likewise. (innermost_args): Likewise. (tsubst): Likewise. (begin_template_parm_list): Use processing_template_parmlist. (end_template_parm_list): Likewise. * cp-tree.h (ANON_UNION_TYPE_P): New macro. * decl.c (grokdeclarator): Use it. * decl2.c (grok_x_components): Likewise. * init.c (initializing_context): Likewise. * method.c (do_build_copy_constructor): Likewise. (do_build_assign_ref): Likewise. * search.c (compute_access): Likewise. * typeck.c (build_component_ref): Likewise. * decl.c (grokdeclarator): Don't give a cv-qualified version of an unnamed type a typedef name "for linkage purposes". * pt.c (lookup_template_class): Don't look at IDENTIFIER_CLASS_VALUE when there's no current_class_type. * method.c (build_overload_int): Handle error cases gracefully. * pt.c (instantiate_decl): Handle static member variables correctly. * pt.c (tsubst): Use the tsubst'd type when producing new TEMPLATE_PARM_INDEX nodes. From-SVN: r20045
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog39
-rw-r--r--gcc/cp/cp-tree.h6
-rw-r--r--gcc/cp/decl.c16
-rw-r--r--gcc/cp/decl2.c12
-rw-r--r--gcc/cp/init.c2
-rw-r--r--gcc/cp/method.c21
-rw-r--r--gcc/cp/pt.c63
-rw-r--r--gcc/cp/search.c3
-rw-r--r--gcc/cp/typeck.c6
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/typedef1.C13
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/crash5.C12
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/memtemp75.C25
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/spec18.C30
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/static2.C21
14 files changed, 216 insertions, 53 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b54b78fadd5..23b61d0e491 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,42 @@
+1998-05-25 Mark Mitchell <mark@markmitchell.com>
+
+ * decl2.c (build_anon_union_vars): Don't crash on empty sub-unions.
+
+ * cp-tree.h (processing_template_parmlist): Declare.
+ * decl.c (pushtag): Don't call push_template_decl when we
+ shouldn't.
+ * pt.c (processing_template_parmlist): New variable.
+ (TMPL_ARGS_HAVE_MULTIPLE_LEVELS): New macro.
+ (complete_template_args): Use it.
+ (add_to_template_args): Likewise.
+ (innermost_args): Likewise.
+ (tsubst): Likewise.
+ (begin_template_parm_list): Use processing_template_parmlist.
+ (end_template_parm_list): Likewise.
+
+ * cp-tree.h (ANON_UNION_TYPE_P): New macro.
+ * decl.c (grokdeclarator): Use it.
+ * decl2.c (grok_x_components): Likewise.
+ * init.c (initializing_context): Likewise.
+ * method.c (do_build_copy_constructor): Likewise.
+ (do_build_assign_ref): Likewise.
+ * search.c (compute_access): Likewise.
+ * typeck.c (build_component_ref): Likewise.
+
+ * decl.c (grokdeclarator): Don't give a cv-qualified version of an
+ unnamed type a typedef name "for linkage purposes".
+
+ * pt.c (lookup_template_class): Don't look at
+ IDENTIFIER_CLASS_VALUE when there's no current_class_type.
+
+ * method.c (build_overload_int): Handle error cases gracefully.
+
+ * pt.c (instantiate_decl): Handle static member variables
+ correctly.
+
+ * pt.c (tsubst): Use the tsubst'd type when producing new
+ TEMPLATE_PARM_INDEX nodes.
+
1998-05-24 Mark Mitchell <mark@markmitchell.com>
* tree.c (cp_tree_equal): Handle pointers to member functions.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f12a82eb253..f65fbd437ef 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1452,6 +1452,11 @@ extern int flag_new_for_scope;
#define ANON_UNION_P(NODE) (DECL_NAME (NODE) == 0)
+/* Nonzero if TYPE is an anonymous union type. */
+#define ANON_UNION_TYPE_P(TYPE) \
+ (TREE_CODE (TYPE) == UNION_TYPE \
+ && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TYPE)))
+
#define UNKNOWN_TYPE LANG_TYPE
/* Define fields and accessors for nodes representing declared names. */
@@ -2644,6 +2649,7 @@ extern int comp_template_args PROTO((tree, tree));
extern int processing_specialization;
extern int processing_explicit_instantiation;
+extern int processing_template_parmlist;
/* in repo.c */
extern void repo_template_used PROTO((tree));
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 1fb79382e6f..67604d7cd08 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2291,9 +2291,15 @@ pushtag (name, type, globalize)
friend class S2;
};
- declares S2 to be at global scope. */
- || (processing_template_decl >
- template_class_depth (current_class_type))))
+ declares S2 to be at global scope. We must be
+ careful, however, of the following case:
+
+ template <class A*> struct S;
+
+ which declares a non-template class `A'. */
+ || (!processing_template_parmlist
+ && (processing_template_decl >
+ template_class_depth (current_class_type)))))
{
d = push_template_decl_real (d, globalize);
/* If the current binding level is the binding level for
@@ -8750,8 +8756,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
/* Static anonymous unions are dealt with here. */
if (staticp && decl_context == TYPENAME
&& TREE_CODE (declspecs) == TREE_LIST
- && TREE_CODE (TREE_VALUE (declspecs)) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TREE_VALUE (declspecs))))
+ && ANON_UNION_TYPE_P (TREE_VALUE (declspecs)))
decl_context = FIELD;
/* Give error if `const,' `volatile,' `inline,' `friend,' or `virtual'
@@ -9659,6 +9664,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
refer to it, so nothing needs know about the name change.
The TYPE_NAME field was filled in by build_struct_xref. */
if (type != error_mark_node
+ && !TYPE_READONLY (type) && !TYPE_VOLATILE (type)
&& TYPE_NAME (type)
&& TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& ANON_AGGRNAME_P (TYPE_IDENTIFIER (type)))
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 2ad9bbe5f22..e4c14abb30a 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -865,8 +865,7 @@ grok_x_components (specs, components)
{
case VAR_DECL:
/* Static anonymous unions come out as VAR_DECLs. */
- if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TREE_TYPE (t))))
+ if (ANON_UNION_TYPE_P (TREE_TYPE (t)))
return t;
/* We return SPECS here, because in the parser it was ending
@@ -904,8 +903,7 @@ grok_x_components (specs, components)
tcode = enum_type_node;
t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0);
- if (TREE_CODE (t) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
+ if (ANON_UNION_TYPE_P (t))
{
/* See also shadow_tag. */
@@ -2176,7 +2174,11 @@ build_anon_union_vars (anon_decl, elems, static_p, external_p)
if (DECL_NAME (field) == NULL_TREE
&& TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
- decl = build_anon_union_vars (field, elems, static_p, external_p);
+ {
+ decl = build_anon_union_vars (field, elems, static_p, external_p);
+ if (!decl)
+ continue;
+ }
else
{
decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field));
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 0d0fa8c8023..c706a04ba31 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -866,7 +866,7 @@ initializing_context (field)
/* Anonymous union members can be initialized in the first enclosing
non-anonymous union context. */
- while (t && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
+ while (t && ANON_UNION_TYPE_P (t))
t = TYPE_CONTEXT (t);
return t;
}
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 5cf4133166d..054cfddb9f3 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -515,7 +515,13 @@ build_overload_int (value, in_template)
id = ansi_opname [(int) TREE_CODE (value)];
my_friendly_assert (id != NULL_TREE, 0);
name = IDENTIFIER_POINTER (id);
- my_friendly_assert (name[0] == '_' && name[1] == '_', 0);
+ if (name[0] != '_' || name[1] != '_')
+ /* On some erroneous inputs, we can get here with VALUE a
+ LOOKUP_EXPR. In that case, the NAME will be the
+ identifier for "<invalid operator>". We must survive
+ this routine in order to issue a sensible error
+ message, so we fall through to the case below. */
+ goto bad_value;
for (i = 0; i < operands; ++i)
{
@@ -553,6 +559,7 @@ build_overload_int (value, in_template)
This should cause assembler errors we'll notice. */
static int n;
+ bad_value:
sprintf (digit_buffer, " *%d", n++);
OB_PUTCP (digit_buffer);
}
@@ -2180,8 +2187,7 @@ do_build_copy_constructor (fndecl)
continue;
}
else if ((t = TREE_TYPE (field)) != NULL_TREE
- && TREE_CODE (t) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+ && ANON_UNION_TYPE_P (t)
&& TYPE_FIELDS (t) != NULL_TREE)
{
do
@@ -2190,8 +2196,7 @@ do_build_copy_constructor (fndecl)
field = largest_union_member (t);
}
while ((t = TREE_TYPE (field)) != NULL_TREE
- && TREE_CODE (t) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+ && ANON_UNION_TYPE_P (t)
&& TYPE_FIELDS (t) != NULL_TREE);
}
else
@@ -2290,8 +2295,7 @@ do_build_assign_ref (fndecl)
continue;
}
else if ((t = TREE_TYPE (field)) != NULL_TREE
- && TREE_CODE (t) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+ && ANON_UNION_TYPE_P (t)
&& TYPE_FIELDS (t) != NULL_TREE)
{
do
@@ -2301,8 +2305,7 @@ do_build_assign_ref (fndecl)
field = largest_union_member (t);
}
while ((t = TREE_TYPE (field)) != NULL_TREE
- && TREE_CODE (t) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+ && ANON_UNION_TYPE_P (t)
&& TYPE_FIELDS (t) != NULL_TREE);
}
else
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d148e0dd93a..dd7060ad43f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -63,6 +63,7 @@ int minimal_parse_mode;
int processing_specialization;
int processing_explicit_instantiation;
+int processing_template_parmlist;
static int template_header_count;
static tree saved_trees;
@@ -115,6 +116,14 @@ static int check_cv_quals_for_unify PROTO((int, tree, tree));
static tree tsubst_template_arg_vector PROTO((tree, tree));
static void regenerate_decl_from_template PROTO((tree, tree));
+/* Nonzero if ARGVEC contains multiple levels of template arguments. */
+#define TMPL_ARGS_HAVE_MULTIPLE_LEVELS(NODE) \
+ (NODE != NULL_TREE \
+ && TREE_CODE (NODE) == TREE_VEC \
+ && TREE_VEC_LENGTH (NODE) > 0 \
+ && TREE_VEC_ELT (NODE, 0) != NULL_TREE \
+ && TREE_CODE (TREE_VEC_ELT (NODE, 0)) == TREE_VEC)
+
/* Do any processing required when DECL (a member template declaration
using TEMPLATE_PARAMETERS as its innermost parameter list) is
finished. Returns the TEMPLATE_DECL corresponding to DECL, unless
@@ -388,7 +397,7 @@ complete_template_args (tmpl, extra_args, unbound_only)
my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
my_friendly_assert (TREE_CODE (extra_args) == TREE_VEC, 0);
- if (TREE_CODE (TREE_VEC_ELT (extra_args, 0)) == TREE_VEC)
+ if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (extra_args))
extra_arg_depth = TREE_VEC_LENGTH (extra_args);
else
extra_arg_depth = 1;
@@ -411,7 +420,7 @@ complete_template_args (tmpl, extra_args, unbound_only)
TEMPLATE_DECL with DECL_TEMPLATE_INFO. DECL_TI_ARGS is
all the bound template arguments. */
args = DECL_TI_ARGS (tmpl);
- if (TREE_CODE (TREE_VEC_ELT (args, 0)) != TREE_VEC)
+ if (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
depth = 1;
else
depth = TREE_VEC_LENGTH (args);
@@ -485,7 +494,7 @@ add_to_template_args (args, extra_args)
{
tree new_args;
- if (TREE_CODE (TREE_VEC_ELT (args, 0)) != TREE_VEC)
+ if (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
{
new_args = make_tree_vec (2);
TREE_VEC_ELT (new_args, 0) = args;
@@ -529,6 +538,7 @@ begin_template_parm_list ()
pushlevel (0);
declare_pseudo_global_level ();
++processing_template_decl;
+ ++processing_template_parmlist;
note_template_header (0);
}
@@ -1452,6 +1462,8 @@ end_template_parm_list (parms)
for (parm = parms, nparms = 0; parm; parm = TREE_CHAIN (parm), nparms++)
TREE_VEC_ELT (saved_parmlist, nparms) = parm;
+ --processing_template_parmlist;
+
return saved_parmlist;
}
@@ -2858,9 +2870,10 @@ lookup_template_class (d1, arglist, in_decl, context)
{
if (context)
push_decl_namespace (context);
- template =
- maybe_get_template_decl_from_type_decl
- (IDENTIFIER_CLASS_VALUE (d1));
+ if (current_class_type != NULL_TREE)
+ template =
+ maybe_get_template_decl_from_type_decl
+ (IDENTIFIER_CLASS_VALUE (d1));
if (template == NULL_TREE)
template = lookup_name_nonclass (d1);
if (context)
@@ -3993,7 +4006,7 @@ innermost_args (args, is_spec)
tree args;
int is_spec;
{
- if (args != NULL_TREE && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+ if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
return TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1 - is_spec);
return args;
}
@@ -4189,8 +4202,7 @@ tsubst (t, args, in_decl)
{
tree arg = NULL_TREE;
- if (TREE_VEC_ELT (args, 0) != NULL_TREE
- && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+ if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
{
levels = TREE_VEC_LENGTH (args);
if (level <= levels)
@@ -4275,7 +4287,7 @@ tsubst (t, args, in_decl)
break;
case TEMPLATE_PARM_INDEX:
- r = reduce_template_parm_level (t, TREE_TYPE (t), levels);
+ r = reduce_template_parm_level (t, type, levels);
break;
default:
@@ -6220,14 +6232,14 @@ unify (tparms, targs, parm, arg, strict, explicit_mask)
/* The PARM is not one we're trying to unify. Just check
to see if it matches ARG. */
return (TREE_CODE (arg) == TREE_CODE (parm)
- && cp_tree_equal (parm, arg)) ? 0 : 1;
+ && cp_tree_equal (parm, arg) > 0) ? 0 : 1;
idx = TEMPLATE_PARM_IDX (parm);
targ = TREE_VEC_ELT (targs, idx);
if (targ)
{
- int i = cp_tree_equal (targ, arg);
+ int i = (cp_tree_equal (targ, arg) > 0);
if (i == 1)
return 0;
else if (i == 0)
@@ -7082,17 +7094,6 @@ instantiate_decl (d)
lineno = DECL_SOURCE_LINE (d);
input_filename = DECL_SOURCE_FILE (d);
- /* We need to set up DECL_INITIAL regardless of pattern_defined if the
- variable is a static const initialized in the class body. */
- if (TREE_CODE (d) == VAR_DECL
- && ! DECL_INITIAL (d) && DECL_INITIAL (code_pattern))
- {
- pushclass (DECL_CONTEXT (d), 2);
- DECL_INITIAL (d) = tsubst_expr (DECL_INITIAL (code_pattern), args,
- tmpl);
- cp_finish_decl (d, DECL_INITIAL (d), NULL_TREE, 0, LOOKUP_NORMAL);
- }
-
if (pattern_defined)
{
repo_template_used (d);
@@ -7123,11 +7124,17 @@ instantiate_decl (d)
&& ! (TREE_CODE (d) == FUNCTION_DECL && DECL_INLINE (d)))
goto out;
- /* Defer all templates except inline functions used in another function. */
- if (! pattern_defined
- || (! (TREE_CODE (d) == FUNCTION_DECL && DECL_INLINE (d) && nested)
- && ! at_eof))
- {
+ if (TREE_CODE (d) == VAR_DECL
+ && DECL_INITIAL (d) == NULL_TREE
+ && DECL_INITIAL (code_pattern) != NULL_TREE)
+ /* We need to set up DECL_INITIAL regardless of pattern_defined if
+ the variable is a static const initialized in the class body. */;
+ else if (! pattern_defined
+ || (! (TREE_CODE (d) == FUNCTION_DECL && DECL_INLINE (d) && nested)
+ && ! at_eof))
+ {
+ /* Defer all templates except inline functions used in another
+ function. */
lineno = line;
input_filename = file;
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 1a779138f38..c0db0572ee5 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -969,8 +969,7 @@ compute_access (basetype_path, field)
/* Fields coming from nested anonymous unions have their DECL_CLASS_CONTEXT
slot set to the union type rather than the record type containing
the anonymous union. */
- if (context && TREE_CODE (context) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (context)))
+ if (context && ANON_UNION_TYPE_P (context))
context = TYPE_CONTEXT (context);
/* Virtual function tables are never private. But we should know that
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 135bbd1f61b..63b2adc2f3b 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2065,8 +2065,8 @@ build_component_ref (datum, component, basetype_path, protect)
{
tree context = DECL_FIELD_CONTEXT (field);
tree base = context;
- while (base != basetype && TYPE_NAME (base)
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (base)))
+ while (!comptypes (base, basetype,1) && TYPE_NAME (base)
+ && ANON_UNION_TYPE_P (base))
{
base = TYPE_CONTEXT (base);
}
@@ -2096,7 +2096,7 @@ build_component_ref (datum, component, basetype_path, protect)
basetype = base;
/* Handle things from anon unions here... */
- if (TYPE_NAME (context) && ANON_AGGRNAME_P (TYPE_IDENTIFIER (context)))
+ if (TYPE_NAME (context) && ANON_UNION_TYPE_P (context))
{
tree subfield = lookup_anon_field (basetype, context);
tree subdatum = build_component_ref (datum, subfield,
diff --git a/gcc/testsuite/g++.old-deja/g++.other/typedef1.C b/gcc/testsuite/g++.old-deja/g++.other/typedef1.C
new file mode 100644
index 00000000000..d44772932ed
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.other/typedef1.C
@@ -0,0 +1,13 @@
+// Build don't link:
+
+typedef const struct {
+ int x;
+} Test;
+
+void foo(Test);
+
+void foo(Test t)
+{
+ t.x = 0; // ERROR - assignment of read-only member
+ return;
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash5.C b/gcc/testsuite/g++.old-deja/g++.pt/crash5.C
new file mode 100644
index 00000000000..786cdf2c902
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/crash5.C
@@ -0,0 +1,12 @@
+// Build don't link:
+
+template <class T, int i>
+struct K {
+ void f();
+};
+
+template <class T>
+void
+K<T, i>::f()
+{ // ERROR - template parameters
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memtemp75.C b/gcc/testsuite/g++.old-deja/g++.pt/memtemp75.C
new file mode 100644
index 00000000000..4ff38b6c04c
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/memtemp75.C
@@ -0,0 +1,25 @@
+// Build don't link:
+
+void
+print(const int& i)
+{
+}
+
+template<class A>
+class bar
+{
+public:
+ template<void (*B)(const A& a)>
+ void doit(const A& a)
+ {
+ B(a);
+ }
+};
+
+
+int
+main()
+{
+ bar<int> b;
+ b.template doit<print>(2);
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec18.C b/gcc/testsuite/g++.old-deja/g++.pt/spec18.C
new file mode 100644
index 00000000000..d7d034d6f7f
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/spec18.C
@@ -0,0 +1,30 @@
+// Build don't link:
+
+template<class A, class B>
+void foo(const A& a, const B& b)
+{
+}
+
+template<class A, class B>
+void foo(const A& a, const int& b)
+{
+}
+
+template<class A*, class B>
+void foo(const A*& a, const B& b)
+{
+}
+
+template<>
+void foo(const int&, const double&)
+{
+}
+
+
+int
+main()
+{
+ foo("98239", 23);
+ foo(232, 1.022);
+}
+
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/static2.C b/gcc/testsuite/g++.old-deja/g++.pt/static2.C
new file mode 100644
index 00000000000..5060cfdfb9e
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/static2.C
@@ -0,0 +1,21 @@
+// Build don't link:
+
+template <class A>
+class TEST
+{
+public:
+ TEST (A) {}
+};
+
+template <class A>
+class TEST2
+{
+ static A i;
+};
+
+template <class A>
+A TEST2 <A>::i (0);
+
+TEST2 <TEST <int> > a;
+
+template class TEST2 <TEST <int> >;