C++ PATCH for template parameter shadowing and overloading
Mark Mitchell
mark@markmitchell.com
Wed Dec 16 15:52:00 GMT 1998
This patch fixes two bugs. On code like:
// Build don't link:
template <class T>
struct S {
typedef T X;
class C {
typedef T X;
};
};
template <int I>
struct S2 {
enum { A = I };
void f() {
int A;
}
};
we issued spurious errors about shadowing template parameters. Quite
bogus ineed. And, on:
int i = 1;
void func(void (*f)(void *))
{
(*f)(0);
}
class foobar {
void callback();
static void callback(void *);
public:
foobar();
};
void foobar::callback(void*)
{
i = 0;
}
foobar::foobar()
{
func(callback);
}
int main()
{
foobar fb;
return i;
}
we failed to take the address of `callback' before passing it to
`func', resulting in bogus code generation and/or compiler aborts.
--
Mark Mitchell mark@markmitchell.com
Mark Mitchell Consulting http://www.markmitchell.com
1998-12-16 Mark Mitchell <mark@markmitchell.com>
* class.c (resolve_address_of_overloaded_function): Do conversion
to correct type here, rather than ...
(instantiate_type): Here.
* cp-tree.h (DECL_TEMPLATE_PARM_P): New macro.
(DECL_TEMPLATE_TEMPLATE_PARM_P): Use it.
(decl_template_parm_p): Remove.
* decl.c (pushdecl): Don't set DECL_CONTEXT for a template
paramter.
* lex.c (do_identifier): Use DECL_TEMPLATE_PARM_P.
(push_inline_template_parms_recursive): Set it.
(decl_template_parm_p): Remove.
(check_template_shadow): Use DECL_TEMPLATE_PARM_P.
(process_template_parm): Set it.
Index: cp/class.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/class.c,v
retrieving revision 1.122
diff -c -p -r1.122 class.c
*** class.c 1998/12/14 15:35:28 1.122
--- class.c 1998/12/16 21:25:43
*************** resolve_address_of_overloaded_function (
*** 5025,5030 ****
--- 5025,5031 ----
are the TREE_PURPOSE, not the TREE_VALUE, in this list, for easy
interoperability with most_specialized_instantiation. */
tree matches = NULL_TREE;
+ tree fn;
/* By the time we get here, we should be seeing only real
pointer-to-member types, not the internal POINTER_TYPE to
*************** resolve_address_of_overloaded_function (
*** 5212,5219 ****
return error_mark_node;
}
! /* Good, exactly one match. */
! return TREE_PURPOSE (matches);
}
/* This function will instantiate the type of the expression given in
--- 5213,5232 ----
return error_mark_node;
}
! /* Good, exactly one match. Now, convert it to the correct type. */
! fn = TREE_PURPOSE (matches);
!
! if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type))
! return build_unary_op (ADDR_EXPR, fn, 0);
! else
! {
! /* The target must be a REFERENCE_TYPE. Above, build_unary_op
! will mark the function as addressed, but here we must do it
! explicitly. */
! mark_addressable (fn);
!
! return fn;
! }
}
/* This function will instantiate the type of the expression given in
*************** instantiate_type (lhstype, rhs, complain
*** 5291,5323 ****
case COMPONENT_REF:
{
tree field = TREE_OPERAND (rhs, 1);
! if (TREE_CODE (field) == TREE_LIST)
! {
! tree function = instantiate_type (lhstype, field, complain);
! if (function == error_mark_node)
! return error_mark_node;
! my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 185);
! if (! DECL_STATIC_FUNCTION_P (function))
{
! tree t = TREE_TYPE (TREE_OPERAND (rhs, 0));
! if (TYPE_MAIN_VARIANT (t) == current_class_type)
! t = constructor_name (t);
!
! cp_error ("object-dependent reference to `%D' can only be used in a call",
! function);
! cp_error (" to form a pointer to member function, say `&%T::%D'",
! t, DECL_NAME (function));
! return error_mark_node;
}
!
! mark_used (function);
! return function;
}
!
! /* I could not trigger this code. MvL */
! my_friendly_abort (980326);
! return rhs;
}
case OFFSET_REF:
--- 5304,5334 ----
case COMPONENT_REF:
{
tree field = TREE_OPERAND (rhs, 1);
! tree r;
! my_friendly_assert (TREE_CODE (field) == TREE_LIST, 0);
!
! r = instantiate_type (lhstype, field, complain);
!
! if (r != error_mark_node && TYPE_PTRMEMFUNC_P (lhstype))
! {
! tree t = TYPE_PTRMEMFUNC_OBJECT_TYPE (lhstype);
! tree fn = TREE_VALUE (field);
! if (TREE_CODE (fn) == OVERLOAD)
! fn = OVL_FUNCTION (fn);
! if (TREE_CODE (fn) == FUNCTION_DECL)
{
! cp_error ("object-dependent reference `%E' can only be used in a call",
! DECL_NAME (fn));
! cp_error (" to form a pointer to member function, say `&%T::%E'",
! t, DECL_NAME (fn));
}
! else
! cp_error ("object-dependent reference can only be used in a call");
! return error_mark_node;
}
!
! return r;
}
case OFFSET_REF:
*************** instantiate_type (lhstype, rhs, complain
*** 5469,5495 ****
return rhs;
case ADDR_EXPR:
! {
! tree fn = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
! if (fn == error_mark_node)
! return error_mark_node;
! mark_addressable (fn);
! TREE_OPERAND (rhs, 0) = fn;
! TREE_CONSTANT (rhs) = staticp (fn);
! if (TYPE_PTRMEMFUNC_P (lhstype))
! {
! /* We must use the POINTER_TYPE to METHOD_TYPE on RHS here
! so that build_ptrmemfunc knows that RHS we have is not
! already a pointer-to-member constant. Instead, it is
! just a ADDR_EXPR over a FUNCTION_DECL. */
! TREE_TYPE (rhs) = TYPE_PTRMEMFUNC_FN_TYPE (lhstype);
! rhs = build_ptrmemfunc (TREE_TYPE (rhs), rhs, 0);
! }
! else
! /* Here, things our simple; we have exactly what we need. */
! TREE_TYPE (rhs) = lhstype;
! }
! return rhs;
case ENTRY_VALUE_EXPR:
my_friendly_abort (184);
--- 5480,5486 ----
return rhs;
case ADDR_EXPR:
! return instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
case ENTRY_VALUE_EXPR:
my_friendly_abort (184);
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.180
diff -c -p -r1.180 cp-tree.h
*** cp-tree.h 1998/12/13 14:45:49 1.180
--- cp-tree.h 1998/12/16 21:25:46
*************** Boston, MA 02111-1307, USA. */
*** 65,70 ****
--- 65,71 ----
Usage of DECL_LANG_FLAG_?:
0: DECL_ERROR_REPORTED (in VAR_DECL).
+ DECL_TEMPLATE_PARM_P (in CONST_DECL, TYPE_DECL, or TEMPLATE_DECL)
1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
*************** extern int flag_new_for_scope;
*** 1832,1842 ****
#define DECL_TEMPLATE_SPECIALIZATIONS(NODE) DECL_SIZE(NODE)
#define DECL_TEMPLATE_INJECT(NODE) DECL_INITIAL(NODE)
! /* Nonzero for TEMPLATE_DECL nodes that represents template template
! parameters */
#define DECL_TEMPLATE_TEMPLATE_PARM_P(NODE) \
! (TREE_CODE (NODE) == TEMPLATE_DECL && TREE_TYPE (NODE) \
! && TREE_CODE (TREE_TYPE (NODE)) == TEMPLATE_TEMPLATE_PARM)
#define DECL_FUNCTION_TEMPLATE_P(NODE) \
(TREE_CODE (NODE) == TEMPLATE_DECL \
--- 1833,1844 ----
#define DECL_TEMPLATE_SPECIALIZATIONS(NODE) DECL_SIZE(NODE)
#define DECL_TEMPLATE_INJECT(NODE) DECL_INITIAL(NODE)
! /* Nonzero for a DECL which is actually a template parameter. */
! #define DECL_TEMPLATE_PARM_P(NODE) \
! DECL_LANG_FLAG_0 (NODE)
!
#define DECL_TEMPLATE_TEMPLATE_PARM_P(NODE) \
! (TREE_CODE (NODE) == TEMPLATE_DECL && DECL_TEMPLATE_PARM_P (NODE))
#define DECL_FUNCTION_TEMPLATE_P(NODE) \
(TREE_CODE (NODE) == TEMPLATE_DECL \
*************** extern void do_pushlevel PROTO((void))
*** 3070,3076 ****
extern int is_member_template PROTO((tree));
extern int template_parms_equal PROTO((tree, tree));
extern int comp_template_parms PROTO((tree, tree));
- extern int decl_template_parm_p PROTO((tree));
extern int template_class_depth PROTO((tree));
extern int is_specialization_of PROTO((tree, tree));
extern int comp_template_args PROTO((tree, tree));
--- 3072,3077 ----
Index: cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.286
diff -c -p -r1.286 decl.c
*** decl.c 1998/12/15 13:59:52 1.286
--- decl.c 1998/12/16 21:25:55
*************** pushdecl (x)
*** 3514,3528 ****
register tree name = DECL_ASSEMBLER_NAME (x);
int need_new_binding = 1;
! if (current_function_decl && x != current_function_decl
! /* A local declaration for a function doesn't constitute nesting. */
! && (TREE_CODE (x) != FUNCTION_DECL || DECL_INITIAL (x))
! /* Don't change DECL_CONTEXT of virtual methods. */
! && (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x))
! && !DECL_CONTEXT (x))
! DECL_CONTEXT (x) = current_function_decl;
! if (!DECL_CONTEXT (x))
! DECL_CONTEXT (x) = FROB_CONTEXT (current_namespace);
/* Type are looked up using the DECL_NAME, as that is what the rest of the
compiler wants to use. */
--- 3514,3536 ----
register tree name = DECL_ASSEMBLER_NAME (x);
int need_new_binding = 1;
! if (DECL_TEMPLATE_PARM_P (x))
! /* Template parameters have no context; they are not X::T even
! when declared within a class or namespace. */
! ;
! else
! {
! if (current_function_decl && x != current_function_decl
! /* A local declaration for a function doesn't constitute
! nesting. */
! && (TREE_CODE (x) != FUNCTION_DECL || DECL_INITIAL (x))
! /* Don't change DECL_CONTEXT of virtual methods. */
! && (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x))
! && !DECL_CONTEXT (x))
! DECL_CONTEXT (x) = current_function_decl;
! if (!DECL_CONTEXT (x))
! DECL_CONTEXT (x) = FROB_CONTEXT (current_namespace);
! }
/* Type are looked up using the DECL_NAME, as that is what the rest of the
compiler wants to use. */
Index: cp/lex.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/lex.c,v
retrieving revision 1.94
diff -c -p -r1.94 lex.c
*** lex.c 1998/12/13 14:45:57 1.94
--- lex.c 1998/12/16 21:25:58
*************** do_identifier (token, parsing, args)
*** 3051,3066 ****
cp_error ("enum `%D' is private", id);
/* protected is OK, since it's an enum of `this'. */
}
! if (!processing_template_decl
! /* Really, if we're processing a template, we just want to
! resolve template parameters, and not enumeration
! constants. But, they're hard to tell apart. (Note that
! a non-type template parameter may have enumeration type.)
! Fortunately, there's no harm in resolving *global*
! enumeration constants, since they can't depend on
! template parameters. */
! || (TREE_CODE (CP_DECL_CONTEXT (id)) == NAMESPACE_DECL
! && TREE_CODE (DECL_INITIAL (id)) == TEMPLATE_PARM_INDEX))
id = DECL_INITIAL (id);
}
else
--- 3051,3057 ----
cp_error ("enum `%D' is private", id);
/* protected is OK, since it's an enum of `this'. */
}
! if (!processing_template_decl || DECL_TEMPLATE_PARM_P (id))
id = DECL_INITIAL (id);
}
else
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.246
diff -c -p -r1.246 pt.c
*** pt.c 1998/12/14 15:35:35 1.246
--- pt.c 1998/12/16 21:26:08
*************** push_inline_template_parms_recursive (pa
*** 357,366 ****
case PARM_DECL:
{
! /* Make a CONST_DECL as is done in process_template_parm. */
tree decl = build_decl (CONST_DECL, DECL_NAME (parm),
TREE_TYPE (parm));
DECL_INITIAL (decl) = DECL_INITIAL (parm);
pushdecl (decl);
}
break;
--- 357,371 ----
case PARM_DECL:
{
! /* Make a CONST_DECL as is done in process_template_parm.
! It is ugly that we recreate this here; the original
! version built in process_template_parm is no longer
! available. */
tree decl = build_decl (CONST_DECL, DECL_NAME (parm),
TREE_TYPE (parm));
+ SET_DECL_ARTIFICIAL (decl);
DECL_INITIAL (decl) = DECL_INITIAL (parm);
+ DECL_TEMPLATE_PARM_P (decl) = 1;
pushdecl (decl);
}
break;
*************** int comp_template_parms (parms1, parms2)
*** 1467,1499 ****
return 1;
}
-
- /* Returns 1 iff DECL is a template parameter. */
-
- int decl_template_parm_p (decl)
- tree decl;
- {
- /* For template template parms. */
- if (TREE_CODE (decl) == TEMPLATE_DECL
- && TREE_TYPE (decl)
- && TREE_CODE (TREE_TYPE (decl)) == TEMPLATE_TEMPLATE_PARM)
- return 1;
-
- /* For template type parms. */
- if (TREE_CODE (decl) == TYPE_DECL
- && TREE_TYPE (decl)
- && TREE_CODE (TREE_TYPE (decl)) == TEMPLATE_TYPE_PARM)
- return 1;
-
- /* For template non-type parms. */
- if (TREE_CODE (decl) == CONST_DECL
- && DECL_INITIAL (decl)
- && TREE_CODE (DECL_INITIAL (decl)) == TEMPLATE_PARM_INDEX)
- return 1;
-
- return 0;
- }
-
/* Complain if DECL shadows a template parameter.
[temp.local]: A template-parameter shall not be redeclared within its
--- 1472,1477 ----
*************** check_template_shadow (decl)
*** 1510,1516 ****
/* We check for decl != olddecl to avoid bogus errors for using a
name inside a class. We check TPFI to avoid duplicate errors for
inline member templates. */
! if (decl != olddecl && decl_template_parm_p (olddecl)
&& ! TEMPLATE_PARMS_FOR_INLINE (current_template_parms))
{
cp_error_at ("declaration of `%#D'", decl);
--- 1488,1494 ----
/* We check for decl != olddecl to avoid bogus errors for using a
name inside a class. We check TPFI to avoid duplicate errors for
inline member templates. */
! if (decl != olddecl && DECL_TEMPLATE_PARM_P (olddecl)
&& ! TEMPLATE_PARMS_FOR_INLINE (current_template_parms))
{
cp_error_at ("declaration of `%#D'", decl);
*************** process_template_parm (list, next)
*** 1671,1676 ****
--- 1649,1655 ----
decl, TREE_TYPE (parm));
}
SET_DECL_ARTIFICIAL (decl);
+ DECL_TEMPLATE_PARM_P (decl) = 1;
pushdecl (decl);
parm = build_tree_list (defval, parm);
return chainon (list, parm);
Index: testsuite/g++.old-deja/g++.pt/shadow1.C
===================================================================
RCS file: shadow1.C
diff -N shadow1.C
*** /dev/null Sat Dec 5 20:30:03 1998
--- shadow1.C Wed Dec 16 14:33:49 1998
***************
*** 0 ****
--- 1,19 ----
+ // Build don't link:
+
+ template <class T>
+ struct S {
+ typedef T X;
+
+ class C {
+ typedef T X;
+ };
+ };
+
+ template <int I>
+ struct S2 {
+ enum { A = I };
+
+ void f() {
+ int A;
+ }
+ };
Index: testsuite/g++.old-deja/g++.other/overload10.C
===================================================================
RCS file: overload10.C
diff -N overload10.C
*** /dev/null Sat Dec 5 20:30:03 1998
--- overload10.C Wed Dec 16 14:34:23 1998
***************
*** 0 ****
--- 1,30 ----
+ int i = 1;
+
+ void func(void (*f)(void *))
+ {
+ (*f)(0);
+ }
+
+ class foobar {
+ void callback();
+ static void callback(void *);
+ public:
+ foobar();
+ };
+
+ void foobar::callback(void*)
+ {
+ i = 0;
+ }
+
+ foobar::foobar()
+ {
+ func(callback);
+ }
+
+ int main()
+ {
+ foobar fb;
+
+ return i;
+ }
More information about the Gcc-patches
mailing list