This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

PATCH for references to functions



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);
  }
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]