This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
An explicit template specification patch
- To: egcs at cygnus dot com
- Subject: An explicit template specification patch
- From: Kriang Lerdsuwanakij <lerdsuwa at scf-fs dot usc dot edu>
- Date: Sun, 09 Nov 1997 16:49:36 -0800
- CC: g++ at cygnus dot com
Hi,
The explicit template specification code in the recent egcs code still
misses a couple cases. Template function calls and member template
function calls inside templates are not properly handled. I found that
template arguments are discarded on my machine (i586 Linux).
Below are all the test cases that I used and the patch against g++ (I
worked with egcs 971023). The patch also contains the fix I posted
earlier in egcs list
(http://www.cygnus.com/ml/egcs/1997-Oct/1170.html). Some test cases
rely on it.
I hope the approach to the problem is correct.
Thanks
Kriang Lerdsuwanakij
===========================================================
Test Cases:
diff -Nu g++.pt.old/explicit50.C g++.pt/explicit50.C
--- g++.pt.old/explicit50.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit50.C Wed Nov 5 22:24:56 1997
@@ -0,0 +1,15 @@
+extern "C" void abort ();
+
+template <class T> int f ()
+{
+ return sizeof(T);
+}
+
+int main ()
+{
+ if (f<long> () != sizeof(long)
+ || f<char> () != sizeof(char)
+ || f<long> () != sizeof(long)
+ || f<long int> () != sizeof(long int))
+ abort ();
+}
diff -Nu g++.pt.old/explicit51.C g++.pt/explicit51.C
--- g++.pt.old/explicit51.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit51.C Wed Nov 5 22:27:14 1997
@@ -0,0 +1,18 @@
+extern "C" void abort ();
+
+template <int a> int fact ()
+{
+ return 0;
+}
+
+template <> int fact<1> ()
+{
+ return 1;
+}
+
+int main()
+{
+ if (fact<3> () != 0 || fact<1> () != 1
+ || fact<3> () != 0 || fact<1> () != 1 || fact<1+0> () != 1)
+ abort ();
+}
diff -Nu g++.pt.old/explicit52.C g++.pt/explicit52.C
--- g++.pt.old/explicit52.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit52.C Wed Nov 5 22:29:15 1997
@@ -0,0 +1,18 @@
+extern "C" void abort ();
+
+template <int a> inline int fact ()
+{
+ return a * fact<a-1> ();
+}
+
+template <> inline int fact<1> ()
+{
+ return 1;
+}
+
+int main()
+{
+ if (fact<3> () != 6 || fact<1> () != 1
+ || fact<3> () != 6 || fact<1> () != 1 || fact<1+0> () != 1)
+ abort ();
+}
diff -Nu g++.pt.old/explicit53.C g++.pt/explicit53.C
--- g++.pt.old/explicit53.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit53.C Wed Nov 5 22:31:02 1997
@@ -0,0 +1,21 @@
+extern "C" void abort ();
+
+template <int a> inline int fact ();
+template <> inline int fact<1> ();
+
+template <int a> inline int fact ()
+{
+ return a * fact<a-1> ();
+}
+
+template <> inline int fact<1> ()
+{
+ return 1;
+}
+
+int main()
+{
+ if (fact<3> () != 6 || fact<1> () != 1
+ || fact<3> () != 6 || fact<1> () != 1 || fact<1+0> () != 1)
+ abort ();
+}
diff -Nu g++.pt.old/explicit54.C g++.pt/explicit54.C
--- g++.pt.old/explicit54.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit54.C Wed Nov 5 22:33:53 1997
@@ -0,0 +1,35 @@
+extern "C" void abort ();
+
+template <int a> inline int fact2 ();
+
+template <int a> inline int fact ()
+{
+ return a * fact2<a-1> ();
+}
+
+template <> inline int fact<1> ()
+{
+ return 1;
+}
+
+template <int a> inline int fact2 ()
+{
+ return a*fact<a-1>();
+}
+
+template <> inline int fact2<1> ()
+{
+ return 1;
+}
+
+int main()
+{
+ if (fact<3> () != 6 || fact<1> () != 1
+ || fact<3> () != 6 || fact<1> () != 1 || fact<1+0> () != 1)
+ abort ();
+ if (fact2<3> () != 6 || fact2<1> () != 1
+ || fact2<3> () != 6 || fact2<1> () != 1 || fact2<1+0> () != 1)
+ abort ();
+ if (fact2<4> () != 24 || fact<4> () != 24)
+ abort ();
+}
diff -Nu g++.pt.old/explicit55.C g++.pt/explicit55.C
--- g++.pt.old/explicit55.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit55.C Wed Nov 5 22:36:10 1997
@@ -0,0 +1,14 @@
+template <class T> T* create ()
+{
+ return new T;
+}
+
+template <class T> T* create2()
+{
+ return create<T>();
+}
+
+int main()
+{
+ int *p = create2<int>();
+}
diff -Nu g++.pt.old/explicit56.C g++.pt/explicit56.C
--- g++.pt.old/explicit56.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit56.C Wed Nov 5 22:37:26 1997
@@ -0,0 +1,16 @@
+template <class T> T* create ();
+
+template <class T> T* create2()
+{
+ return create<T>();
+}
+
+template <class T> T* create ()
+{
+ return new T;
+}
+
+int main()
+{
+ int *p = create2<int>();
+}
diff -Nu g++.pt.old/explicit57.C g++.pt/explicit57.C
--- g++.pt.old/explicit57.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit57.C Wed Nov 5 22:51:44 1997
@@ -0,0 +1,42 @@
+extern "C" void abort ();
+
+int a = 0;
+
+template <class T> void f ();
+template <class T> void g ()
+{
+ if (a)
+ abort ();
+}
+
+template <> void g<char> ()
+{
+}
+
+template <class T> class C
+{
+ public:
+ void ff () { f<T> (); }
+ void gg () { g<T> (); }
+};
+
+template <class T> void f ()
+{
+ if (a)
+ abort ();
+}
+
+template <> void f<char> ()
+{
+}
+
+int main ()
+{
+ C<int> c;
+ c.ff();
+ c.gg();
+ a = 1;
+ C<char> d;
+ d.ff();
+ d.gg();
+}
diff -Nu g++.pt.old/explicit58.C g++.pt/explicit58.C
--- g++.pt.old/explicit58.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit58.C Wed Nov 5 23:28:02 1997
@@ -0,0 +1,41 @@
+extern "C" void abort ();
+
+template <class T> void f ();
+template <class T> void g ()
+{
+ abort ();
+}
+
+template <> void g<char> ()
+{
+ abort ();
+}
+
+template <class T> class C
+{
+ public:
+ template <class U> void f () {}
+ template <class U> void g () {}
+ void ff () { f<T> (); }
+ void gg () { g<T> (); }
+};
+
+template <class T> void f ()
+{
+ abort ();
+}
+
+template <> void f<char> ()
+{
+ abort ();
+}
+
+int main ()
+{
+ C<int> c;
+ c.ff();
+ c.gg();
+ C<char> d;
+ d.ff();
+ d.gg();
+}
diff -Nu g++.pt.old/explicit59.C g++.pt/explicit59.C
--- g++.pt.old/explicit59.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit59.C Wed Nov 5 22:55:15 1997
@@ -0,0 +1,41 @@
+extern "C" void abort ();
+
+template <class T> void f ();
+template <class T> void g ()
+{
+ abort ();
+}
+
+template <> void g<char> ()
+{
+ abort ();
+}
+
+template <class T> class C
+{
+ public:
+ void ff () { f<T> (); }
+ void gg () { g<T> (); }
+ template <class U> void f () {}
+ template <class U> void g () {}
+};
+
+template <class T> void f ()
+{
+ abort ();
+}
+
+template <> void f<char> ()
+{
+ abort ();
+}
+
+int main ()
+{
+ C<int> c;
+ c.ff();
+ c.gg();
+ C<char> d;
+ d.ff();
+ d.gg();
+}
diff -Nu g++.pt.old/explicit60.C g++.pt/explicit60.C
--- g++.pt.old/explicit60.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit60.C Fri Nov 7 20:03:57 1997
@@ -0,0 +1,43 @@
+extern "C" void abort ();
+
+template <class T> void f ();
+template <class T> void g ()
+{
+ abort ();
+}
+
+template <> void g<char> ()
+{
+ abort ();
+}
+
+template <class T> class C
+{
+ public:
+ void ff () { f<T> (); }
+ void gg () { g<T> (); }
+ template <class U> void f () {}
+ template <class U> void g () {}
+ template <class U> void f (int) { abort(); }
+ template <class U> void g (int) { abort(); }
+};
+
+template <class T> void f ()
+{
+ abort ();
+}
+
+template <> void f<char> ()
+{
+ abort ();
+}
+
+int main ()
+{
+ C<int> c;
+ c.ff();
+ c.gg();
+ C<char> d;
+ d.ff();
+ d.gg();
+}
diff -Nu g++.pt.old/explicit61.C g++.pt/explicit61.C
--- g++.pt.old/explicit61.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit61.C Fri Nov 7 20:04:07 1997
@@ -0,0 +1,43 @@
+extern "C" void abort ();
+
+template <class T> void f ();
+template <class T> void g ()
+{
+ abort ();
+}
+
+template <> void g<char> ()
+{
+ abort ();
+}
+
+template <class T> class C
+{
+ public:
+ void ff () { f<T> (0); }
+ void gg () { g<T> (1); }
+ template <class U> void f () { abort(); }
+ template <class U> void g () { abort(); }
+ template <class U> void f (int) {}
+ template <class U> void g (int) {}
+};
+
+template <class T> void f ()
+{
+ abort ();
+}
+
+template <> void f<char> ()
+{
+ abort ();
+}
+
+int main ()
+{
+ C<int> c;
+ c.ff();
+ c.gg();
+ C<char> d;
+ d.ff();
+ d.gg();
+}
diff -Nu g++.pt.old/explicit62.C g++.pt/explicit62.C
--- g++.pt.old/explicit62.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit62.C Fri Nov 7 20:19:57 1997
@@ -0,0 +1,19 @@
+extern "C" void abort ();
+
+template <class T> void f ()
+{
+}
+
+
+template <class T> class C
+{
+ friend void f<char> ();
+ public:
+ void ff () { f<char> (); }
+};
+
+int main ()
+{
+ C<int> c;
+ c.ff();
+}
diff -Nu g++.pt.old/explicit63.C g++.pt/explicit63.C
--- g++.pt.old/explicit63.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit63.C Fri Nov 7 21:06:32 1997
@@ -0,0 +1,19 @@
+extern "C" void abort ();
+
+template <class T> void f ()
+{
+}
+
+
+template <class T> class C
+{
+ friend void f<T> ();
+ public:
+ void ff () { f<T> (); }
+};
+
+int main ()
+{
+ C<int> c;
+ c.ff();
+}
diff -Nu g++.pt.old/explicit64.C g++.pt/explicit64.C
--- g++.pt.old/explicit64.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit64.C Fri Nov 7 21:07:29 1997
@@ -0,0 +1,23 @@
+extern "C" void abort ();
+
+template <class T> void f ()
+{
+ abort ();
+}
+
+template <> void f<char> ()
+{
+}
+
+template <class T> class C
+{
+ friend void f<char> ();
+ public:
+ void ff () { f<char> (); }
+};
+
+int main ()
+{
+ C<int> c;
+ c.ff();
+}
diff -Nu g++.pt.old/explicit65.C g++.pt/explicit65.C
--- g++.pt.old/explicit65.C Wed Dec 31 16:00:00 1969
+++ g++.pt/explicit65.C Sun Nov 9 00:52:37 1997
@@ -0,0 +1,33 @@
+extern "C" void abort ();
+
+template <class T> void f ()
+{
+ abort ();
+}
+
+template <> void f<char> ()
+{
+ abort ();
+}
+
+template <class T> void f (int)
+{
+ abort ();
+}
+
+template <> void f<char> (int)
+{
+}
+
+template <class T> class C
+{
+ friend void f<char> (int);
+ public:
+ void ff () { f<char> (0); }
+};
+
+int main ()
+{
+ C<int> c;
+ c.ff();
+}
================================================================
* pt.c (tsubst_copy): Handle explicit template arguments in
function calls.
* typeck.c (build_x_function_call): Likewise
* decl2.c (build_expr_from_tree): Lookup function name if it
hasn't been done.
* pt.c (tsubst): Instantiate template functions properly when
template parameter does not appear in function arguments and return
type.
(comp_template_args): Handle member templates required by tsubst.
diff -u save/decl2.c cp/decl2.c
--- save/decl2.c Tue Nov 4 02:04:17 1997
+++ cp/decl2.c Fri Nov 7 20:06:04 1997
@@ -3571,6 +3571,10 @@
tree name = TREE_OPERAND (t, 0);
if (! really_overloaded_fn (name))
name = build_expr_from_tree (name);
+ else if (TREE_CODE (name) == TEMPLATE_ID_EXPR
+ && TREE_CODE (TREE_OPERAND (name, 0)) == LOOKUP_EXPR)
+ /* Lookup function name */
+ TREE_OPERAND (name, 0) = build_expr_from_tree (TREE_OPERAND (name,
0));
return build_x_function_call
(name, build_expr_from_tree (TREE_OPERAND (t, 1)),
current_class_ref);
diff -u save/pt.c cp/pt.c
--- save/pt.c Sun Oct 26 00:11:51 1997
+++ cp/pt.c Fri Nov 7 20:05:53 1997
@@ -1157,7 +1157,13 @@
continue;
if (TREE_CODE (nt) != TREE_CODE (ot))
return 0;
- if (TREE_CODE_CLASS (TREE_CODE (ot)) == 't')
+ if (TREE_CODE (nt) == TREE_VEC)
+ {
+ /* For member templates */
+ if (comp_template_args (nt, ot))
+ continue;
+ }
+ else if (TREE_CODE_CLASS (TREE_CODE (ot)) == 't')
{
if (comptypes (ot, nt, 1))
continue;
@@ -2246,14 +2252,6 @@
type = tsubst (type, args, nargs, in_decl);
}
- if (type == TREE_TYPE (t)
- && (! member || ctx == DECL_CLASS_CONTEXT (t)))
- {
- t = copy_node (t);
- copy_lang_decl (t);
- return t;
- }
-
/* Do we already have this instantiation? */
if (DECL_TEMPLATE_INFO (t) != NULL_TREE)
{
@@ -2262,7 +2260,8 @@
for (; decls; decls = TREE_CHAIN (decls))
if (TREE_TYPE (TREE_VALUE (decls)) == type
- && DECL_CLASS_CONTEXT (TREE_VALUE (decls)) == ctx)
+ && DECL_CLASS_CONTEXT (TREE_VALUE (decls)) == ctx
+ && comp_template_args (TREE_PURPOSE (decls), args))
return TREE_VALUE (decls);
}
@@ -2965,7 +2964,11 @@
case CALL_EXPR:
{
tree fn = TREE_OPERAND (t, 0);
- if (really_overloaded_fn (fn))
+ if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
+ /* Keep the TEMPLATE_ID_EXPR node for build_new_function_call
+ later */
+ fn = tsubst_copy (fn, args, nargs, in_decl);
+ else if (really_overloaded_fn (fn))
fn = tsubst_copy (TREE_VALUE (fn), args, nargs, in_decl);
else
fn = tsubst_copy (fn, args, nargs, in_decl);
@@ -3028,10 +3031,33 @@
case TEMPLATE_ID_EXPR:
{
- tree r = lookup_template_function
- (tsubst_copy (TREE_OPERAND (t, 0), args, nargs, in_decl),
- tsubst_copy (TREE_OPERAND (t, 1), args, nargs, in_decl));
- return r;
+ /* Substituted template arguments */
+ tree targs = tsubst_copy (TREE_OPERAND (t, 1), args, nargs, in_decl);
+ tree chain = targs;
+ while (chain)
+ {
+ if (TREE_CODE_CLASS (TREE_CODE (TREE_VALUE (chain))) != 't'
+ && !uses_template_parms (TREE_VALUE (chain)))
+ {
+ /* Sometimes, one of the args was an expression involving a
+ template constant parameter, like N - 1. Now that we've
+ tsubst'd, we might have something like 2 - 1. This will
+ confuse lookup_template_class, so we do constant folding
+ here. We have to unset processing_template_decl, to
+ fool build_expr_from_tree() into building an actual
+ tree. */
+
+ int saved_processing_template_decl = processing_template_decl;
+ processing_template_decl = 0;
+ TREE_VALUE (chain) = fold
+ (build_expr_from_tree (TREE_VALUE (chain)));
+ processing_template_decl = saved_processing_template_decl;
+ }
+ chain = TREE_CHAIN (chain);
+ }
+
+ return lookup_template_function
+ (tsubst_copy (TREE_OPERAND (t, 0), args, nargs, in_decl), targs);
}
case TREE_LIST:
diff -u save/typeck.c cp/typeck.c
--- save/typeck.c Fri Nov 7 18:53:23 1997
+++ cp/typeck.c Sun Nov 9 01:09:11 1997
@@ -2266,6 +2266,7 @@
tree function, params, decl;
{
tree type;
+ tree explicit_targs = NULL_TREE;
int is_method;
if (function == error_mark_node)
@@ -2274,6 +2275,13 @@
if (processing_template_decl)
return build_min_nt (CALL_EXPR, function, params, NULL_TREE);
+ /* Save explicit template arguments if found */
+ if (TREE_CODE (function) == TEMPLATE_ID_EXPR)
+ {
+ explicit_targs = TREE_OPERAND (function, 1);
+ function = TREE_OPERAND (function, 0);
+ }
+
type = TREE_TYPE (function);
if (TREE_CODE (type) == OFFSET_TYPE
@@ -2368,6 +2376,9 @@
decl = build_indirect_ref (decl, NULL_PTR);
}
+ /* Put back explicit template arguments if exist*/
+ if (explicit_targs != NULL_TREE)
+ function = lookup_template_function (function, explicit_targs);
return build_method_call (decl, function, params,
NULL_TREE, LOOKUP_NORMAL);
}
@@ -2396,7 +2407,12 @@
tree val = TREE_VALUE (function);
if (flag_ansi_overloading)
- return build_new_function_call (function, params, NULL_TREE);
+ {
+ /* Put back explicit template arguments if exist*/
+ if (explicit_targs != NULL_TREE)
+ function = lookup_template_function (function, explicit_targs);
+ return build_new_function_call (function, params, NULL_TREE);
+ }
if (TREE_CODE (val) == TEMPLATE_DECL)
return build_overload_call_real