This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH for references to functions
- To: egcs-patches at cygnus dot com
- Subject: PATCH for references to functions
- From: Mark Mitchell <mark at markmitchell dot com>
- Date: Fri, 25 Sep 1998 00:02:12 -0700
- Cc: Jason Merrill <jason at cygnus dot com>
- Reply-to: mark at markmitchell dot com
This patch allows the creation of references to functions, as mandated
by the standard. This bug in g++ dates back apparently to g++ 1.3.x.
--
Mark Mitchell mark@markmitchell.com
Mark Mitchell Consulting http://www.markmitchell.com
1998-09-24 Mark Mitchell <mark@markmitchell.com>
* cp-tree.h (language_lvalue_valid): Remove.
* decl.c (grokdeclarator): Don't disallow references to functions.
* tree.c (lvalue_p_1): New function, combining duplicated
code from ...
(lvalue_p): Use it.
(real_lvalue_p): Likewise.
* typeck.c (language_lvalue_valid): Remove.
(build_modify_expr): Treat FUNCTION_TYPEs as readonly, even though
they don't have TREE_READONLY set.
* typeck2.c (readonly_error): Add case for FUNCTION_DECLs.
Index: testsuite/g++.old-deja/g++.bugs/900519_05.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.bugs/900519_05.C,v
retrieving revision 1.1.1.1
diff -c -p -r1.1.1.1 900519_05.C
*** 900519_05.C 1997/08/19 07:35:13 1.1.1.1
--- 900519_05.C 1998/09/25 06:40:54
***************
*** 7,18 ****
// keywords: function types, reference types
typedef void (func_type) (int, int);
! typedef func_type& func_ref_type; // gets bogus error, XFAIL *-*-*
void function (int arg1, int arg2)
{
}
! func_type& global_func_ref1 = function; // gets bogus error, XFAIL *-*-*
int main () { return 0; }
--- 7,18 ----
// keywords: function types, reference types
typedef void (func_type) (int, int);
! typedef func_type& func_ref_type;
void function (int arg1, int arg2)
{
}
! func_type& global_func_ref1 = function;
int main () { return 0; }
Index: testsuite/g++.old-deja/g++.jason/ref4.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.jason/ref4.C,v
retrieving revision 1.1.1.1
diff -c -p -r1.1.1.1 ref4.C
*** ref4.C 1997/08/19 07:35:25 1.1.1.1
--- ref4.C 1998/09/25 06:40:54
***************
*** 1,4 ****
// Build don't link:
void f ();
! void (&fr)() = f; // gets bogus error - references to functions XFAIL *-*-*
--- 1,4 ----
// Build don't link:
void f ();
! void (&fr)() = f;
Index: testsuite/g++.old-deja/g++.law/arm2.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.law/arm2.C,v
retrieving revision 1.1.1.1
diff -c -p -r1.1.1.1 arm2.C
*** arm2.C 1997/08/19 07:35:34 1.1.1.1
--- arm2.C 1998/09/25 06:40:54
*************** int f() { return 1; }
*** 11,17 ****
int main()
{
! int (&fr)() = f; // g++ cannot compile it
return 0;
}
--- 11,17 ----
int main()
{
! int (&fr)() = f;
return 0;
}
Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.141
diff -c -p -r1.141 cp-tree.h
*** cp-tree.h 1998/09/15 11:43:42 1.141
--- cp-tree.h 1998/09/25 05:35:18
*************** extern tree build_const_cast PROTO((tr
*** 3101,3107 ****
extern tree build_c_cast PROTO((tree, tree));
extern tree build_x_modify_expr PROTO((tree, enum tree_code, tree));
extern tree build_modify_expr PROTO((tree, enum tree_code, tree));
- extern int language_lvalue_valid PROTO((tree));
extern void warn_for_assignment PROTO((char *, char *, char *, tree, int, int));
extern tree convert_for_initialization PROTO((tree, tree, tree, int, char *, tree, int));
extern void c_expand_asm_operands PROTO((tree, tree, tree, tree, int, char *, int));
--- 3100,3105 ----
Index: decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.212
diff -c -p -r1.212 decl.c
*** decl.c 1998/09/22 11:58:35 1.212
--- decl.c 1998/09/25 05:36:02
*************** grokdeclarator (declarator, declspecs, d
*** 9744,9761 ****
}
else if (TREE_CODE (declarator) == ADDR_EXPR)
{
! if (TREE_CODE (type) == FUNCTION_TYPE)
! {
! error ("cannot declare references to functions; use pointer to function instead");
! type = build_pointer_type (type);
! }
else
! {
! if (TREE_CODE (type) == VOID_TYPE)
! error ("invalid type: `void &'");
! else
! type = build_reference_type (type);
! }
}
else if (TREE_CODE (type) == METHOD_TYPE)
{
--- 9744,9753 ----
}
else if (TREE_CODE (declarator) == ADDR_EXPR)
{
! if (TREE_CODE (type) == VOID_TYPE)
! error ("invalid type: `void &'");
else
! type = build_reference_type (type);
}
else if (TREE_CODE (type) == METHOD_TYPE)
{
Index: tree.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/tree.c,v
retrieving revision 1.65
diff -c -p -r1.65 tree.c
*** tree.c 1998/09/07 14:25:31 1.65
--- tree.c 1998/09/25 05:36:22
*************** static tree list_hash_lookup PROTO((int,
*** 40,59 ****
tree));
static void propagate_binfo_offsets PROTO((tree, tree));
static int avoid_overlap PROTO((tree, tree));
#define CEIL(x,y) (((x) + (y) - 1) / (y))
! /* Return nonzero if REF is an lvalue valid for this language.
! Lvalues can be assigned, unless they have TREE_READONLY.
! Lvalues can have their address taken, unless they have DECL_REGISTER. */
! int
! real_lvalue_p (ref)
tree ref;
{
- if (! language_lvalue_valid (ref))
- return 0;
-
if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
return 1;
--- 40,58 ----
tree));
static void propagate_binfo_offsets PROTO((tree, tree));
static int avoid_overlap PROTO((tree, tree));
+ static int lvalue_p_real PROTO((tree, int));
#define CEIL(x,y) (((x) + (y) - 1) / (y))
! /* Returns non-zero if REF is an lvalue. If
! TREAT_CLASS_RVALUES_AS_LVALUES is non-zero, rvalues of class type
! are considered lvalues. */
! static int
! lvalue_p_real (ref, treat_class_rvalues_as_lvalues)
tree ref;
+ int treat_class_rvalues_as_lvalues;
{
if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
return 1;
*************** real_lvalue_p (ref)
*** 71,77 ****
case UNSAVE_EXPR:
case TRY_CATCH_EXPR:
case WITH_CLEANUP_EXPR:
! return real_lvalue_p (TREE_OPERAND (ref, 0));
case STRING_CST:
return 1;
--- 70,79 ----
case UNSAVE_EXPR:
case TRY_CATCH_EXPR:
case WITH_CLEANUP_EXPR:
! case REALPART_EXPR:
! case IMAGPART_EXPR:
! return lvalue_p_real (TREE_OPERAND (ref, 0),
! treat_class_rvalues_as_lvalues);
case STRING_CST:
return 1;
*************** real_lvalue_p (ref)
*** 85,91 ****
case ARRAY_REF:
case PARM_DECL:
case RESULT_DECL:
- case ERROR_MARK:
if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
&& TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
return 1;
--- 87,92 ----
*************** real_lvalue_p (ref)
*** 97,121 ****
case OFFSET_REF:
if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
return 1;
! return real_lvalue_p (TREE_OPERAND (ref, 0))
! && real_lvalue_p (TREE_OPERAND (ref, 1));
break;
case COND_EXPR:
! return (real_lvalue_p (TREE_OPERAND (ref, 1))
! && real_lvalue_p (TREE_OPERAND (ref, 2)));
case MODIFY_EXPR:
return 1;
case COMPOUND_EXPR:
! return real_lvalue_p (TREE_OPERAND (ref, 1));
case MAX_EXPR:
case MIN_EXPR:
! return (real_lvalue_p (TREE_OPERAND (ref, 0))
! && real_lvalue_p (TREE_OPERAND (ref, 1)));
default:
break;
}
--- 98,141 ----
case OFFSET_REF:
if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
return 1;
! return (lvalue_p_real (TREE_OPERAND (ref, 0),
! treat_class_rvalues_as_lvalues)
! && lvalue_p_real (TREE_OPERAND (ref, 1),
! treat_class_rvalues_as_lvalues));
break;
case COND_EXPR:
! return (lvalue_p_real (TREE_OPERAND (ref, 1),
! treat_class_rvalues_as_lvalues)
! && lvalue_p_real (TREE_OPERAND (ref, 2),
! treat_class_rvalues_as_lvalues));
case MODIFY_EXPR:
return 1;
case COMPOUND_EXPR:
! return lvalue_p_real (TREE_OPERAND (ref, 1),
! treat_class_rvalues_as_lvalues);
case MAX_EXPR:
case MIN_EXPR:
! return (lvalue_p_real (TREE_OPERAND (ref, 0),
! treat_class_rvalues_as_lvalues)
! && lvalue_p_real (TREE_OPERAND (ref, 1),
! treat_class_rvalues_as_lvalues));
!
! case TARGET_EXPR:
! return treat_class_rvalues_as_lvalues;
!
! case CALL_EXPR:
! return (treat_class_rvalues_as_lvalues
! && IS_AGGR_TYPE (TREE_TYPE (ref)));
+ case FUNCTION_DECL:
+ /* All functions (except non-static-member functions) are
+ lvalues. */
+ return !DECL_NONSTATIC_MEMBER_FUNCTION_P (ref);
+
default:
break;
}
*************** real_lvalue_p (ref)
*** 123,214 ****
return 0;
}
/* This differs from real_lvalue_p in that class rvalues are considered
lvalues. */
int
lvalue_p (ref)
tree ref;
{
! if (! language_lvalue_valid (ref))
! return 0;
!
! if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
! return 1;
!
! if (ref == current_class_ptr && flag_this_is_variable <= 0)
! return 0;
!
! switch (TREE_CODE (ref))
! {
! /* preincrements and predecrements are valid lvals, provided
! what they refer to are valid lvals. */
! case PREINCREMENT_EXPR:
! case PREDECREMENT_EXPR:
! case REALPART_EXPR:
! case IMAGPART_EXPR:
! case COMPONENT_REF:
! case SAVE_EXPR:
! case UNSAVE_EXPR:
! case TRY_CATCH_EXPR:
! case WITH_CLEANUP_EXPR:
! return lvalue_p (TREE_OPERAND (ref, 0));
!
! case STRING_CST:
! return 1;
!
! case VAR_DECL:
! if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
! && DECL_LANG_SPECIFIC (ref)
! && DECL_IN_AGGR_P (ref))
! return 0;
! case INDIRECT_REF:
! case ARRAY_REF:
! case PARM_DECL:
! case RESULT_DECL:
! case ERROR_MARK:
! if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
! && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
! return 1;
! break;
!
! case TARGET_EXPR:
! return 1;
!
! case CALL_EXPR:
! if (IS_AGGR_TYPE (TREE_TYPE (ref)))
! return 1;
! break;
!
! /* A currently unresolved scope ref. */
! case SCOPE_REF:
! my_friendly_abort (103);
! case OFFSET_REF:
! if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
! return 1;
! return lvalue_p (TREE_OPERAND (ref, 0))
! && lvalue_p (TREE_OPERAND (ref, 1));
! break;
!
! case COND_EXPR:
! return (lvalue_p (TREE_OPERAND (ref, 1))
! && lvalue_p (TREE_OPERAND (ref, 2)));
!
! case MODIFY_EXPR:
! return 1;
!
! case COMPOUND_EXPR:
! return lvalue_p (TREE_OPERAND (ref, 1));
!
! case MAX_EXPR:
! case MIN_EXPR:
! return (lvalue_p (TREE_OPERAND (ref, 0))
! && lvalue_p (TREE_OPERAND (ref, 1)));
!
! default:
! break;
! }
!
! return 0;
}
/* Return nonzero if REF is an lvalue valid for this language;
--- 143,167 ----
return 0;
}
+ /* Return nonzero if REF is an lvalue valid for this language.
+ Lvalues can be assigned, unless they have TREE_READONLY.
+ Lvalues can have their address taken, unless they have DECL_REGISTER. */
+
+ int
+ real_lvalue_p (ref)
+ tree ref;
+ {
+ return lvalue_p_real (ref, /*treat_class_rvalues_as_lvalues=*/0);
+ }
+
/* This differs from real_lvalue_p in that class rvalues are considered
lvalues. */
+
int
lvalue_p (ref)
tree ref;
{
! return lvalue_p_real (ref, /*treat_class_rvalues_as_lvalues=*/1);
}
/* Return nonzero if REF is an lvalue valid for this language;
Index: typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.108
diff -c -p -r1.108 typeck.c
*** typeck.c 1998/09/15 14:28:07 1.108
--- typeck.c 1998/09/25 05:36:44
*************** build_x_modify_expr (lhs, modifycode, rh
*** 6354,6368 ****
return build_modify_expr (lhs, modifycode, rhs);
}
- /* Return 0 if EXP is not a valid lvalue in this language
- even though `lvalue_or_else' would accept it. */
-
- int
- language_lvalue_valid (exp)
- tree exp ATTRIBUTE_UNUSED;
- {
- return 1;
- }
/* Get difference in deltas for different pointer to member function
types. Return integer_zero_node, if FROM cannot be converted to a
--- 6331,6336 ----
Index: typeck2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck2.c,v
retrieving revision 1.30
diff -c -p -r1.30 typeck2.c
*** typeck2.c 1998/09/07 14:25:34 1.30
--- typeck2.c 1998/09/25 05:36:47
*************** build_modify_expr (lhs, modifycode, rhs)
*** 6106,6111 ****
--- 6083,6091 ----
&& (IS_SIGNATURE_POINTER (TREE_TYPE (TREE_OPERAND (lhs, 0)))
|| IS_SIGNATURE_REFERENCE (TREE_TYPE (TREE_OPERAND (lhs, 0)))))
&& (TREE_READONLY (lhs) || TYPE_READONLY (lhstype)
+ /* Functions are not modifiable, even though they are
+ lvalues. */
+ || TREE_CODE (TREE_TYPE (lhs)) == FUNCTION_TYPE
|| ((TREE_CODE (lhstype) == RECORD_TYPE
|| TREE_CODE (lhstype) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (lhstype))
*************** readonly_error (arg, string, soft)
*** 118,124 ****
(*fn) ("%s of read-only reference `%D'", string, TREE_OPERAND (arg, 0));
else if (TREE_CODE (arg) == RESULT_DECL)
(*fn) ("%s of read-only named return value `%D'", string, arg);
! else
(*fn) ("%s of read-only location", string);
}
--- 118,126 ----
(*fn) ("%s of read-only reference `%D'", string, TREE_OPERAND (arg, 0));
else if (TREE_CODE (arg) == RESULT_DECL)
(*fn) ("%s of read-only named return value `%D'", string, arg);
! else if (TREE_CODE (arg) == FUNCTION_DECL)
! (*fn) ("%s of function `%D'", string, arg);
! else
(*fn) ("%s of read-only location", string);
}