This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for c++/36334 and 37646
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Wed, 14 Jan 2009 22:30:25 -0500
- Subject: C++ PATCH for c++/36334 and 37646
Two different bugs where lvalue_p wasn't handling member function names
properly, at least one fallout from the fix for 28588 when we started
using BASELINKs for a reference to a static member function.
To fix this I needed to revert the const_tree changes for the lvalue_p
family of functions, since the BASELINK_FUNCTIONS macro isn't const-correct.
Tested x86_64-pc-linux-gnu, applied to trunk.
2009-01-14 Jason Merrill <jason@redhat.com>
PR c++/36334
PR c++/37646
* tree.c (lvalue_p_1): Handle BASELINK. A COMPONENT_REF to
a function isn't necessarily an lvalue. Take tree, not const_tree.
(lvalue_p, real_lvalue_p): Take tree, not const_tree.
* typeck.c (lvalue_or_else): Likewise.
* cp-tree.h: Adjust prototypes.
* g++.dg/conversion/memfn1.C: New test.
* g++.dg/conversion/memfn2.C: New test.
Index: cp/typeck.c
===================================================================
*** cp/typeck.c (revision 143386)
--- cp/typeck.c (working copy)
*************** non_reference (tree t)
*** 7339,7345 ****
how the lvalue is being used and so selects the error message. */
int
! lvalue_or_else (const_tree ref, enum lvalue_use use, tsubst_flags_t complain)
{
int win = lvalue_p (ref);
--- 7339,7345 ----
how the lvalue is being used and so selects the error message. */
int
! lvalue_or_else (tree ref, enum lvalue_use use, tsubst_flags_t complain)
{
int win = lvalue_p (ref);
Index: cp/tree.c
===================================================================
*** cp/tree.c (revision 143386)
--- cp/tree.c (working copy)
*************** static tree build_cplus_array_type_1 (tr
*** 44,50 ****
static int list_hash_eq (const void *, const void *);
static hashval_t list_hash_pieces (tree, tree, tree);
static hashval_t list_hash (const void *);
! static cp_lvalue_kind lvalue_p_1 (const_tree, int);
static tree build_target_expr (tree, tree);
static tree count_trees_r (tree *, int *, void *);
static tree verify_stmt_tree_r (tree *, int *, void *);
--- 44,50 ----
static int list_hash_eq (const void *, const void *);
static hashval_t list_hash_pieces (tree, tree, tree);
static hashval_t list_hash (const void *);
! static cp_lvalue_kind lvalue_p_1 (tree, int);
static tree build_target_expr (tree, tree);
static tree count_trees_r (tree *, int *, void *);
static tree verify_stmt_tree_r (tree *, int *, void *);
*************** static tree handle_init_priority_attribu
*** 59,65 ****
nonzero, rvalues of class type are considered lvalues. */
static cp_lvalue_kind
! lvalue_p_1 (const_tree ref,
int treat_class_rvalues_as_lvalues)
{
cp_lvalue_kind op1_lvalue_kind = clk_none;
--- 59,65 ----
nonzero, rvalues of class type are considered lvalues. */
static cp_lvalue_kind
! lvalue_p_1 (tree ref,
int treat_class_rvalues_as_lvalues)
{
cp_lvalue_kind op1_lvalue_kind = clk_none;
*************** lvalue_p_1 (const_tree ref,
*** 110,120 ****
op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
treat_class_rvalues_as_lvalues);
/* Look at the member designator. */
! if (!op1_lvalue_kind
! /* The "field" can be a FUNCTION_DECL or an OVERLOAD in some
! situations. */
! || TREE_CODE (TREE_OPERAND (ref, 1)) != FIELD_DECL)
;
else if (DECL_C_BIT_FIELD (TREE_OPERAND (ref, 1)))
{
/* Clear the ordinary bit. If this object was a class
--- 110,122 ----
op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
treat_class_rvalues_as_lvalues);
/* Look at the member designator. */
! if (!op1_lvalue_kind)
;
+ else if (is_overloaded_fn (TREE_OPERAND (ref, 1)))
+ /* The "field" can be a FUNCTION_DECL or an OVERLOAD in some
+ situations. */
+ op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
+ treat_class_rvalues_as_lvalues);
else if (DECL_C_BIT_FIELD (TREE_OPERAND (ref, 1)))
{
/* Clear the ordinary bit. If this object was a class
*************** lvalue_p_1 (const_tree ref,
*** 195,200 ****
--- 197,208 ----
return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref)
? clk_none : clk_ordinary);
+ case BASELINK:
+ /* We now represent a reference to a single static member function
+ with a BASELINK. */
+ return lvalue_p_1 (BASELINK_FUNCTIONS (ref),
+ treat_class_rvalues_as_lvalues);
+
case NON_DEPENDENT_EXPR:
/* We must consider NON_DEPENDENT_EXPRs to be lvalues so that
things like "&E" where "E" is an expression with a
*************** lvalue_p_1 (const_tree ref,
*** 227,233 ****
computes the C++ definition of lvalue. */
cp_lvalue_kind
! real_lvalue_p (const_tree ref)
{
return lvalue_p_1 (ref,
/*treat_class_rvalues_as_lvalues=*/0);
--- 235,241 ----
computes the C++ definition of lvalue. */
cp_lvalue_kind
! real_lvalue_p (tree ref)
{
return lvalue_p_1 (ref,
/*treat_class_rvalues_as_lvalues=*/0);
*************** real_lvalue_p (const_tree ref)
*** 237,243 ****
considered lvalues. */
int
! lvalue_p (const_tree ref)
{
return
(lvalue_p_1 (ref, /*class rvalue ok*/ 1) != clk_none);
--- 245,251 ----
considered lvalues. */
int
! lvalue_p (tree ref)
{
return
(lvalue_p_1 (ref, /*class rvalue ok*/ 1) != clk_none);
Index: cp/cp-tree.h
===================================================================
*** cp/cp-tree.h (revision 143386)
--- cp/cp-tree.h (working copy)
*************** extern tree canonical_type_variant (tre
*** 4836,4842 ****
extern tree copy_binfo (tree, tree, tree,
tree *, int);
extern int member_p (const_tree);
! extern cp_lvalue_kind real_lvalue_p (const_tree);
extern bool builtin_valid_in_constant_expr_p (const_tree);
extern tree build_min (enum tree_code, tree, ...);
extern tree build_min_nt (enum tree_code, ...);
--- 4836,4842 ----
extern tree copy_binfo (tree, tree, tree,
tree *, int);
extern int member_p (const_tree);
! extern cp_lvalue_kind real_lvalue_p (tree);
extern bool builtin_valid_in_constant_expr_p (const_tree);
extern tree build_min (enum tree_code, tree, ...);
extern tree build_min_nt (enum tree_code, ...);
*************** extern tree lookup_anon_field (tree, t
*** 4984,4992 ****
extern bool invalid_nonstatic_memfn_p (const_tree, tsubst_flags_t);
extern tree convert_member_func_to_ptr (tree, tree);
extern tree convert_ptrmem (tree, tree, bool, bool);
! extern int lvalue_or_else (const_tree, enum lvalue_use,
tsubst_flags_t);
! extern int lvalue_p (const_tree);
/* in typeck2.c */
extern void require_complete_eh_spec_types (tree, tree);
--- 4984,4992 ----
extern bool invalid_nonstatic_memfn_p (const_tree, tsubst_flags_t);
extern tree convert_member_func_to_ptr (tree, tree);
extern tree convert_ptrmem (tree, tree, bool, bool);
! extern int lvalue_or_else (tree, enum lvalue_use,
tsubst_flags_t);
! extern int lvalue_p (tree);
/* in typeck2.c */
extern void require_complete_eh_spec_types (tree, tree);
Index: testsuite/g++.dg/conversion/memfn1.C
===================================================================
*** testsuite/g++.dg/conversion/memfn1.C (revision 0)
--- testsuite/g++.dg/conversion/memfn1.C (revision 0)
***************
*** 0 ****
--- 1,26 ----
+ // PR c++/36334
+
+ struct X
+ {
+ typedef int* foobar();
+ static void foo(foobar&);
+ };
+
+ void X::foo(foobar&)
+ {
+ }
+
+ struct Y : public X
+ {
+ static foobar bar;
+ static void foo();
+ };
+
+ void Y::foo()
+ {
+ X::foo(bar);
+ }
+ int* Y::bar()
+ {
+ return 0;
+ }
Index: testsuite/g++.dg/conversion/memfn2.C
===================================================================
*** testsuite/g++.dg/conversion/memfn2.C (revision 0)
--- testsuite/g++.dg/conversion/memfn2.C (revision 0)
***************
*** 0 ****
--- 1,11 ----
+ // PR c++/37646
+
+ struct A
+ {
+ void foo();
+
+ void bar(int i)
+ {
+ void (*p)() = i ? foo : foo; // { dg-error "invalid use of member" }
+ }
+ };