This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
Patch for specializations of static members, and other problems
- To: Jason Merrill <jason at cygnus dot com>
- Subject: Patch for specializations of static members, and other problems
- From: Mark Mitchell <mmitchell at usa dot net>
- Date: Thu, 29 Jan 1998 16:51:48 -0800
- Cc: egcs-bugs at cygnus dot com, reciojm at madrid dot ecid dot cig dot mot dot com, chen at gs204 dot sp dot cs dot cmu dot edu, ingolf at mathematik dot uni-jena dot de, markj at ibmoto dot com, snyder at d0sgif dot fnal dot gov, Mark Mitchell <mmitchell at usa dot net>
- Reply-to: mmitchell at usa dot net
Jason --
Here's a patch that fixes problems reported by the folks above:
mostly compiler crashes or spurious errors, but one actual
code-generation problem with code like this:
int i;
int j = i++;
at file scope: i was not being incremented!
It's in a slightly unusual format. There are actually two patches
below: one for the cp directory, and one for the testsuite. The
reason is that I wanted to make diffs against the current state of the
repository since I wasn't sure exactly what form the stuff I'd sent
you lately had ended up in. Search for `CUT HERE' to find the
separation betwen the two patches.
--
Mark Mitchell mmitchell@usa.net
Stanford University http://www.stanford.edu
Thu Jan 29 16:19:39 1998 Mark Mitchell <mmitchell@usa.net>
* call.c (add_template_candidate_real): Pass extra parameter to
fn_type_unification.
* cp-tree.h (DECL_NONSTATIC_FUNCTION_MEMBER_P): New macro.
(revert_static_member_fn): Declare.
(fn_type_unification): Add parameter.
* decl.c (revert_static_member_fn): Remove declaration. Change
linkage from internal to external.
(lookup_name_real): Do not assume all contexts are type contexts
when considering making an implicit typename.
(cp_finish_decl): Deal with virtual functions in classes local to
template functions.
* decl2.c (finish_file): Don't forget to emit increment/decrement
expressions in initializers for file-scope variables.
* parse.y (typename_sub2): If the typename doesn't names a
template, rather than a type, issue an error message.
* pt.c (check_explicit_specialization): Handle specializations of
static member functions.
(coerce_template_parms): Handle offset references to lists of
member functions.
(fn_type_unification): Add additional parameter to deal with
static member functions.
(get_bindings): Deal with static member functions.
* search.c (note_debug_info_needed): Don't crash when handed a
type which is being defined.
* typeck.c (complete_type): Don't crash when handed NULL_TREE;
that can happen with some illegal code.
diff -c -p ./call.c /home/mitchell/projects/egcs/gcc/cp/call.c
*** ./call.c Tue Jan 27 22:53:38 1998
--- /home/mitchell/projects/egcs/gcc/cp/call.c Thu Jan 29 14:46:50 1998
*************** add_template_candidate_real (candidates,
*** 4176,4182 ****
tree fn;
i = fn_type_unification (tmpl, explicit_targs, targs, arglist,
! return_type, 0);
if (i != 0)
return candidates;
--- 4176,4182 ----
tree fn;
i = fn_type_unification (tmpl, explicit_targs, targs, arglist,
! return_type, 0, NULL_TREE);
if (i != 0)
return candidates;
diff -c -p ./cp-tree.h /home/mitchell/projects/egcs/gcc/cp/cp-tree.h
*** ./cp-tree.h Wed Jan 28 12:03:11 1998
--- /home/mitchell/projects/egcs/gcc/cp/cp-tree.h Thu Jan 29 14:46:27 1998
*************** struct lang_decl
*** 1020,1029 ****
(TREE_CODE (NODE) == VAR_DECL || TREE_CODE (NODE) == TYPE_DECL \
|| TREE_CODE (NODE) == CONST_DECL)
/* Nonzero for FUNCTION_DECL means that this decl is a member function
(static or non-static). */
#define DECL_FUNCTION_MEMBER_P(NODE) \
! (TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE || DECL_STATIC_FUNCTION_P (NODE))
/* Nonzero for FUNCTION_DECL means that this member function
has `this' as const X *const. */
--- 1020,1034 ----
(TREE_CODE (NODE) == VAR_DECL || TREE_CODE (NODE) == TYPE_DECL \
|| TREE_CODE (NODE) == CONST_DECL)
+ /* Nonzero for FUNCTION_DECL means that this decl is a non-static
+ member function. */
+ #define DECL_NONSTATIC_FUNCTION_MEMBER_P(NODE) \
+ (TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE)
+
/* Nonzero for FUNCTION_DECL means that this decl is a member function
(static or non-static). */
#define DECL_FUNCTION_MEMBER_P(NODE) \
! (DECL_NONSTATIC_FUNCTION_MEMBER_P(NODE) || DECL_STATIC_FUNCTION_P (NODE))
/* Nonzero for FUNCTION_DECL means that this member function
has `this' as const X *const. */
*************** extern int in_function_p PROTO((void))
*** 2119,2124 ****
--- 2124,2130 ----
extern void replace_defarg PROTO((tree, tree));
extern void print_other_binding_stack PROTO((struct binding_level *));
extern tree strip_attrs PROTO((tree));
+ extern void revert_static_member_fn PROTO((tree*, tree*, tree*));
/* in decl2.c */
extern int flag_assume_nonnull_objects;
*************** extern int uses_template_parms PROTO((
*** 2347,2353 ****
extern tree instantiate_class_template PROTO((tree));
extern tree instantiate_template PROTO((tree, tree));
extern void overload_template_name PROTO((tree));
! extern int fn_type_unification PROTO((tree, tree, tree, tree, tree, int));
extern int type_unification PROTO((tree, tree *, tree, tree, tree, int *, int, int));
struct tinst_level *tinst_for_decl PROTO((void));
extern void mark_decl_instantiated PROTO((tree, int));
--- 2353,2359 ----
extern tree instantiate_class_template PROTO((tree));
extern tree instantiate_template PROTO((tree, tree));
extern void overload_template_name PROTO((tree));
! extern int fn_type_unification PROTO((tree, tree, tree, tree, tree, int, tree));
extern int type_unification PROTO((tree, tree *, tree, tree, tree, int *, int, int));
struct tinst_level *tinst_for_decl PROTO((void));
extern void mark_decl_instantiated PROTO((tree, int));
diff -c -p ./decl.c /home/mitchell/projects/egcs/gcc/cp/decl.c
*** ./decl.c Wed Jan 28 12:03:11 1998
--- /home/mitchell/projects/egcs/gcc/cp/decl.c Thu Jan 29 14:32:13 1998
*************** static struct stack_level *decl_stack;
*** 136,142 ****
static tree grokparms PROTO((tree, int));
static tree lookup_nested_type PROTO((tree, tree));
static char *redeclaration_error_message PROTO((tree, tree));
- static void revert_static_member_fn PROTO((tree *, tree *, tree *));
static tree push_overloaded_decl PROTO((tree, int));
static void push_overloaded_decl_top_level PROTO((tree, int));
--- 136,141 ----
*************** lookup_name_real (name, prefer_type, non
*** 4622,4627 ****
--- 4621,4627 ----
if (processing_template_decl
&& classval && TREE_CODE (classval) == TYPE_DECL
&& DECL_CONTEXT (classval) != current_class_type
+ && hack_decl_function_context (classval) == NULL_TREE
&& uses_template_parms (DECL_CONTEXT (classval))
&& ! DECL_ARTIFICIAL (classval))
{
*************** cp_finish_decl (decl, init, asmspec_tree
*** 6495,6502 ****
{
tree stmt = DECL_VINDEX (decl);
/* If the decl is declaring a member of a local class (in a
! template function), there will be no associated stmt. */
! if (stmt != NULL_TREE)
{
DECL_VINDEX (decl) = NULL_TREE;
TREE_OPERAND (stmt, 2) = copy_to_permanent (init);
--- 6495,6504 ----
{
tree stmt = DECL_VINDEX (decl);
/* If the decl is declaring a member of a local class (in a
! template function), the DECL_VINDEX will either be NULL,
! or it will be an actual virtual function index, not a
! DECL_STMT. */
! if (stmt != NULL_TREE && TREE_CODE (stmt) == DECL_STMT)
{
DECL_VINDEX (decl) = NULL_TREE;
TREE_OPERAND (stmt, 2) = copy_to_permanent (init);
*************** finish_stmt ()
*** 13008,13014 ****
(TREE_TYPE (decl)) to ARGTYPES, as doing so will corrupt the types of
other decls. Either pass the addresses of local variables or NULL. */
! static void
revert_static_member_fn (decl, fn, argtypes)
tree *decl, *fn, *argtypes;
{
--- 13010,13016 ----
(TREE_TYPE (decl)) to ARGTYPES, as doing so will corrupt the types of
other decls. Either pass the addresses of local variables or NULL. */
! void
revert_static_member_fn (decl, fn, argtypes)
tree *decl, *fn, *argtypes;
{
diff -c -p ./decl2.c /home/mitchell/projects/egcs/gcc/cp/decl2.c
*** ./decl2.c Thu Jan 29 00:22:48 1998
--- /home/mitchell/projects/egcs/gcc/cp/decl2.c Thu Jan 29 10:57:19 1998
*************** finish_file ()
*** 3139,3144 ****
--- 3139,3148 ----
}
else
expand_assignment (decl, init, 0, 0);
+
+ /* The expression might have involved increments and
+ decrements. */
+ emit_queue ();
/* Cleanup any temporaries needed for the initial value. */
expand_end_target_temps ();
diff -c -p ./parse.y /home/mitchell/projects/egcs/gcc/cp/parse.y
*** ./parse.y Thu Jan 29 00:23:02 1998
--- /home/mitchell/projects/egcs/gcc/cp/parse.y Thu Jan 29 16:17:45 1998
*************** typename_sub2:
*** 3308,3315 ****
TYPENAME SCOPE
{
if (TREE_CODE ($1) != IDENTIFIER_NODE)
! $$ = lastiddecl;
! got_scope = $$ = complete_type (TREE_TYPE ($$));
}
| SELFNAME SCOPE
{
--- 3308,3319 ----
TYPENAME SCOPE
{
if (TREE_CODE ($1) != IDENTIFIER_NODE)
! $1 = lastiddecl;
!
! got_scope = $$ = complete_type (TREE_TYPE ($1));
!
! if ($$ == error_mark_node)
! cp_error ("`%T' is not a class or namespace", $1);
}
| SELFNAME SCOPE
{
diff -c -p ./pt.c /home/mitchell/projects/egcs/gcc/cp/pt.c
*** ./pt.c Thu Jan 29 15:51:45 1998
--- /home/mitchell/projects/egcs/gcc/cp/pt.c Thu Jan 29 15:47:19 1998
*************** check_explicit_specialization (declarato
*** 866,871 ****
--- 866,874 ----
SET_DECL_EXPLICIT_INSTANTIATION (decl);
return decl;
}
+ else if (DECL_STATIC_FUNCTION_P (tmpl)
+ && DECL_NONSTATIC_FUNCTION_MEMBER_P (decl))
+ revert_static_member_fn (&decl, 0, 0);
/* Mangle the function name appropriately. Note that we do
not mangle specializations of non-template member
*************** coerce_template_parms (parms, arglist, i
*** 1820,1830 ****
continue;
}
! /* In case we are checking arguments inside a template template
! parameter, ARG that does not come from default argument is
! also a TREE_LIST node */
! if (TREE_CODE (arg) == TREE_LIST && ! is_overloaded_fn (arg))
{
is_tmpl_parm = 1;
arg = TREE_VALUE (arg);
}
--- 1827,1849 ----
continue;
}
! if (TREE_CODE (arg) == TREE_LIST
! && TREE_TYPE (arg) != NULL_TREE
! && TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
! {
! /* The template argument was the name of some
! member function. That's usually
! illegal, but static members are OK. In any
! case, grab the underlying fields/functions
! and issue an error later if required. */
! arg = TREE_VALUE (arg);
! TREE_TYPE (arg) = unknown_type_node;
! }
! else if (TREE_CODE (arg) == TREE_LIST && ! is_overloaded_fn (arg))
{
+ /* In case we are checking arguments inside a template template
+ parameter, ARG that does not come from default argument is
+ also a TREE_LIST node */
is_tmpl_parm = 1;
arg = TREE_VALUE (arg);
}
*************** overload_template_name (type)
*** 4584,4596 ****
pushdecl_class_level (decl);
}
/* Like type_unification but designed specially to handle conversion
! operators. */
int
! fn_type_unification (fn, explicit_targs, targs, args, return_type, strict)
tree fn, explicit_targs, targs, args, return_type;
int strict;
{
int i, dummy = 0;
tree fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
--- 4606,4622 ----
pushdecl_class_level (decl);
}
+
/* Like type_unification but designed specially to handle conversion
! operators. The EXTRA_FN_ARG, if any, is the type of an additional
! parameter to be added to the beginning of FN's parameter list. */
int
! fn_type_unification (fn, explicit_targs, targs, args, return_type,
! strict, extra_fn_arg)
tree fn, explicit_targs, targs, args, return_type;
int strict;
+ tree extra_fn_arg;
{
int i, dummy = 0;
tree fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
*************** fn_type_unification (fn, explicit_targs,
*** 4603,4615 ****
/* This is a template conversion operator. Use the return types
as well as the argument types. */
fn_arg_types = scratch_tree_cons (NULL_TREE,
! TREE_TYPE (TREE_TYPE (fn)),
! fn_arg_types);
decl_arg_types = scratch_tree_cons (NULL_TREE,
! return_type,
! decl_arg_types);
}
i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn),
&TREE_VEC_ELT (targs, 0),
fn_arg_types,
--- 4629,4645 ----
/* This is a template conversion operator. Use the return types
as well as the argument types. */
fn_arg_types = scratch_tree_cons (NULL_TREE,
! TREE_TYPE (TREE_TYPE (fn)),
! fn_arg_types);
decl_arg_types = scratch_tree_cons (NULL_TREE,
! return_type,
! decl_arg_types);
}
+ if (extra_fn_arg != NULL_TREE)
+ fn_arg_types = scratch_tree_cons (NULL_TREE, extra_fn_arg,
+ fn_arg_types);
+
i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn),
&TREE_VEC_ELT (targs, 0),
fn_arg_types,
*************** get_bindings (fn, decl, explicit_args)
*** 5247,5258 ****
{
int ntparms = DECL_NTPARMS (fn);
tree targs = make_scratch_vec (ntparms);
int i;
i = fn_type_unification (fn, explicit_args, targs,
! TYPE_ARG_TYPES (TREE_TYPE (decl)),
TREE_TYPE (TREE_TYPE (decl)),
! 1);
if (i == 0)
{
--- 5277,5311 ----
{
int ntparms = DECL_NTPARMS (fn);
tree targs = make_scratch_vec (ntparms);
+ tree decl_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ tree extra_fn_arg = NULL_TREE;
int i;
+ if (DECL_STATIC_FUNCTION_P (fn)
+ && DECL_NONSTATIC_FUNCTION_MEMBER_P (decl))
+ {
+ /* Sometimes we are trying to figure out what's being
+ specialized by a declaration that looks like a method, and it
+ turns out to be a static member function. */
+ if (CLASSTYPE_TEMPLATE_INFO (DECL_REAL_CONTEXT (fn))
+ && !is_member_template (fn))
+ /* The natural thing to do here seems to be to remove the
+ spurious `this' parameter from the DECL, but that prevents
+ unification from making use of the class type. So,
+ instead, we have fn_type_unification add to the parameters
+ for FN. */
+ extra_fn_arg = build_pointer_type (DECL_REAL_CONTEXT (fn));
+ else
+ /* In this case, though, adding the extra_fn_arg can confuse
+ things, so we remove from decl_arg_types instead. */
+ decl_arg_types = TREE_CHAIN (decl_arg_types);
+ }
+
i = fn_type_unification (fn, explicit_args, targs,
! decl_arg_types,
TREE_TYPE (TREE_TYPE (decl)),
! 1,
! extra_fn_arg);
if (i == 0)
{
diff -c -p ./search.c /home/mitchell/projects/egcs/gcc/cp/search.c
*** ./search.c Thu Jan 22 21:35:30 1998
--- /home/mitchell/projects/egcs/gcc/cp/search.c Thu Jan 29 10:14:39 1998
*************** note_debug_info_needed (type)
*** 3220,3225 ****
--- 3220,3229 ----
if (current_template_parms)
return;
+
+ if (TYPE_BEING_DEFINED (type))
+ /* We can't go looking for the base types and fields just yet. */
+ return;
/* We can't do the TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
does not support name references between translation units. Well, we
diff -c -p ./typeck.c /home/mitchell/projects/egcs/gcc/cp/typeck.c
*** ./typeck.c Thu Jan 29 00:23:02 1998
--- /home/mitchell/projects/egcs/gcc/cp/typeck.c Thu Jan 29 10:11:50 1998
*************** tree
*** 134,139 ****
--- 134,144 ----
complete_type (type)
tree type;
{
+ if (type == NULL_TREE)
+ /* Rather than crash, we return something sure to cause an error
+ at some point. */
+ return error_mark_node;
+
if (type == error_mark_node || TYPE_SIZE (type) != NULL_TREE)
;
else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
------------------------CUT HERE-----------------
Index: gcc/testsuite/g++.old-deja/g++.other/init1.C
===================================================================
RCS file: init1.C
diff -N init1.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- init1.C Thu Jan 29 10:56:02 1998
***************
*** 0 ****
--- 1,10 ----
+ extern "C" void abort();
+
+ int i;
+ int j = i++;
+
+ int main()
+ {
+ if (i != 1)
+ abort();
+ }
Index: gcc/testsuite/g++.old-deja/g++.pt/crash1.C
===================================================================
RCS file: crash1.C
diff -N crash1.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- /tmp/cvs27039caa Thu Jan 29 16:15:09 1998
***************
*** 0 ****
--- 1,11 ----
+ template<class T> class A {
+ public:
+ class subA {};
+ };
+
+
+ template<class T> class B : public A<T> {
+ public:
+ class subB : public A::subA {}; // ERROR - not a class or namespace
+ };
+
Index: gcc/testsuite/g++.old-deja/g++.pt/crash2.C
===================================================================
RCS file: crash2.C
diff -N crash2.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- crash2.C Thu Jan 29 15:43:14 1998
***************
*** 0 ****
--- 1,14 ----
+ // Build don't link:
+
+ template <class T>
+ struct S1
+ {
+ T* t;
+ static int foo;
+ };
+
+
+ struct S2 : public S1<S2>
+ {
+ S2* s;
+ };
Index: gcc/testsuite/g++.old-deja/g++.pt/explicit66.C
===================================================================
RCS file: explicit66.C
diff -N explicit66.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- /tmp/cvs27039daa Thu Jan 29 16:15:10 1998
***************
*** 0 ****
--- 1,11 ----
+ void f(int) {}
+ void f(double);
+
+ template <void (*fn)(int)>
+ void foo() {}
+
+ int main()
+ {
+ foo<f>();
+ }
+
Index: gcc/testsuite/g++.old-deja/g++.pt/explicit67.C
===================================================================
RCS file: explicit67.C
diff -N explicit67.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- /tmp/cvs27039eaa Thu Jan 29 16:15:10 1998
***************
*** 0 ****
--- 1,20 ----
+ struct S
+ {
+ void f(int);
+ void f(double);
+ };
+
+ void g(int);
+ void g(double);
+
+ template <int* IP>
+ void foo();
+ template <long l>
+ void foo();
+
+ void bar()
+ {
+ foo<S::f>(); // ERROR - no matching function
+ foo<g>(); // ERROR - no matching function
+
+ }
Index: gcc/testsuite/g++.old-deja/g++.pt/local6.C
===================================================================
RCS file: local6.C
diff -N local6.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- /tmp/cvs27039faa Thu Jan 29 16:15:11 1998
***************
*** 0 ****
--- 1,24 ----
+ extern "C" void abort();
+
+ template <class T>
+ int f(T)
+ {
+ struct S1 {
+ virtual int foo() { return 1; }
+ };
+
+ struct S2 : public S1 {
+ int foo() { return 2; }
+ };
+
+ S1* s2 = new S2;
+
+ return s2->foo();
+ }
+
+
+ int main()
+ {
+ if (f(3) != 2)
+ abort();
+ }
Index: gcc/testsuite/g++.old-deja/g++.pt/spec14.C
===================================================================
RCS file: spec14.C
diff -N spec14.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- /tmp/cvs27039haa Thu Jan 29 16:15:12 1998
***************
*** 0 ****
--- 1,9 ----
+ class X
+ {
+ public:
+ template <typename A, typename B, typename C>
+ X() {}
+
+ template <typename A, typename B>
+ X::X<A, void, B>() {} // ERROR - non-template type used as a template
+ };
Index: gcc/testsuite/g++.old-deja/g++.pt/spec15.C
===================================================================
RCS file: spec15.C
diff -N spec15.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- spec15.C Thu Jan 29 15:21:49 1998
***************
*** 0 ****
--- 1,49 ----
+ extern "C" void abort();
+
+ template <class T>
+ struct S1
+ {
+ static void f();
+ };
+
+ template <>
+ void S1<int>::f() {}
+
+ struct S2
+ {
+ template <class T>
+ static void g(T);
+ };
+
+ template <>
+ void S2::g(double) {}
+
+ template <>
+ void S2::g<int>(int) {}
+
+ template <class T>
+ struct S3
+ {
+ template <class U>
+ static int h(U);
+ };
+
+ template <class T>
+ template <>
+ int S3<T>::h(int) { return 0; }
+
+ template <>
+ template <>
+ int S3<char>::h(int) { return 1; }
+
+ int main()
+ {
+ S1<int>::f();
+ S2::g(3.0);
+ S2::g(7);
+
+ if (S3<double>::h(7) != 0)
+ abort();
+ if (S3<char>::h(7) != 1)
+ abort();
+ }