Patch for specializations of static members, and other problems
Mark Mitchell
mmitchell@usa.net
Thu Jan 29 16:50:00 GMT 1998
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();
+ }
More information about the Gcc-bugs
mailing list