diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 26aad5f7dd0..548bed8dd71 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +1998-09-24 Mark Mitchell + + * 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. + 1998-09-24 Benjamin Kosnik * spew.c (yylex): Give diagnostic. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 1f4bc0e2774..d77bb82c381 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3101,7 +3101,6 @@ extern tree build_const_cast PROTO((tree, tree)); 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)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index a8317cc698c..87a391f0350 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -9744,18 +9744,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) } 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); - } + if (TREE_CODE (type) == VOID_TYPE) + error ("invalid type: `void &'"); else - { - if (TREE_CODE (type) == VOID_TYPE) - error ("invalid type: `void &'"); - else - type = build_reference_type (type); - } + type = build_reference_type (type); } else if (TREE_CODE (type) == METHOD_TYPE) { diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 41475b5f467..1a87a5128e1 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -40,20 +40,19 @@ static tree list_hash_lookup PROTO((int, int, int, int, tree, tree, tree)); static void propagate_binfo_offsets PROTO((tree, tree)); static int avoid_overlap PROTO((tree, tree)); +static int lvalue_p_1 PROTO((tree, int)); #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. */ +/* Returns non-zero if REF is an lvalue. If + TREAT_CLASS_RVALUES_AS_LVALUES is non-zero, rvalues of class type + are considered lvalues. */ -int -real_lvalue_p (ref) +static int +lvalue_p_1 (ref, treat_class_rvalues_as_lvalues) tree ref; + int treat_class_rvalues_as_lvalues; { - if (! language_lvalue_valid (ref)) - return 0; - if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE) return 1; @@ -71,7 +70,10 @@ real_lvalue_p (ref) case UNSAVE_EXPR: case TRY_CATCH_EXPR: case WITH_CLEANUP_EXPR: - return real_lvalue_p (TREE_OPERAND (ref, 0)); + case REALPART_EXPR: + case IMAGPART_EXPR: + return lvalue_p_1 (TREE_OPERAND (ref, 0), + treat_class_rvalues_as_lvalues); case STRING_CST: return 1; @@ -85,7 +87,6 @@ real_lvalue_p (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; @@ -97,24 +98,43 @@ real_lvalue_p (ref) 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)); + return (lvalue_p_1 (TREE_OPERAND (ref, 0), + treat_class_rvalues_as_lvalues) + && lvalue_p_1 (TREE_OPERAND (ref, 1), + treat_class_rvalues_as_lvalues)); break; case COND_EXPR: - return (real_lvalue_p (TREE_OPERAND (ref, 1)) - && real_lvalue_p (TREE_OPERAND (ref, 2))); + return (lvalue_p_1 (TREE_OPERAND (ref, 1), + treat_class_rvalues_as_lvalues) + && lvalue_p_1 (TREE_OPERAND (ref, 2), + treat_class_rvalues_as_lvalues)); case MODIFY_EXPR: return 1; case COMPOUND_EXPR: - return real_lvalue_p (TREE_OPERAND (ref, 1)); + return lvalue_p_1 (TREE_OPERAND (ref, 1), + treat_class_rvalues_as_lvalues); case MAX_EXPR: case MIN_EXPR: - return (real_lvalue_p (TREE_OPERAND (ref, 0)) - && real_lvalue_p (TREE_OPERAND (ref, 1))); + return (lvalue_p_1 (TREE_OPERAND (ref, 0), + treat_class_rvalues_as_lvalues) + && lvalue_p_1 (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; @@ -123,92 +143,26 @@ real_lvalue_p (ref) return 0; } +/* Return nonzero if REF is an lvalue valid for this language. + Lvalues can be assigned, unless they have TREE_READONLY, or unless + they are FUNCTION_DECLs. Lvalues can have their address taken, + unless they have DECL_REGISTER. */ + +int +real_lvalue_p (ref) + tree ref; +{ + return lvalue_p_1 (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; { - 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 lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/1); } /* Return nonzero if REF is an lvalue valid for this language; diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 6fc3707160e..72481750d76 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -6106,6 +6106,9 @@ build_modify_expr (lhs, modifycode, rhs) && (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)) @@ -6354,15 +6357,6 @@ build_x_modify_expr (lhs, modifycode, rhs) 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 diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 265b387fd23..a00a4f13ffc 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -118,7 +118,9 @@ readonly_error (arg, string, soft) (*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 + else if (TREE_CODE (arg) == FUNCTION_DECL) + (*fn) ("%s of function `%D'", string, arg); + else (*fn) ("%s of read-only location", string); } diff --git a/gcc/testsuite/g++.old-deja/g++.bugs/900519_05.C b/gcc/testsuite/g++.old-deja/g++.bugs/900519_05.C index 05d2ea03d3d..9a2a4cffaa2 100644 --- a/gcc/testsuite/g++.old-deja/g++.bugs/900519_05.C +++ b/gcc/testsuite/g++.old-deja/g++.bugs/900519_05.C @@ -7,12 +7,12 @@ // keywords: function types, reference types typedef void (func_type) (int, int); -typedef func_type& func_ref_type; // gets bogus error, XFAIL *-*-* +typedef func_type& func_ref_type; void function (int arg1, int arg2) { } -func_type& global_func_ref1 = function; // gets bogus error, XFAIL *-*-* +func_type& global_func_ref1 = function; int main () { return 0; } diff --git a/gcc/testsuite/g++.old-deja/g++.jason/ref4.C b/gcc/testsuite/g++.old-deja/g++.jason/ref4.C index 422c58cab70..5c62d6a10d2 100644 --- a/gcc/testsuite/g++.old-deja/g++.jason/ref4.C +++ b/gcc/testsuite/g++.old-deja/g++.jason/ref4.C @@ -1,4 +1,4 @@ // Build don't link: void f (); -void (&fr)() = f; // gets bogus error - references to functions XFAIL *-*-* +void (&fr)() = f; diff --git a/gcc/testsuite/g++.old-deja/g++.law/arm2.C b/gcc/testsuite/g++.old-deja/g++.law/arm2.C index de8fe425bda..d2f43d76e8b 100644 --- a/gcc/testsuite/g++.old-deja/g++.law/arm2.C +++ b/gcc/testsuite/g++.old-deja/g++.law/arm2.C @@ -11,7 +11,7 @@ int f() { return 1; } int main() { - int (&fr)() = f; // g++ cannot compile it + int (&fr)() = f; return 0; }