diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a8cdba270b9c..0f8ebea5cc52 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2004-11-25 Mark Mitchell + + PR c++/18001 + * c-common.h (lvalue_use): Move here from c-ctypeck.c. + (lvalue_or_else): Declare. + * c-common.c (lvalue_or_else): Move here from c-typeck.c. + * c-typeck.c (lvalue_use): Remove. + (lvalue_or_else): Remove. + + PR c++/18556 + * toplev.c (check_global_declarations): Set DECL_IGNORED_P on + unemitted variables with static storage duration. + 2004-11-25 Gerald Pfeifer * tree-cfg.c (tree_verify_flow_info): Do not terminate error() diff --git a/gcc/c-common.c b/gcc/c-common.c index 81bdbbf62543..bfefeb231dcb 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -5617,4 +5617,40 @@ fold_offsetof (tree expr) return convert (size_type_node, fold_offsetof_1 (expr)); } +/* Return nonzero if REF is an lvalue valid for this language; + otherwise, print an error message and return zero. USE says + how the lvalue is being used and so selects the error message. */ + +int +lvalue_or_else (tree ref, enum lvalue_use use) +{ + int win = lvalue_p (ref); + + if (!win) + { + switch (use) + { + case lv_assign: + error ("invalid lvalue in assignment"); + break; + case lv_increment: + error ("invalid lvalue in increment"); + break; + case lv_decrement: + error ("invalid lvalue in decrement"); + break; + case lv_addressof: + error ("invalid lvalue in unary %<&%>"); + break; + case lv_asm: + error ("invalid lvalue in asm statement"); + break; + default: + gcc_unreachable (); + } + } + + return win; +} + #include "gt-c-common.h" diff --git a/gcc/c-common.h b/gcc/c-common.h index 63c095c07811..d0fbaa837dfd 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -873,6 +873,19 @@ extern void verify_sequence_points (tree); extern tree fold_offsetof (tree); +/* Places where an lvalue, or modifiable lvalue, may be required. + Used to select diagnostic messages in lvalue_or_else and + readonly_error. */ +enum lvalue_use { + lv_assign, + lv_increment, + lv_decrement, + lv_addressof, + lv_asm +}; + +extern int lvalue_or_else (tree, enum lvalue_use); + /* In c-gimplify.c */ extern void c_genericize (tree); extern int c_gimplify_expr (tree *, tree *, tree *); diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index c5401042b66b..23ff80e10de2 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -44,17 +44,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tree-iterator.h" #include "tree-gimple.h" -/* Places where an lvalue, or modifiable lvalue, may be required. - Used to select diagnostic messages in lvalue_or_else and - readonly_error. */ -enum lvalue_use { - lv_assign, - lv_increment, - lv_decrement, - lv_addressof, - lv_asm -}; - /* Possible cases of implicit bad conversions. Used to select diagnostic messages in convert_for_assignment. */ enum impl_conv { @@ -109,7 +98,6 @@ static void add_pending_init (tree, tree); static void set_nonincremental_init (void); static void set_nonincremental_init_from_string (tree); static tree find_init_member (tree); -static int lvalue_or_else (tree, enum lvalue_use); static void readonly_error (tree, enum lvalue_use); static void record_maybe_used_decl (tree); @@ -2714,43 +2702,6 @@ lvalue_p (tree ref) return 0; } } - -/* Return nonzero if REF is an lvalue valid for this language; - otherwise, print an error message and return zero. USE says - how the lvalue is being used and so selects the error message. */ - -static int -lvalue_or_else (tree ref, enum lvalue_use use) -{ - int win = lvalue_p (ref); - - if (!win) - { - switch (use) - { - case lv_assign: - error ("invalid lvalue in assignment"); - break; - case lv_increment: - error ("invalid lvalue in increment"); - break; - case lv_decrement: - error ("invalid lvalue in decrement"); - break; - case lv_addressof: - error ("invalid lvalue in unary %<&%>"); - break; - case lv_asm: - error ("invalid lvalue in asm statement"); - break; - default: - gcc_unreachable (); - } - } - - return win; -} - /* Give an error for storing in something that is 'const'. */ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e79b20e55926..6a8aea8e4e18 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,30 @@ +2004-11-25 Mark Mitchell + + PR c++/18445 + * class.c (instantiate_type): Treat NON_DEPENDENT_EXPRs with + unknown_type as non matching. Tidy up. + * pt.c (build_non_dependent_expr): Do not build a + NON_DEPENDENT_EXPR for a VAR_DECL. + + PR c++/18001 + * cp-tree.h (lvalue_or_else): Remove declaration. + * tree.c (lvalue_or_else): Remove. + * typeck.c (build_unary_op): Adjust call to lvalue_or_else. + (build_modify_expr): Likewise. + + PR c++/18625 + * decl.c (duplicate_decls): Return error_mark_node on error, as + specified. + + PR c++/18466 + * decl.c (grokvardecl): Keep track of whether or not a there was + explicit qualification. + * name-lookup.c (set_decl_namespace): Complain about explicit + qualification of a name within its own namespace. + + PR c++/18545 + * typeck.c (check_return_expr): Robustify. + 2004-11-25 Kriang Lerdsuwanakij Friend class name lookup 3/n, PR c++/3332 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index e146abc0223e..3db223a8717c 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5864,6 +5864,15 @@ instantiate_type (tree lhstype, tree rhs, tsubst_flags_t flags) if (TREE_CODE (rhs) == BASELINK) rhs = BASELINK_FUNCTIONS (rhs); + /* If we are in a template, and have a NON_DEPENDENT_EXPR, we cannot + deduce any type information. */ + if (TREE_CODE (rhs) == NON_DEPENDENT_EXPR) + { + if (flags & tf_error) + error ("not enough type information"); + return error_mark_node; + } + /* We don't overwrite rhs if it is an overloaded function. Copying it would destroy the tree link. */ if (TREE_CODE (rhs) != OVERLOAD) @@ -5904,14 +5913,15 @@ instantiate_type (tree lhstype, tree rhs, tsubst_flags_t flags) case COMPONENT_REF: { - tree addr = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags); + tree member = TREE_OPERAND (rhs, 1); - if (addr != error_mark_node + member = instantiate_type (lhstype, member, flags); + if (member != error_mark_node && TREE_SIDE_EFFECTS (TREE_OPERAND (rhs, 0))) /* Do not lose object's side effects. */ - addr = build2 (COMPOUND_EXPR, TREE_TYPE (addr), - TREE_OPERAND (rhs, 0), addr); - return addr; + return build2 (COMPOUND_EXPR, TREE_TYPE (member), + TREE_OPERAND (rhs, 0), member); + return member; } case OFFSET_REF: @@ -5943,12 +5953,6 @@ instantiate_type (tree lhstype, tree rhs, tsubst_flags_t flags) /*template_only=*/false, /*explicit_targs=*/NULL_TREE); - case TREE_LIST: - /* Now we should have a baselink. */ - gcc_assert (BASELINK_P (rhs)); - - return instantiate_type (lhstype, BASELINK_FUNCTIONS (rhs), flags); - case CALL_EXPR: /* This is too hard for now. */ gcc_unreachable (); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 0f0bfb290679..f6da43c82870 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4186,7 +4186,6 @@ extern tree copy_binfo (tree, tree, tree, tree *, int); extern int member_p (tree); extern cp_lvalue_kind real_lvalue_p (tree); -extern int lvalue_or_else (tree, const char *); extern tree build_min (enum tree_code, tree, ...); extern tree build_min_nt (enum tree_code, ...); extern tree build_min_non_dep (enum tree_code, tree, ...); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 98ca4f944ad8..2085a57fff29 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1417,7 +1417,7 @@ duplicate_decls (tree newdecl, tree olddecl) error ("conflicting declaration %q#D", newdecl); cp_error_at ("%qD has a previous declaration as %q#D", olddecl, olddecl); - return NULL_TREE; + return error_mark_node; } } else if (TREE_CODE (newdecl) == FUNCTION_DECL @@ -5921,10 +5921,13 @@ grokvardecl (tree type, tree scope) { tree decl; + tree explicit_scope; gcc_assert (!name || TREE_CODE (name) == IDENTIFIER_NODE); - /* Compute the scope in which to place the variable. */ + /* Compute the scope in which to place the variable, but remember + whether or not that scope was explicitly specified by the user. */ + explicit_scope = scope; if (!scope) { /* An explicit "extern" specifier indicates a namespace-scope @@ -5949,8 +5952,8 @@ grokvardecl (tree type, else decl = build_decl (VAR_DECL, name, type); - if (scope && TREE_CODE (scope) == NAMESPACE_DECL) - set_decl_namespace (decl, scope, 0); + if (explicit_scope && TREE_CODE (explicit_scope) == NAMESPACE_DECL) + set_decl_namespace (decl, explicit_scope, 0); else DECL_CONTEXT (decl) = scope; diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index aa5e5d24454a..14c94a890449 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3114,42 +3114,46 @@ set_decl_namespace (tree decl, tree scope, bool friendp) error ("declaration of %qD not in a namespace surrounding %qD", decl, scope); DECL_CONTEXT (decl) = FROB_CONTEXT (scope); - if (scope != current_namespace) + + /* Writing "int N::i" to declare a variable within "N" is invalid. */ + if (scope == current_namespace) { - /* See whether this has been declared in the namespace. */ - old = namespace_binding (DECL_NAME (decl), scope); - if (!old) - /* No old declaration at all. */ - goto complain; - /* A template can be explicitly specialized in any namespace. */ - if (processing_explicit_instantiation) - return; - if (!is_overloaded_fn (decl)) - /* Don't compare non-function decls with decls_match here, - since it can't check for the correct constness at this - point. pushdecl will find those errors later. */ - return; - /* Since decl is a function, old should contain a function decl. */ - if (!is_overloaded_fn (old)) - goto complain; - if (processing_template_decl || processing_specialization) - /* We have not yet called push_template_decl to turn a - FUNCTION_DECL into a TEMPLATE_DECL, so the declarations - won't match. But, we'll check later, when we construct the - template. */ - return; - if (is_overloaded_fn (old)) - { - for (; old; old = OVL_NEXT (old)) - if (decls_match (decl, OVL_CURRENT (old))) - return; - } - else - if (decls_match (decl, old)) + if (at_namespace_scope_p ()) + error ("explicit qualification in declaration of `%D'", + decl); + return; + } + + /* See whether this has been declared in the namespace. */ + old = namespace_binding (DECL_NAME (decl), scope); + if (!old) + /* No old declaration at all. */ + goto complain; + /* A template can be explicitly specialized in any namespace. */ + if (processing_explicit_instantiation) + return; + if (!is_overloaded_fn (decl)) + /* Don't compare non-function decls with decls_match here, since + it can't check for the correct constness at this + point. pushdecl will find those errors later. */ + return; + /* Since decl is a function, old should contain a function decl. */ + if (!is_overloaded_fn (old)) + goto complain; + if (processing_template_decl || processing_specialization) + /* We have not yet called push_template_decl to turn a + FUNCTION_DECL into a TEMPLATE_DECL, so the declarations won't + match. But, we'll check later, when we construct the + template. */ + return; + if (is_overloaded_fn (old)) + { + for (; old; old = OVL_NEXT (old)) + if (decls_match (decl, OVL_CURRENT (old))) return; } - else - return; + else if (decls_match (decl, old)) + return; complain: error ("%qD should have been declared inside %qD", decl, scope); } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b514cc143013..cc11f364d306 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12296,6 +12296,9 @@ build_non_dependent_expr (tree expr) || TREE_CODE (inner_expr) == TEMPLATE_DECL || TREE_CODE (inner_expr) == TEMPLATE_ID_EXPR) return expr; + /* There is no need to return a proxy for a variable. */ + if (TREE_CODE (expr) == VAR_DECL) + return expr; /* Preserve string constants; conversions from string constants to "char *" are allowed, even though normally a "const char *" cannot be used to initialize a "char *". */ diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 82aebe49550e..a4b470ecda24 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -215,20 +215,6 @@ lvalue_p (tree ref) (lvalue_p_1 (ref, /*class rvalue ok*/ 1) != clk_none); } -/* Return nonzero if REF is an lvalue valid for this language; - otherwise, print an error message and return zero. */ - -int -lvalue_or_else (tree ref, const char* string) -{ - if (!lvalue_p (ref)) - { - error ("non-lvalue in %s", string); - return 0; - } - return 1; -} - /* Build a TARGET_EXPR, initializing the DECL with the VALUE. */ static tree diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 60f03c97387f..149a38896c72 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -3956,7 +3956,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) /* Complain about anything else that is not a true lvalue. */ if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) - ? "increment" : "decrement"))) + ? lv_increment : lv_decrement))) return error_mark_node; /* Forbid using -- on `bool'. */ @@ -4100,7 +4100,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) is an error. */ else if (TREE_CODE (argtype) != FUNCTION_TYPE && TREE_CODE (argtype) != METHOD_TYPE - && !lvalue_or_else (arg, "unary %<&$>")) + && !lvalue_or_else (arg, lv_addressof)) return error_mark_node; if (argtype != error_mark_node) @@ -5294,7 +5294,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs) case MAX_EXPR: /* MIN_EXPR and MAX_EXPR are currently only permitted as lvalues, when neither operand has side-effects. */ - if (!lvalue_or_else (lhs, "assignment")) + if (!lvalue_or_else (lhs, lv_assign)) return error_mark_node; gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)) @@ -5322,7 +5322,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs) /* Check this here to avoid odd errors when trying to convert a throw to the type of the COND_EXPR. */ - if (!lvalue_or_else (lhs, "assignment")) + if (!lvalue_or_else (lhs, lv_assign)) return error_mark_node; cond = build_conditional_expr @@ -5421,7 +5421,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs) } /* The left-hand side must be an lvalue. */ - if (!lvalue_or_else (lhs, "assignment")) + if (!lvalue_or_else (lhs, lv_assign)) return error_mark_node; /* Warn about modifying something that is `const'. Don't warn if @@ -6230,6 +6230,15 @@ check_return_expr (tree retval) /* Remember that this function did return a value. */ current_function_returns_value = 1; + /* Check for errnoneous operands -- but after giving ourselves a + chance to provide an error about returning a value from a void + function. */ + if (error_operand_p (retval)) + { + current_function_return_value = error_mark_node; + return error_mark_node; + } + /* Only operator new(...) throw(), can return NULL [expr.new/13]. */ if ((DECL_OVERLOADED_OPERATOR_P (current_function_decl) == NEW_EXPR || DECL_OVERLOADED_OPERATOR_P (current_function_decl) == VEC_NEW_EXPR) @@ -6305,8 +6314,8 @@ check_return_expr (tree retval) /* We don't need to do any conversions when there's nothing being returned. */ - if (!retval || retval == error_mark_node) - return retval; + if (!retval) + return NULL_TREE; /* Do any required conversions. */ if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 934cb9aa81e8..dc9628f6d612 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,20 @@ +2004-11-25 Mark Mitchell + + PR c++/18445 + * g++.dg/template/crash28.C: Likewise. + + PR c++/18001 + * g++.dg/expr/unary2.C: Adjust lvalue messages. + * g++.dg/ext/lvaddr.C: Likewise. + * g++.dg/opt/pr7503-3.C: Likewise. + + PR c++/18466 + * g++.dg/parse/qualified3.C: New test. + * g++.old-deja/g++.other/friend7.C: Remove bogus qualification. + + PR c++/18545 + * g++.dg/expr/return1.C: New test. + 2004-11-25 Kriang Lerdsuwanakij Friend class name lookup 3/n, PR c++/3332 diff --git a/gcc/testsuite/g++.dg/expr/return1.C b/gcc/testsuite/g++.dg/expr/return1.C new file mode 100644 index 000000000000..7a64988e4b32 --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/return1.C @@ -0,0 +1,9 @@ +// PR c++/18545 + +struct A; + +A foo() // { dg-error "" } +{ + A a; // { dg-error "" } + return a; +} diff --git a/gcc/testsuite/g++.dg/expr/unary2.C b/gcc/testsuite/g++.dg/expr/unary2.C index 9d6acc844883..8418815918fb 100644 --- a/gcc/testsuite/g++.dg/expr/unary2.C +++ b/gcc/testsuite/g++.dg/expr/unary2.C @@ -8,13 +8,13 @@ int n; void f(void) { - -n = 0; // { dg-error "non-lvalue" } - +n = 0; // { dg-error "non-lvalue" } + -n = 0; // { dg-error "lvalue" } + +n = 0; // { dg-error "lvalue" } } template void g(void) { - -n = 0; // { dg-error "non-lvalue" "" { xfail *-*-* } } - +n = 0; // { dg-error "non-lvalue" "" { xfail *-*-* } } + -n = 0; // { dg-error "lvalue" "" { xfail *-*-* } } + +n = 0; // { dg-error "lvalue" "" { xfail *-*-* } } } diff --git a/gcc/testsuite/g++.dg/ext/lvaddr.C b/gcc/testsuite/g++.dg/ext/lvaddr.C index 184afce900b6..5b217d165949 100644 --- a/gcc/testsuite/g++.dg/ext/lvaddr.C +++ b/gcc/testsuite/g++.dg/ext/lvaddr.C @@ -6,5 +6,5 @@ void f() { int n; - char* p = &(char) n; // { dg-error "non-lvalue" } + char* p = &(char) n; // { dg-error "lvalue" } } diff --git a/gcc/testsuite/g++.dg/opt/pr7503-3.C b/gcc/testsuite/g++.dg/opt/pr7503-3.C index ed223f4dc2c4..34d91ddb6c0d 100644 --- a/gcc/testsuite/g++.dg/opt/pr7503-3.C +++ b/gcc/testsuite/g++.dg/opt/pr7503-3.C @@ -6,21 +6,21 @@ extern int A, B; void test1() { - (A++ ? B) = 0; // { dg-error "non-lvalue in assignment" } + (A++ >? B) = 0; // { dg-error "lvalue in assignment" } } void test4() { - (A >? B++) = 0; // { dg-error "non-lvalue in assignment" } + (A >? B++) = 0; // { dg-error "lvalue in assignment" } } diff --git a/gcc/testsuite/g++.dg/parse/qualified3.C b/gcc/testsuite/g++.dg/parse/qualified3.C new file mode 100644 index 000000000000..ab160ab8db24 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/qualified3.C @@ -0,0 +1,8 @@ +// PR c++/18466 + +int ::i; // { dg-error "" } +void ::f(); // { dg-error "" } +namespace N { + int N::j; // { dg-error "" } + void N::g(); // { dg-error "" } +} diff --git a/gcc/testsuite/g++.dg/template/crash28.C b/gcc/testsuite/g++.dg/template/crash28.C new file mode 100644 index 000000000000..e8b2bbb29853 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/crash28.C @@ -0,0 +1,13 @@ +// PR c++/18445 + +struct a +{ + int what(); +}; +void g(void*); +template +void f() +{ + a ex; + g(ex.what); // { dg-error "" } +} diff --git a/gcc/testsuite/g++.old-deja/g++.other/friend7.C b/gcc/testsuite/g++.old-deja/g++.other/friend7.C index 1055d99ceae7..aed56a187ddf 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/friend7.C +++ b/gcc/testsuite/g++.old-deja/g++.other/friend7.C @@ -15,7 +15,7 @@ class S { }; } -void (::foo)(M::S *ptr) { +void (foo)(M::S *ptr) { M::S::s.Fn(); ptr->Fn(); } diff --git a/gcc/toplev.c b/gcc/toplev.c index 29ae0651426b..e2efecd563ca 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -819,6 +819,13 @@ check_global_declarations (tree *vec, int len) { decl = vec[i]; + /* Do not emit debug information about variables that are in + static storage, but not defined. */ + if (TREE_CODE (decl) == VAR_DECL + && TREE_STATIC (decl) + && !TREE_ASM_WRITTEN (decl)) + DECL_IGNORED_P (decl) = 1; + /* Warn about any function declared static but not defined. We don't warn about variables,