* [Patch] PR c++/26256 @ 2010-05-11 19:44 Fabien Chêne 2010-05-16 19:20 ` Fabien Chêne 2010-06-08 21:50 ` Jason Merrill 0 siblings, 2 replies; 40+ messages in thread From: Fabien Chêne @ 2010-05-11 19:44 UTC (permalink / raw) To: gcc-patches [-- Attachment #1: Type: text/plain, Size: 1953 bytes --] Hello, Here is a patch to fix PR c++/26256, which deals with using declarations. I've tried a naive approach: basically, when a field decl is ambiguous, lookup_member (invoked with protect = 1) returns a TREE_LIST. So when we are in this case, I have implemented a lookup in the object scope, which try to disambiguate the field decl using 'using decl'. If the lookup succeeds, just return the selected field decl in the TREE_LIST. I've also implemented the dual fix for type fields. The principle is the same than above, if a field type is ambiguous, lookup_name_real returns a TREE_LIST. In this case, we have to do a lookup in the appropriate class scope, and return the selected field type in the TREE_LIST if the lookup succeds. Thought ? Bootstrapped with all default languages, tested x86_64/Linux. gcc/testsuite/ChangeLog: 2010-05-11 Fabien Chêne <fabien.chene@gmail.com> PR c++/26256 * g++.dg/lookup/using23.C: New. * g++.dg/lookup/using24.C: New. * g++.dg/lookup/using25.C: New. * g++.dg/lookup/using26.C: New. * g++.dg/lookup/using27.C: New. * g++.dg/debug/using4.C: New. * g++.dg/debug/using5.C: New. gcc/cp/ChangeLog: 2010-05-11 Fabien Chêne <fabien.chene@gmail.com> PR c++/26256 * cp-tree.h (disambiguate_with_using_decl): Declare. * name-lookup.c (disambiguate_with_using_decl): Define. Try to disambiguate a field type or a field decl with using declarations. * search.c (lookup-member): Call disambiguate_with_using_decl when a field decl is ambiguous. * parser.c (cp_parser_lookup_name): Call disambiguate_with_using_decl when a field type is ambiguous. * class.c (count_fields): Ignore using declarations. (add_fields_to_record_type): Likewise. (check_field_decls): Keep using declarations. gcc/ChangeLog: 2010-05-11 Fabien Chêne <fabien.chene@gmail.com> PR c++/26256 * dbxout.c (dbxout_type_fields): Ignore using declarations. -- Fabien [-- Attachment #2: pr26256.patch --] [-- Type: application/octet-stream, Size: 10399 bytes --] Index: gcc/testsuite/g++.dg/debug/using4.C =================================================================== --- gcc/testsuite/g++.dg/debug/using4.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using4.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + typedef char type; +}; + +struct B +{ + typedef int type; +}; + +struct C : A, B +{ + using A::type; + type f (type); +}; + +C::type C::f( type ) +{ + type c = 'e'; + return c; +} Index: gcc/testsuite/g++.dg/debug/using5.C =================================================================== --- gcc/testsuite/g++.dg/debug/using5.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using5.C (revision 0) @@ -0,0 +1,23 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using B::i; + int f (); +}; + +int C::f() +{ + return i; +} Index: gcc/testsuite/g++.dg/lookup/using24.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using24.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using24.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct ListDProto { + unsigned length(); + bool empty(); + void clear(); + void first(); + void next(); + enum Action { NORMAL, REMOVE_CURRENT }; +}; +struct SetLD: ListDProto { + void remove() + {ListDProto::Action a = this->NORMAL;} + ListDProto::length; + ListDProto::empty; + ListDProto::clear; + ListDProto::first; + ListDProto::next; + + using ListDProto::NORMAL; + using ListDProto::REMOVE_CURRENT; +}; + Index: gcc/testsuite/g++.dg/lookup/using25.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using25.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using25.C (revision 0) @@ -0,0 +1,28 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + int next; +}; + +struct B +{ + int next; +}; + +struct C : public A, public B +{ + using A::next; +}; + +void foo(C& c) { c.next = 42; } + +int main() +{ + C c; + foo (c); + c.B::next = 12; + if (c.next != 42 || c.A::next != 42 || c.B::next != 12) + __builtin_abort(); +} Index: gcc/testsuite/g++.dg/lookup/using26.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using26.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using26.C (revision 0) @@ -0,0 +1,27 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + double next; +}; + +struct B +{ +private: + int next; // { dg-error "private" } +}; + +struct C +{ + int next; +}; + +struct D : A, B, C // { dg-error "context" } +{ + using B::next; + void f() + { + next = 12; + } +}; Index: gcc/testsuite/g++.dg/lookup/using23.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using23.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using23.C (revision 0) @@ -0,0 +1,21 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ +private: + typedef int type; // { dg-error "private" } +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B // { dg-error "context" } +{ + using A::type; + type d; // { dg-error "context" } +}; + + Index: gcc/testsuite/g++.dg/lookup/using27.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using27.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using27.C (revision 0) @@ -0,0 +1,49 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + typedef int type; +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B +{ + using A::type; + type d; + + void f() + { + type e; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); + } + + void g(); +}; + +void C::g() +{ + type x; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); +} + +int main () +{ + if (sizeof (C::type) != sizeof (A::type)) + __builtin_abort(); + + if (sizeof (C::d) != sizeof (A::type)) + __builtin_abort(); + + C::type x; + C c; + c.f(); + c.g(); +} + Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 158572) +++ gcc/cp/class.c (working copy) @@ -2704,6 +2704,8 @@ count_fields (tree fields) int n_fields = 0; for (x = fields; x; x = TREE_CHAIN (x)) { + if (TREE_CODE (x) == USING_DECL) + continue; if (TREE_CODE (x) == FIELD_DECL && ANON_AGGR_TYPE_P (TREE_TYPE (x))) n_fields += count_fields (TYPE_FIELDS (TREE_TYPE (x))); else @@ -2721,6 +2723,9 @@ add_fields_to_record_type (tree fields, tree x; for (x = fields; x; x = TREE_CHAIN (x)) { + if (TREE_CODE (x) == USING_DECL) + continue; + if (TREE_CODE (x) == FIELD_DECL && ANON_AGGR_TYPE_P (TREE_TYPE (x))) idx = add_fields_to_record_type (TYPE_FIELDS (TREE_TYPE (x)), field_vec, idx); else @@ -2935,15 +2940,8 @@ check_field_decls (tree t, tree *access_ if (TREE_CODE (x) == USING_DECL) { - /* Prune the access declaration from the list of fields. */ - *field = TREE_CHAIN (x); - /* Save the access declarations for our caller. */ *access_decls = tree_cons (NULL_TREE, x, *access_decls); - - /* Since we've reset *FIELD there's no reason to skip to the - next field. */ - next = field; continue; } Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 158572) +++ gcc/cp/parser.c (working copy) @@ -1,6 +1,6 @@ /* C++ Parser. Copyright (C) 2000, 2001, 2002, 2003, 2004, - 2005, 2007, 2008, 2009 Free Software Foundation, Inc. + 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Written by Mark Mitchell <mark@codesourcery.com>. This file is part of GCC. @@ -18121,6 +18121,9 @@ cp_parser_lookup_name (cp_parser *parser if (is_template) decl = maybe_get_template_decl_from_type_decl (decl); + /* Handle using decls. */ + decl = disambiguate_with_using_decl (decl, parser->qualifying_scope); + /* If it's a TREE_LIST, the result of the lookup was ambiguous. */ if (TREE_CODE (decl) == TREE_LIST) { Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 158572) +++ gcc/cp/cp-tree.h (working copy) @@ -4648,6 +4648,7 @@ extern tree check_for_out_of_scope_varia extern void print_other_binding_stack (struct cp_binding_level *); extern tree maybe_push_decl (tree); extern tree current_decl_namespace (void); +extern tree disambiguate_with_using_decl (tree, tree); /* decl.c */ extern tree poplevel (int, int, int); Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c (revision 158572) +++ gcc/cp/search.c (working copy) @@ -1,7 +1,7 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -1225,6 +1225,17 @@ lookup_member (tree xbasetype, tree name protect = 0; } + if (protect == 1 && lfi.ambiguous) + { + tree disamb = disambiguate_with_using_decl (lfi.ambiguous, + TREE_TYPE (basetype_path)); + if (TREE_CODE (disamb) != TREE_LIST) + { + rval = disamb; + errstr = 0; + } + } + /* [class.access] In the case of overloaded function names, access control is Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 158572) +++ gcc/cp/name-lookup.c (working copy) @@ -5509,4 +5509,60 @@ cp_emit_debug_info_for_using (tree t, tr } } +/* Try to disambiguate an ambiguous DECL, with using + declarations. Returns DECL if DECL cannot be disambiguated, + otherwise returns the selected candidate (not a TREE_LIST). The + lookup is done in SCOPE if it is not a NULL_TREE, otherwise, in + current_class_type if it is not a NULL_TREE. */ +tree +disambiguate_with_using_decl (tree decl, tree scope) +{ + int candidates = 0; + tree decl_after_using = NULL_TREE; + tree field = NULL_TREE; + tree decl_scope = NULL_TREE; + + if (TREE_CODE (decl) != TREE_LIST) + return decl; + + if (scope) + decl_scope = scope; + else if (current_class_type) + decl_scope = current_class_type; + /* else if (object_scope) */ + /* decl_scope = TREE_TYPE (object_scope); */ + + if (decl_scope == NULL_TREE + || !CLASS_TYPE_P (decl_scope)) + return decl; + + for (field = TYPE_FIELDS (decl_scope); + field; + field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) == USING_DECL) + { + tree using_decl = USING_DECL_DECLS (field); + tree fn; + for (fn = decl; fn != NULL_TREE; fn = TREE_CHAIN (fn)) + { + if (same_type_p ( TREE_TYPE (TREE_VALUE (fn)), + TREE_TYPE (using_decl))) + { + decl_after_using = tree_cons (NULL_TREE, + using_decl, + decl_after_using); + ++ candidates; + break; + } + } + } + } + + if (candidates == 1) + decl = TREE_VALUE (decl_after_using); + return decl; +} + + #include "gt-cp-name-lookup.h" Index: gcc/dbxout.c =================================================================== --- gcc/dbxout.c (revision 158572) +++ gcc/dbxout.c (working copy) @@ -1,6 +1,6 @@ /* Output dbx-format symbol table information from GNU compiler. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -1431,6 +1431,8 @@ dbxout_type_fields (tree type) if (TREE_CODE (tem) == TYPE_DECL /* Omit here the nameless fields that are used to skip bits. */ || DECL_IGNORED_P (tem) + /* Omit USING_DECL */ + || TREE_CODE (tem) == USING_DECL /* Omit fields whose position or size are variable or too large to represent. */ || (TREE_CODE (tem) == FIELD_DECL ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-05-11 19:44 [Patch] PR c++/26256 Fabien Chêne @ 2010-05-16 19:20 ` Fabien Chêne 2010-06-08 21:50 ` Jason Merrill 1 sibling, 0 replies; 40+ messages in thread From: Fabien Chêne @ 2010-05-16 19:20 UTC (permalink / raw) To: gcc-patches; +Cc: Jason Merrill [-- Attachment #1: Type: text/plain, Size: 2287 bytes --] Ping ! Updated patch, which removes two commented lines. 2010/5/11 Fabien Chêne <fabien.chene@gmail.com>: > Hello, > > Here is a patch to fix PR c++/26256, which deals with using > declarations. I've tried a naive approach: basically, when a field > decl is ambiguous, lookup_member (invoked with protect = 1) returns a > TREE_LIST. So when we are in this case, I have implemented a lookup in > the object scope, which try to disambiguate the field decl using > 'using decl'. If the lookup succeeds, just return the selected field > decl in the TREE_LIST. > > I've also implemented the dual fix for type fields. The principle is > the same than above, if a field type is ambiguous, lookup_name_real > returns a TREE_LIST. In this case, we have to do a lookup in the > appropriate class scope, and return the selected field type in the > TREE_LIST if the lookup succeds. > > Thought ? > > Bootstrapped with all default languages, tested x86_64/Linux. > > gcc/testsuite/ChangeLog: > > 2010-05-11 Fabien Chêne <fabien.chene@gmail.com> > PR c++/26256 > * g++.dg/lookup/using23.C: New. > * g++.dg/lookup/using24.C: New. > * g++.dg/lookup/using25.C: New. > * g++.dg/lookup/using26.C: New. > * g++.dg/lookup/using27.C: New. > * g++.dg/debug/using4.C: New. > * g++.dg/debug/using5.C: New. > > > gcc/cp/ChangeLog: > > 2010-05-11 Fabien Chêne <fabien.chene@gmail.com> > PR c++/26256 > * cp-tree.h (disambiguate_with_using_decl): Declare. > * name-lookup.c (disambiguate_with_using_decl): Define. Try to > disambiguate a field type or a field decl with using declarations. > * search.c (lookup-member): Call disambiguate_with_using_decl when > a field decl is ambiguous. > * parser.c (cp_parser_lookup_name): Call > disambiguate_with_using_decl when a field type is ambiguous. > * class.c (count_fields): Ignore using declarations. > (add_fields_to_record_type): Likewise. > (check_field_decls): Keep using declarations. > > gcc/ChangeLog: > > 2010-05-11 Fabien Chêne <fabien.chene@gmail.com> > PR c++/26256 > * dbxout.c (dbxout_type_fields): Ignore using declarations. -- Fabien [-- Attachment #2: pr26256.patch --] [-- Type: application/octet-stream, Size: 10317 bytes --] Index: gcc/testsuite/g++.dg/debug/using4.C =================================================================== --- gcc/testsuite/g++.dg/debug/using4.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using4.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + typedef char type; +}; + +struct B +{ + typedef int type; +}; + +struct C : A, B +{ + using A::type; + type f (type); +}; + +C::type C::f( type ) +{ + type c = 'e'; + return c; +} Index: gcc/testsuite/g++.dg/debug/using5.C =================================================================== --- gcc/testsuite/g++.dg/debug/using5.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using5.C (revision 0) @@ -0,0 +1,23 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using B::i; + int f (); +}; + +int C::f() +{ + return i; +} Index: gcc/testsuite/g++.dg/lookup/using24.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using24.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using24.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct ListDProto { + unsigned length(); + bool empty(); + void clear(); + void first(); + void next(); + enum Action { NORMAL, REMOVE_CURRENT }; +}; +struct SetLD: ListDProto { + void remove() + {ListDProto::Action a = this->NORMAL;} + ListDProto::length; + ListDProto::empty; + ListDProto::clear; + ListDProto::first; + ListDProto::next; + + using ListDProto::NORMAL; + using ListDProto::REMOVE_CURRENT; +}; + Index: gcc/testsuite/g++.dg/lookup/using25.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using25.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using25.C (revision 0) @@ -0,0 +1,28 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + int next; +}; + +struct B +{ + int next; +}; + +struct C : public A, public B +{ + using A::next; +}; + +void foo(C& c) { c.next = 42; } + +int main() +{ + C c; + foo (c); + c.B::next = 12; + if (c.next != 42 || c.A::next != 42 || c.B::next != 12) + __builtin_abort(); +} Index: gcc/testsuite/g++.dg/lookup/using26.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using26.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using26.C (revision 0) @@ -0,0 +1,27 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + double next; +}; + +struct B +{ +private: + int next; // { dg-error "private" } +}; + +struct C +{ + int next; +}; + +struct D : A, B, C // { dg-error "context" } +{ + using B::next; + void f() + { + next = 12; + } +}; Index: gcc/testsuite/g++.dg/lookup/using23.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using23.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using23.C (revision 0) @@ -0,0 +1,21 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ +private: + typedef int type; // { dg-error "private" } +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B // { dg-error "context" } +{ + using A::type; + type d; // { dg-error "context" } +}; + + Index: gcc/testsuite/g++.dg/lookup/using27.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using27.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using27.C (revision 0) @@ -0,0 +1,49 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + typedef int type; +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B +{ + using A::type; + type d; + + void f() + { + type e; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); + } + + void g(); +}; + +void C::g() +{ + type x; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); +} + +int main () +{ + if (sizeof (C::type) != sizeof (A::type)) + __builtin_abort(); + + if (sizeof (C::d) != sizeof (A::type)) + __builtin_abort(); + + C::type x; + C c; + c.f(); + c.g(); +} + Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 158572) +++ gcc/cp/class.c (working copy) @@ -2704,6 +2704,8 @@ count_fields (tree fields) int n_fields = 0; for (x = fields; x; x = TREE_CHAIN (x)) { + if (TREE_CODE (x) == USING_DECL) + continue; if (TREE_CODE (x) == FIELD_DECL && ANON_AGGR_TYPE_P (TREE_TYPE (x))) n_fields += count_fields (TYPE_FIELDS (TREE_TYPE (x))); else @@ -2721,6 +2723,9 @@ add_fields_to_record_type (tree fields, tree x; for (x = fields; x; x = TREE_CHAIN (x)) { + if (TREE_CODE (x) == USING_DECL) + continue; + if (TREE_CODE (x) == FIELD_DECL && ANON_AGGR_TYPE_P (TREE_TYPE (x))) idx = add_fields_to_record_type (TYPE_FIELDS (TREE_TYPE (x)), field_vec, idx); else @@ -2935,15 +2940,8 @@ check_field_decls (tree t, tree *access_ if (TREE_CODE (x) == USING_DECL) { - /* Prune the access declaration from the list of fields. */ - *field = TREE_CHAIN (x); - /* Save the access declarations for our caller. */ *access_decls = tree_cons (NULL_TREE, x, *access_decls); - - /* Since we've reset *FIELD there's no reason to skip to the - next field. */ - next = field; continue; } Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 158572) +++ gcc/cp/parser.c (working copy) @@ -1,6 +1,6 @@ /* C++ Parser. Copyright (C) 2000, 2001, 2002, 2003, 2004, - 2005, 2007, 2008, 2009 Free Software Foundation, Inc. + 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Written by Mark Mitchell <mark@codesourcery.com>. This file is part of GCC. @@ -18121,6 +18121,9 @@ cp_parser_lookup_name (cp_parser *parser if (is_template) decl = maybe_get_template_decl_from_type_decl (decl); + /* Handle using decls. */ + decl = disambiguate_with_using_decl (decl, parser->qualifying_scope); + /* If it's a TREE_LIST, the result of the lookup was ambiguous. */ if (TREE_CODE (decl) == TREE_LIST) { Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 158572) +++ gcc/cp/cp-tree.h (working copy) @@ -4648,6 +4648,7 @@ extern tree check_for_out_of_scope_varia extern void print_other_binding_stack (struct cp_binding_level *); extern tree maybe_push_decl (tree); extern tree current_decl_namespace (void); +extern tree disambiguate_with_using_decl (tree, tree); /* decl.c */ extern tree poplevel (int, int, int); Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c (revision 158572) +++ gcc/cp/search.c (working copy) @@ -1,7 +1,7 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -1225,6 +1225,17 @@ lookup_member (tree xbasetype, tree name protect = 0; } + if (protect == 1 && lfi.ambiguous) + { + tree disamb = disambiguate_with_using_decl (lfi.ambiguous, + TREE_TYPE (basetype_path)); + if (TREE_CODE (disamb) != TREE_LIST) + { + rval = disamb; + errstr = 0; + } + } + /* [class.access] In the case of overloaded function names, access control is Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 158572) +++ gcc/cp/name-lookup.c (working copy) @@ -5509,4 +5509,58 @@ cp_emit_debug_info_for_using (tree t, tr } } +/* Try to disambiguate an ambiguous DECL, with using + declarations. Returns DECL if DECL cannot be disambiguated, + otherwise returns the selected candidate (not a TREE_LIST). The + lookup is done in SCOPE if it is not a NULL_TREE, otherwise, in + current_class_type if it is not a NULL_TREE. */ +tree +disambiguate_with_using_decl (tree decl, tree scope) +{ + int candidates = 0; + tree decl_after_using = NULL_TREE; + tree field = NULL_TREE; + tree decl_scope = NULL_TREE; + + if (TREE_CODE (decl) != TREE_LIST) + return decl; + + if (scope) + decl_scope = scope; + else if (current_class_type) + decl_scope = current_class_type; + + if (decl_scope == NULL_TREE + || !CLASS_TYPE_P (decl_scope)) + return decl; + + for (field = TYPE_FIELDS (decl_scope); + field; + field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) == USING_DECL) + { + tree using_decl = USING_DECL_DECLS (field); + tree fn; + for (fn = decl; fn != NULL_TREE; fn = TREE_CHAIN (fn)) + { + if (same_type_p ( TREE_TYPE (TREE_VALUE (fn)), + TREE_TYPE (using_decl))) + { + decl_after_using = tree_cons (NULL_TREE, + using_decl, + decl_after_using); + ++ candidates; + break; + } + } + } + } + + if (candidates == 1) + decl = TREE_VALUE (decl_after_using); + return decl; +} + + #include "gt-cp-name-lookup.h" Index: gcc/dbxout.c =================================================================== --- gcc/dbxout.c (revision 158572) +++ gcc/dbxout.c (working copy) @@ -1,6 +1,6 @@ /* Output dbx-format symbol table information from GNU compiler. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -1431,6 +1431,8 @@ dbxout_type_fields (tree type) if (TREE_CODE (tem) == TYPE_DECL /* Omit here the nameless fields that are used to skip bits. */ || DECL_IGNORED_P (tem) + /* Omit USING_DECL */ + || TREE_CODE (tem) == USING_DECL /* Omit fields whose position or size are variable or too large to represent. */ || (TREE_CODE (tem) == FIELD_DECL ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-05-11 19:44 [Patch] PR c++/26256 Fabien Chêne 2010-05-16 19:20 ` Fabien Chêne @ 2010-06-08 21:50 ` Jason Merrill 2010-06-09 9:23 ` Fabien Chêne 2010-06-16 21:21 ` Fabien Chêne 1 sibling, 2 replies; 40+ messages in thread From: Jason Merrill @ 2010-06-08 21:50 UTC (permalink / raw) To: Fabien Chêne; +Cc: gcc-patches Hunh, I thought I had reviewed this already. Sorry for the delay. > I've tried a naive approach: basically, when a field > decl is ambiguous, lookup_member (invoked with protect = 1) returns a > TREE_LIST. So when we are in this case, I have implemented a lookup in > the object scope, which try to disambiguate the field decl using > 'using decl'. If the lookup succeeds, just return the selected field > decl in the TREE_LIST. It seems like this only works if there is a using in the most derived class; a using in an intermediate class wouldn't avoid the ambiguity. I'd prefer to tear out the old access declaration code and actually handle USING_DECLs directly in lookup_field_r et al. Jason ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-06-08 21:50 ` Jason Merrill @ 2010-06-09 9:23 ` Fabien Chêne 2010-06-09 9:23 ` Fabien Chêne 2010-06-16 21:21 ` Fabien Chêne 1 sibling, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2010-06-09 9:23 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches 2010/6/8 Jason Merrill <jason@redhat.com>: > Hunh, I thought I had reviewed this already. Sorry for the delay. Do not apologize, you already did :-) I was working slowly on what you have suggested. >> I've tried a naive approach: basically, when a field >> decl is ambiguous, lookup_member (invoked with protect = 1) returns a >> TREE_LIST. So when we are in this case, I have implemented a lookup in >> the object scope, which try to disambiguate the field decl using >> 'using decl'. If the lookup succeeds, just return the selected field >> decl in the TREE_LIST. > > It seems like this only works if there is a using in the most derived class; > a using in an intermediate class wouldn't avoid the ambiguity. Yes, and I think the below code is illegal, don't you think so ? struct A { int next; }; struct B { int next; }; struct C : B { using B::next; }; struct D : A, C { // using C::next; void f() { next = 1; } }; Nevertheless, I think that it is legal if 'using C::next' is uncommented. I'll try this testcase. > I'd prefer to tear out the old access declaration code and actually handle > USING_DECLs directly in lookup_field_r et al. That's what I'm trying to do, bootstrap is OK with all default languages, and C only. Regtesting is in progress ... -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-06-09 9:23 ` Fabien Chêne @ 2010-06-09 9:23 ` Fabien Chêne 2010-06-09 12:17 ` Jason Merrill 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2010-06-09 9:23 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches 2010/6/9 Fabien Chêne <fabien.chene@gmail.com>: > 2010/6/8 Jason Merrill <jason@redhat.com>: >> Hunh, I thought I had reviewed this already. Sorry for the delay. > > Do not apologize, you already did :-) I was working slowly on what you > have suggested. > >>> I've tried a naive approach: basically, when a field >>> decl is ambiguous, lookup_member (invoked with protect = 1) returns a >>> TREE_LIST. So when we are in this case, I have implemented a lookup in >>> the object scope, which try to disambiguate the field decl using >>> 'using decl'. If the lookup succeeds, just return the selected field >>> decl in the TREE_LIST. >> >> It seems like this only works if there is a using in the most derived class; >> a using in an intermediate class wouldn't avoid the ambiguity. > > Yes, and I think the below code is illegal, don't you think so ? > > struct A { int next; }; > struct B { int next; }; > struct C : B { using B::next; }; > > struct D : A, C > { > // using C::next; > void f() { next = 1; } > }; Ah, perhaps you mean that; struct A { int next; }; struct B { int next; }; struct C : A, B { using B::next; }; struct D : C { void f() { next = 1; } }; I'll check. -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-06-09 9:23 ` Fabien Chêne @ 2010-06-09 12:17 ` Jason Merrill 0 siblings, 0 replies; 40+ messages in thread From: Jason Merrill @ 2010-06-09 12:17 UTC (permalink / raw) To: Fabien Chêne; +Cc: gcc-patches On 06/09/2010 04:44 AM, Fabien Chêne wrote: > Ah, perhaps you mean that; > > struct A { int next; }; > struct B { int next; }; > struct C : A, B { using B::next; }; > > struct D : C > { > void f() { next = 1; } > }; Right. Jason ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-06-08 21:50 ` Jason Merrill 2010-06-09 9:23 ` Fabien Chêne @ 2010-06-16 21:21 ` Fabien Chêne 2010-06-17 8:39 ` Fabien Chêne 2010-06-18 8:18 ` Jason Merrill 1 sibling, 2 replies; 40+ messages in thread From: Fabien Chêne @ 2010-06-16 21:21 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches [-- Attachment #1: Type: text/plain, Size: 2095 bytes --] Hi, Here is an updated patch that should address some (all ?) issues you have noticed. [...] > It seems like this only works if there is a using in the most derived class; > a using in an intermediate class wouldn't avoid the ambiguity. > > I'd prefer to tear out the old access declaration code and actually handle > USING_DECLs directly in lookup_field_r et al. I have moved the call to disambiguate_with_using_decl in lookup_field_r, which simplify things, thanks. disambiguate_with_using_decl has also been improved so that it can look for a using decl in an intermediate base class. Basically, it recurses on bases provided all using decl context classes are a base for the current class. [...] > @@ -1431,6 +1431,8 @@ dbxout_type_fields (tree type) > + || TREE_CODE (tem) == USING_DECL > This will break bootstrap when C++ isn't enabled. Instead, check TREE_CODE > END_OF_BASE_TREE_CODES. Sounds like it doesn't work. Instead, I've checked TREE_CODE >= LAST_AND_UNUSED_TREE_CODE. Bootstrapped with all default languages, and with C only. Tested x86_64-unknown-linux-gnu. OK for trunk ? gcc/ChangeLog 2010-06-15 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * dbxout.c (dbxout_type_fields): Ignore using declarations. gcc/testsuite/ChangeLog 2010-06-15 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * g++.dg/lookup/using23.C: New. * g++.dg/lookup/using24.C: New. * g++.dg/lookup/using25.C: New. * g++.dg/lookup/using26.C: New. * g++.dg/lookup/using27.C: New. * g++.dg/debug/using4.C: New. * g++.dg/debug/using5.C: New. gcc/cp/ChangeLog 2010-06-15 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * search.c (disambiguate_with_using_decl): Define. Try to disambiguate a field type or a field decl with using declarations. (lookup_field_r): Call disambiguate_with_using_decl when an ambiguity has been encountered. * class.c (count_fields): Ignore using declarations. (add_fields_to_record_type): Likewise. (check_field_decls): Keep using declarations. -- Fabien [-- Attachment #2: pr26256.patch --] [-- Type: application/octet-stream, Size: 9877 bytes --] Index: gcc/testsuite/g++.dg/debug/using4.C =================================================================== --- gcc/testsuite/g++.dg/debug/using4.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using4.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + typedef char type; +}; + +struct B +{ + typedef int type; +}; + +struct C : A, B +{ + using A::type; + type f (type); +}; + +C::type C::f( type ) +{ + type c = 'e'; + return c; +} Index: gcc/testsuite/g++.dg/debug/using5.C =================================================================== --- gcc/testsuite/g++.dg/debug/using5.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using5.C (revision 0) @@ -0,0 +1,23 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using B::i; + int f (); +}; + +int C::f() +{ + return i; +} Index: gcc/testsuite/g++.dg/lookup/using24.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using24.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using24.C (revision 0) @@ -0,0 +1,12 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int next; }; +struct B { int next; }; +struct C : B { using B::next; }; + +struct D : A, C +{ + using C::next; + void f() { next = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using25.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using25.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using25.C (revision 0) @@ -0,0 +1,28 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + int next; +}; + +struct B +{ + int next; +}; + +struct C : public A, public B +{ + using A::next; +}; + +void foo(C& c) { c.next = 42; } + +int main() +{ + C c; + foo (c); + c.B::next = 12; + if (c.next != 42 || c.A::next != 42 || c.B::next != 12) + __builtin_abort(); +} Index: gcc/testsuite/g++.dg/lookup/using26.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using26.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using26.C (revision 0) @@ -0,0 +1,27 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + double next; +}; + +struct B +{ +private: + int next; // { dg-error "private" } +}; + +struct C +{ + int next; +}; + +struct D : A, B, C // { dg-error "context" } +{ + using B::next; + void f() + { + next = 12; + } +}; Index: gcc/testsuite/g++.dg/lookup/using23.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using23.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using23.C (revision 0) @@ -0,0 +1,21 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ +private: + typedef int type; // { dg-error "private" } +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B // { dg-error "context" } +{ + using A::type; + type d; // { dg-error "context" } +}; + + Index: gcc/testsuite/g++.dg/lookup/using27.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using27.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using27.C (revision 0) @@ -0,0 +1,49 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + typedef int type; +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B +{ + using A::type; + type d; + + void f() + { + type e; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); + } + + void g(); +}; + +void C::g() +{ + type x; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); +} + +int main () +{ + if (sizeof (C::type) != sizeof (A::type)) + __builtin_abort(); + + if (sizeof (C::d) != sizeof (A::type)) + __builtin_abort(); + + C::type x; + C c; + c.f(); + c.g(); +} + Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 160857) +++ gcc/cp/class.c (working copy) @@ -2703,6 +2703,8 @@ count_fields (tree fields) int n_fields = 0; for (x = fields; x; x = TREE_CHAIN (x)) { + if (TREE_CODE (x) == USING_DECL) + continue; if (TREE_CODE (x) == FIELD_DECL && ANON_AGGR_TYPE_P (TREE_TYPE (x))) n_fields += count_fields (TYPE_FIELDS (TREE_TYPE (x))); else @@ -2720,6 +2722,9 @@ add_fields_to_record_type (tree fields, tree x; for (x = fields; x; x = TREE_CHAIN (x)) { + if (TREE_CODE (x) == USING_DECL) + continue; + if (TREE_CODE (x) == FIELD_DECL && ANON_AGGR_TYPE_P (TREE_TYPE (x))) idx = add_fields_to_record_type (TYPE_FIELDS (TREE_TYPE (x)), field_vec, idx); else @@ -2928,15 +2933,8 @@ check_field_decls (tree t, tree *access_ if (TREE_CODE (x) == USING_DECL) { - /* Prune the access declaration from the list of fields. */ - *field = TREE_CHAIN (x); - /* Save the access declarations for our caller. */ *access_decls = tree_cons (NULL_TREE, x, *access_decls); - - /* Since we've reset *FIELD there's no reason to skip to the - next field. */ - next = field; continue; } Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c (revision 160857) +++ gcc/cp/search.c (working copy) @@ -1,7 +1,7 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -63,6 +63,7 @@ static access_kind access_in_type (tree, static int protected_accessible_p (tree, tree, tree); static int friend_accessible_p (tree, tree, tree); static tree dfs_get_pure_virtuals (tree, void *); +static tree disambiguate_with_using_decl (tree, tree); \f /* Variables for gathering statistics. */ @@ -1086,6 +1087,7 @@ lookup_field_r (tree binfo, void *data) ; else { + tree disamb = NULL_TREE; /* We have a real ambiguity. We keep a chain of all the candidates. */ if (!lfi->ambiguous && lfi->rval) @@ -1097,10 +1099,21 @@ lookup_field_r (tree binfo, void *data) TREE_TYPE (lfi->ambiguous) = error_mark_node; } - /* Add the new value. */ - lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous); - TREE_TYPE (lfi->ambiguous) = error_mark_node; - lfi->errstr = G_("request for member %qD is ambiguous"); + /* Try to disambiguate with using decls. */ + disamb = disambiguate_with_using_decl (lfi->ambiguous, lfi->type); + if (TREE_CODE (disamb) != TREE_LIST) + { + lfi->rval = disamb; + lfi->rval_binfo = binfo; + lfi->ambiguous = NULL_TREE; + } + else + { + /* Add the new value. */ + lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous); + TREE_TYPE (lfi->ambiguous) = error_mark_node; + lfi->errstr = G_("request for member %qD is ambiguous"); + } } } else @@ -2600,3 +2613,69 @@ original_binfo (tree binfo, tree here) return result; } + +/* Try to disambiguate an ambiguous DECL, with using + declarations. Returns DECL if DECL cannot be disambiguated, + otherwise returns the selected candidate (not a TREE_LIST). The + lookup is done in SCOPE if it is not a NULL_TREE, otherwise, in + current_class_type if it is not a NULL_TREE. */ +tree +disambiguate_with_using_decl (tree decl, tree scope) +{ + int candidates_count = 0; + tree decl_after_using = NULL_TREE; + tree field = NULL_TREE; + + if (TREE_CODE (decl) != TREE_LIST + || scope == NULL_TREE + || !CLASS_TYPE_P (scope)) + return decl; + + for (field = TYPE_FIELDS (scope); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) == USING_DECL) + { + tree using_decl = USING_DECL_DECLS (field); + tree candidate; + for (candidate = decl; candidate; candidate = TREE_CHAIN (candidate)) + { + if (same_type_p ( TREE_TYPE (TREE_VALUE (candidate)), + TREE_TYPE (using_decl))) + { + decl_after_using = tree_cons (NULL_TREE, + using_decl, + decl_after_using); + ++ candidates_count; + break; + } + } + } + } + + if (candidates_count == 1) + decl = TREE_VALUE (decl_after_using); + else + { + tree binfo = TREE_CHAIN (TYPE_BINFO (scope)); + if (binfo != NULL_TREE) + { + tree candidate; + bool subobject = true; + for (candidate = decl; candidate; candidate = TREE_CHAIN (candidate)) + { + tree base = DECL_CLASS_CONTEXT (TREE_VALUE (candidate)); + if (!same_or_base_type_p (base, BINFO_TYPE (binfo))) + { + subobject = false; + break; + } + } + + if (subobject) + return disambiguate_with_using_decl (decl, BINFO_TYPE (binfo)); + } + } + return decl; +} + + Index: gcc/dbxout.c =================================================================== --- gcc/dbxout.c (revision 160857) +++ gcc/dbxout.c (working copy) @@ -1,6 +1,6 @@ /* Output dbx-format symbol table information from GNU compiler. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -1431,6 +1431,8 @@ dbxout_type_fields (tree type) if (TREE_CODE (tem) == TYPE_DECL /* Omit here the nameless fields that are used to skip bits. */ || DECL_IGNORED_P (tem) + /* Omit USING_DECL */ + || TREE_CODE (tem) >= LAST_AND_UNUSED_TREE_CODE /* Omit fields whose position or size are variable or too large to represent. */ || (TREE_CODE (tem) == FIELD_DECL ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-06-16 21:21 ` Fabien Chêne @ 2010-06-17 8:39 ` Fabien Chêne 2010-06-18 8:18 ` Jason Merrill 1 sibling, 0 replies; 40+ messages in thread From: Fabien Chêne @ 2010-06-17 8:39 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches Arf, I boostraped it again yesterday and 02.gch ICEd. The algorithm recursing on bases isn't correct, I will fix it. And ... I've also forgotten to add the testcase for intermediate bases in the patch. 2010/6/16 Fabien Chêne <fabien.chene@gmail.com>: > Hi, > > Here is an updated patch that should address some (all ?) issues you > have noticed. > > [...] >> It seems like this only works if there is a using in the most derived class; >> a using in an intermediate class wouldn't avoid the ambiguity. >> >> I'd prefer to tear out the old access declaration code and actually handle >> USING_DECLs directly in lookup_field_r et al. > > I have moved the call to disambiguate_with_using_decl in > lookup_field_r, which simplify things, thanks. > disambiguate_with_using_decl has also been improved so that it can > look for a using decl in an intermediate base class. Basically, it > recurses on bases provided all using decl context classes are a base > for the current class. > > [...] >> @@ -1431,6 +1431,8 @@ dbxout_type_fields (tree type) >> + || TREE_CODE (tem) == USING_DECL > >> This will break bootstrap when C++ isn't enabled. Instead, check TREE_CODE > END_OF_BASE_TREE_CODES. > > Sounds like it doesn't work. Instead, I've checked TREE_CODE >= > LAST_AND_UNUSED_TREE_CODE. > > Bootstrapped with all default languages, and with C only. > Tested x86_64-unknown-linux-gnu. > > OK for trunk ? > > > gcc/ChangeLog > > 2010-06-15 Fabien Chêne <fabien@gcc.gnu.org> > > PR c++/26256 > * dbxout.c (dbxout_type_fields): Ignore using declarations. > > > gcc/testsuite/ChangeLog > > 2010-06-15 Fabien Chêne <fabien@gcc.gnu.org> > > PR c++/26256 > * g++.dg/lookup/using23.C: New. > * g++.dg/lookup/using24.C: New. > * g++.dg/lookup/using25.C: New. > * g++.dg/lookup/using26.C: New. > * g++.dg/lookup/using27.C: New. > * g++.dg/debug/using4.C: New. > * g++.dg/debug/using5.C: New. > > gcc/cp/ChangeLog > > 2010-06-15 Fabien Chêne <fabien@gcc.gnu.org> > > PR c++/26256 > * search.c (disambiguate_with_using_decl): Define. Try to > disambiguate a field type or a field decl with using declarations. > (lookup_field_r): Call disambiguate_with_using_decl when an > ambiguity has been encountered. > * class.c (count_fields): Ignore using declarations. > (add_fields_to_record_type): Likewise. > (check_field_decls): Keep using declarations. > > > -- > Fabien > -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-06-16 21:21 ` Fabien Chêne 2010-06-17 8:39 ` Fabien Chêne @ 2010-06-18 8:18 ` Jason Merrill 2010-07-30 13:42 ` Fabien Chêne 1 sibling, 1 reply; 40+ messages in thread From: Jason Merrill @ 2010-06-18 8:18 UTC (permalink / raw) To: Fabien Chêne; +Cc: gcc-patches On 06/16/2010 04:30 PM, Fabien Chêne wrote: > @@ -2703,6 +2703,8 @@ count_fields (tree fields) > int n_fields = 0; > for (x = fields; x; x = TREE_CHAIN (x)) > { > + if (TREE_CODE (x) == USING_DECL) > + continue; > @@ -2720,6 +2722,9 @@ add_fields_to_record_type (tree fields, > tree x; > for (x = fields; x; x = TREE_CHAIN (x)) > { > + if (TREE_CODE (x) == USING_DECL) > + continue; I don't think we want to skip USING_DECLs here; we aren't only counting FIELD_DECLs, we count TYPE_DECLs and CONST_DECLs, too. > @@ -1097,10 +1099,21 @@ lookup_field_r (tree binfo, void *data) > TREE_TYPE (lfi->ambiguous) = error_mark_node; > } > > - /* Add the new value. */ > - lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous); > - TREE_TYPE (lfi->ambiguous) = error_mark_node; > - lfi->errstr = G_("request for member %qD is ambiguous"); > + /* Try to disambiguate with using decls. */ > + disamb = disambiguate_with_using_decl (lfi->ambiguous, lfi->type); I don't think we need a separate disambiguate_with_using_decl function at all; the point I was trying to make before is that we should be able to just treat a USING_DECL like any other decl, then pull out the decl being used in lookup_member after we return from dfs_walk_all. Jason ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-06-18 8:18 ` Jason Merrill @ 2010-07-30 13:42 ` Fabien Chêne 2010-08-18 19:29 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2010-07-30 13:42 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches Hi Jason, Hi All, 2010/6/18 Jason Merrill <jason@redhat.com>: > On 06/16/2010 04:30 PM, Fabien Chêne wrote: >> >> @@ -2703,6 +2703,8 @@ count_fields (tree fields) >> int n_fields = 0; >> for (x = fields; x; x = TREE_CHAIN (x)) >> { >> + if (TREE_CODE (x) == USING_DECL) >> + continue; >> @@ -2720,6 +2722,9 @@ add_fields_to_record_type (tree fields, >> tree x; >> for (x = fields; x; x = TREE_CHAIN (x)) >> { >> + if (TREE_CODE (x) == USING_DECL) >> + continue; > > I don't think we want to skip USING_DECLs here; we aren't only counting > FIELD_DECLs, we count TYPE_DECLs and CONST_DECLs, too. I will try to change that, but for now, it ICEs if we do not skip USING_DECLs. I'm close to the result, but I'm not sure about how should behave the compiler with the following examples. I think that in both cases, the using declaration is invalid, can you confirm that ? struct H { typedef int type; }; struct I : H { typedef int type; // { dg-message "local member" } using H::type; // { dg-error "invalid" } }; struct I2 : H { using H::type; // { dg-message "conflicting declaration" } typedef int type; // { dg-error "conflicts" } }; Same question with 'struct type {} instead of 'typedef int type' ? struct J { struct type {}; }; struct K : J { struct type {}; // { dg-message "local member" } using J::type; // { dg-error "invalid" } }; struct L : J { using J::type; // { dg-message "conflicting declaration" } struct type {}; // { dg-error "conflicts" } }; FYI, como rejects all using declarations and clang do not reject the last one (using J::type in struct L) Thanks, -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-07-30 13:42 ` Fabien Chêne @ 2010-08-18 19:29 ` Fabien Chêne 2010-08-20 23:29 ` Jason Merrill 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2010-08-18 19:29 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches [-- Attachment #1: Type: text/plain, Size: 2638 bytes --] 2010/7/30 Fabien Chêne <fabien.chene@gmail.com>: > Hi Jason, Hi All, > > 2010/6/18 Jason Merrill <jason@redhat.com>: >> On 06/16/2010 04:30 PM, Fabien Chêne wrote: >>> >>> @@ -2703,6 +2703,8 @@ count_fields (tree fields) >>> int n_fields = 0; >>> for (x = fields; x; x = TREE_CHAIN (x)) >>> { >>> + if (TREE_CODE (x) == USING_DECL) >>> + continue; >>> @@ -2720,6 +2722,9 @@ add_fields_to_record_type (tree fields, >>> tree x; >>> for (x = fields; x; x = TREE_CHAIN (x)) >>> { >>> + if (TREE_CODE (x) == USING_DECL) >>> + continue; >> >> I don't think we want to skip USING_DECLs here; we aren't only counting >> FIELD_DECLs, we count TYPE_DECLs and CONST_DECLs, too. > > I will try to change that, but for now, it ICEs if we do not skip USING_DECLs. > > I'm close to the result, but I'm not sure about how should behave the > compiler with the following examples. > I think that in both cases, the using declaration is invalid, can you > confirm that ? I've treated all of them as invalid. Here is an updated patch. The fight against the testsuite makes me go a little bit beyond the scope of PR 26256. Tested x86_64-unknown-linux-gnu with no regressions. Is it ok for trunk ? gcc/ChangeLog 2010-08-18 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * dbxout.c (dbxout_type_fields): Ignore using declarations. gcc/testsuite/ChangeLog 2010-08-18 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * g++.dg/lookup/using23.C: New. * g++.dg/lookup/using24.C: New. * g++.dg/lookup/using25.C: New. * g++.dg/lookup/using26.C: New. * g++.dg/lookup/using27.C: New. * g++.dg/lookup/using28.C: New. * g++.dg/lookup/using29.C: New. * g++.dg/debug/using4.C: New. * g++.dg/debug/using5.C: New. * g++.old-deja/g++.other/using1.C: Adjust. * g++.old-deja/g++.other/using8.C: Likewise. * g++.dg/template/using2.C: Likewise. gcc/cp/ChangeLog 2010-08-18 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * search.c (lookup_field_1): Get rid of the comment saying that USING_DECL should not be returned, and actually return USING_DECL if appropriate. * semantics.c (finish_member_declaration): Store USING_DECLs with TYPE_DECLs. * typeck.c (build_class_member_access_expr): Handle USING_DECLs. * class.c (check_field_decls): Keep using declarations and diagnose conflicting declarations involving USING_DECLs. Call diagnose_conflicting_using_decls. (diagnose_conflicting_using_decls): New function. (handle_using_decl): Tweak to make things work for g++.old-deja/g++.other/using8.C. -- Fabien [-- Attachment #2: pr26256.patch --] [-- Type: application/octet-stream, Size: 14297 bytes --] Index: gcc/testsuite/g++.old-deja/g++.other/using1.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.other/using1.C (revision 160857) +++ gcc/testsuite/g++.old-deja/g++.other/using1.C (working copy) @@ -19,9 +19,9 @@ public: class D2 : public B { // { dg-error "" } conflicting access specifications public: using B::a; - using B::b; + using B::b; // { dg-message "" } conflicting declaration private: - using B::b; + using B::b; // { dg-error "" } conflicts }; Index: gcc/testsuite/g++.old-deja/g++.other/using8.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.other/using8.C (revision 160857) +++ gcc/testsuite/g++.old-deja/g++.other/using8.C (working copy) @@ -14,10 +14,6 @@ struct A void D (); }; -struct A2 { - typedef int f; -}; - struct B : A { using A::f; Index: gcc/testsuite/g++.dg/debug/using4.C =================================================================== --- gcc/testsuite/g++.dg/debug/using4.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using4.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + typedef char type; +}; + +struct B +{ + typedef int type; +}; + +struct C : A, B +{ + using A::type; + type f (type); +}; + +C::type C::f( type ) +{ + type c = 'e'; + return c; +} Index: gcc/testsuite/g++.dg/debug/using5.C =================================================================== --- gcc/testsuite/g++.dg/debug/using5.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using5.C (revision 0) @@ -0,0 +1,23 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using B::i; + int f (); +}; + +int C::f() +{ + return i; +} Index: gcc/testsuite/g++.dg/lookup/using24.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using24.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using24.C (revision 0) @@ -0,0 +1,12 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int next; }; +struct B { int next; }; +struct C : B { using B::next; }; + +struct D : A, C +{ + using C::next; + void f() { next = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using28.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using28.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using28.C (revision 0) @@ -0,0 +1,11 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int f; }; +struct B { int f; }; +struct C : A, B { using B::f; }; + +struct D : C +{ + void g() { f = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using25.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using25.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using25.C (revision 0) @@ -0,0 +1,28 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + int next; +}; + +struct B +{ + int next; +}; + +struct C : public A, public B +{ + using A::next; +}; + +void foo(C& c) { c.next = 42; } + +int main() +{ + C c; + foo (c); + c.B::next = 12; + if (c.next != 42 || c.A::next != 42 || c.B::next != 12) + __builtin_abort(); +} Index: gcc/testsuite/g++.dg/lookup/using29.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using29.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using29.C (revision 0) @@ -0,0 +1,87 @@ +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + + +struct C : A, B +{ + using A::i; // { dg-message "conflicting using declaration" } + using B::i; // { dg-error "using declaration" } +}; + + +struct E +{ + typedef int type; +}; + +struct F +{ + typedef int type; +}; + +struct G : E, F +{ + using E::type; // { dg-message "conflicting using declaration" } + using F::type; // { dg-error "using declaration" } +}; + + +struct H +{ + typedef int type; +}; + +struct I : H +{ + typedef int type; // { dg-message "local member" } + using H::type; // { dg-error "invalid" } +}; + + +struct I2 : H +{ + using H::type; // { dg-message "conflicting using declaration" } + typedef int type; // { dg-error "conflicts" } +}; + + +struct J +{ + struct type {}; +}; + +struct K : J +{ + struct type {}; // { dg-message "local member" } + using J::type; // { dg-error "invalid" } +}; + +struct L : J +{ + using J::type; // { dg-message "conflicting using declaration" } + struct type {}; // { dg-error "conflicts" } +}; + + +struct M +{ + typedef int type; + struct type2 {}; +}; + +struct N : M +{ + using M::type; // { dg-message "conflicting using declaration" } + using M::type; // { dg-error "conflicts" } + using M::type2; // { dg-message "conflicting using declaration" } + using M::type2; // { dg-error "conflicts" } +}; Index: gcc/testsuite/g++.dg/lookup/using26.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using26.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using26.C (revision 0) @@ -0,0 +1,27 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + double next; +}; + +struct B +{ +private: + int next; // { dg-error "private" } +}; + +struct C +{ + int next; +}; + +struct D : A, B, C // { dg-error "context" } +{ + using B::next; + void f() + { + next = 12; + } +}; Index: gcc/testsuite/g++.dg/lookup/using23.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using23.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using23.C (revision 0) @@ -0,0 +1,21 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ +private: + typedef int type; // { dg-error "private" } +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B // { dg-error "context" } +{ + using A::type; + type d; // { dg-error "context" } +}; + + Index: gcc/testsuite/g++.dg/lookup/using27.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using27.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using27.C (revision 0) @@ -0,0 +1,49 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + typedef int type; +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B +{ + using A::type; + type d; + + void f() + { + type e; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); + } + + void g(); +}; + +void C::g() +{ + type x; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); +} + +int main () +{ + if (sizeof (C::type) != sizeof (A::type)) + __builtin_abort(); + + if (sizeof (C::d) != sizeof (A::type)) + __builtin_abort(); + + C::type x; + C c; + c.f(); + c.g(); +} + Index: gcc/testsuite/g++.dg/template/using2.C =================================================================== --- gcc/testsuite/g++.dg/template/using2.C (revision 160857) +++ gcc/testsuite/g++.dg/template/using2.C (working copy) @@ -7,24 +7,25 @@ template <class T> struct Foo { - int i; // { dg-error "Foo" } + int i; }; struct Baz { - int i; // { dg-error "Baz" } + int i; }; template <class T> -struct Bar : public Foo<T>, Baz { - using Foo<T>::i; - using Baz::i; +struct Bar : public Foo<T>, Baz +{ + using Foo<T>::i; // { dg-message "conflicting using declaration" } + using Baz::i; // { dg-error "conflicts" } - int foo () { return i; } // { dg-error "request for member" } + int foo () { return i; } }; void foo (Bar<int> &bar) { - bar.foo(); // { dg-message "instantiated" } + bar.foo(); } Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c (revision 160857) +++ gcc/cp/typeck.c (working copy) @@ -1,6 +1,6 @@ /* Build expressions with type checking for C++ compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) @@ -2400,6 +2400,11 @@ build_class_member_access_expr (tree obj result = build2 (COMPOUND_EXPR, TREE_TYPE (result), object, result); } + else if (TREE_CODE (member) == USING_DECL) + result = build_class_member_access_expr (object, + USING_DECL_DECLS (member), + access_path, preserve_reference, + complain); else { if (complain & tf_error) Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 160857) +++ gcc/cp/class.c (working copy) @@ -207,6 +207,7 @@ static bool base_derived_from (tree, tre static int empty_base_at_nonzero_offset_p (tree, tree, splay_tree); static tree end_of_base (tree); static tree get_vcall_index (tree, tree); +static bool diagnose_conflicting_using_decls (tree, tree, tree); /* Variables shared between class.c and call.c. */ @@ -1222,7 +1223,8 @@ handle_using_decl (tree using_decl, tree return; } } - else if (!DECL_ARTIFICIAL (old_value)) + else if (!DECL_ARTIFICIAL (old_value) + || TREE_CODE (decl) != FUNCTION_DECL) { error ("%q+D invalid in %q#T", using_decl, t); error (" because of local member %q+#D with same name", old_value); @@ -2873,6 +2875,29 @@ check_field_decl (tree field, } } +/* Issue an error if USING_DECL conflicts with a DECL already in + scope. If REAL_DECL is a using declaration, then DECL == + USING_DECL_DECLS (REAL_DECL); otherwise, DECL and USING_DECL_DECLS + are the same. */ +static bool +diagnose_conflicting_using_decls (tree decl, tree real_decl, tree using_decl) +{ + if ((TREE_CODE (decl) == FIELD_DECL + || TREE_CODE (decl) == TYPE_DECL) + && TREE_CODE (USING_DECL_DECLS (using_decl)) != FUNCTION_DECL + && DECL_NAME (decl) == DECL_NAME (using_decl)) + { + error_at (DECL_SOURCE_LOCATION (real_decl), + "declaration %qD conflicts with a using declaration " + "already in scope", real_decl); + inform (DECL_SOURCE_LOCATION (using_decl), + "conflicting using declaration %qD", using_decl); + return true; + } + return false; +} + + /* Check the data members (both static and non-static), class-scoped typedefs, etc., appearing in the declaration of T. Issue appropriate diagnostics. Sets ACCESS_DECLS to a list (in @@ -2928,15 +2953,17 @@ check_field_decls (tree t, tree *access_ if (TREE_CODE (x) == USING_DECL) { - /* Prune the access declaration from the list of fields. */ - *field = TREE_CHAIN (x); + tree f; + for (f = x; f != NULL_TREE; f = TREE_CHAIN (f)) + { + if (f != x + && !diagnose_conflicting_using_decls (f, f, x) + && TREE_CODE (f) == USING_DECL) + diagnose_conflicting_using_decls (USING_DECL_DECLS (f), f, x); + } /* Save the access declarations for our caller. */ *access_decls = tree_cons (NULL_TREE, x, *access_decls); - - /* Since we've reset *FIELD there's no reason to skip to the - next field. */ - next = field; continue; } Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 160857) +++ gcc/cp/semantics.c (working copy) @@ -2489,7 +2489,8 @@ finish_member_declaration (tree decl) also keep a pointer to the correct insertion points in the list.) */ - if (TREE_CODE (decl) == TYPE_DECL) + if (TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == USING_DECL) TYPE_FIELDS (current_class_type) = chainon (TYPE_FIELDS (current_class_type), decl); else Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c (revision 160857) +++ gcc/cp/search.c (working copy) @@ -1,7 +1,7 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -460,19 +460,18 @@ lookup_field_1 (tree type, tree name, bo if (temp) return temp; } + if (TREE_CODE (field) == USING_DECL) { - /* We generally treat class-scope using-declarations as - ARM-style access specifications, because support for the - ISO semantics has not been implemented. So, in general, - there's no reason to return a USING_DECL, and the rest of - the compiler cannot handle that. Once the class is - defined, USING_DECLs are purged from TYPE_FIELDS; see - handle_using_decl. However, we make special efforts to - make using-declarations in class templates and class - template partial specializations work correctly. */ if (!DECL_DEPENDENT_P (field)) - continue; + { + tree using_decl = USING_DECL_DECLS (field); + if ((TREE_CODE (using_decl) == FIELD_DECL + || TREE_CODE (using_decl) == TYPE_DECL) + && DECL_NAME (using_decl) == name) + return using_decl; + continue; + } } if (DECL_NAME (field) == name Index: gcc/dbxout.c =================================================================== --- gcc/dbxout.c (revision 160857) +++ gcc/dbxout.c (working copy) @@ -1,6 +1,6 @@ /* Output dbx-format symbol table information from GNU compiler. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -1431,6 +1431,8 @@ dbxout_type_fields (tree type) if (TREE_CODE (tem) == TYPE_DECL /* Omit here the nameless fields that are used to skip bits. */ || DECL_IGNORED_P (tem) + /* Omit USING_DECL */ + || TREE_CODE (tem) >= LAST_AND_UNUSED_TREE_CODE /* Omit fields whose position or size are variable or too large to represent. */ || (TREE_CODE (tem) == FIELD_DECL ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-08-18 19:29 ` Fabien Chêne @ 2010-08-20 23:29 ` Jason Merrill 2010-11-15 21:40 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Jason Merrill @ 2010-08-20 23:29 UTC (permalink / raw) To: Fabien Chêne; +Cc: gcc-patches On 08/18/2010 03:05 PM, Fabien Chêne wrote: > +diagnose_conflicting_using_decls (tree decl, tree real_decl, tree using_decl) I don't think we need to have special code to check for clashes between using decls and other decls; such collisions ought to be caught by the same code that catches two data members with the same name. It looks like this code in finish_member_declaration is preventing that: > /* Enter the DECL into the scope of the class. */ > else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) > || pushdecl_class_level (decl)) What happens if you just remove the USING_DECL check here? Perhaps the checking code in handle_using_decl is also unnecessary. Jason ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-08-20 23:29 ` Jason Merrill @ 2010-11-15 21:40 ` Fabien Chêne 2010-11-15 21:41 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2010-11-15 21:40 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches Hello, 2010/8/20 Jason Merrill <jason@redhat.com>: > On 08/18/2010 03:05 PM, Fabien Chêne wrote: >> >> +diagnose_conflicting_using_decls (tree decl, tree real_decl, tree >> using_decl) > > I don't think we need to have special code to check for clashes between > using decls and other decls; such collisions ought to be caught by the same > code that catches two data members with the same name. It looks like this > code in finish_member_declaration is preventing that: > >> /* Enter the DECL into the scope of the class. */ >> else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) >> || pushdecl_class_level (decl)) > > What happens if you just remove the USING_DECL check here? Sounds like it was the right thing to do. I have had to modify a bit the parser in order to handle USING_DECLs. I also have modified supplement_binding() to handle USING_DECLs. It is a bit touchy, but it seems to work well. Please also double check that lookup/using31.C is correct, I am not sure. > Perhaps the checking code in handle_using_decl is also unnecessary. Definitely. Regtested x86_64-unknown-linux-gnu without regressions on an old tree. Regtesting in progress on a fresh tree. OK to commit if it succeeds ? gcc/ChangeLog 2010-11-15 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * dbxout.c (dbxout_type_fields): Ignore using declarations. gcc/testsuite/ChangeLog 2010-11-15 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * g++.dg/lookup/using23.C: New. * g++.dg/lookup/using24.C: New. * g++.dg/lookup/using25.C: New. * g++.dg/lookup/using26.C: New. * g++.dg/lookup/using27.C: New. * g++.dg/lookup/using28.C: New. * g++.dg/lookup/using29.C: New. * g++.dg/lookup/using30.C: New. * g++.dg/lookup/using31.C: New. * g++.dg/lookup/using32.C: New. * g++.dg/lookup/using33.C: New. * g++.dg/lookup/using34.C: New. * g++.dg/debug/using4.C: New. * g++.dg/debug/using5.C: New. * g++.old-deja/g++.other/using1.C: Adjust. * g++.dg/template/using2.C: Likewise. gcc/cp/ChangeLog 2010-11-15 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * search.c (lookup_field_1): Get rid of the comment saying that USING_DECL should not be returned, and actually return USING_DECL if appropriate. * semantics.c (finish_member_declaration): Remove the check that prevents USING_DECLs from being verified by pushdecl_class_level. * typeck.c (build_class_member_access_expr): Handle USING_DECLs. * class.c (check_field_decls): Keep using declarations. * parser.c (cp_parser_nonclass_name): Handle USING_DECLs. * name-lookup.c (supplement_binding): Extend the `struct stat' hack to handle using declarations. (push_class_level_binding): Returns early for dependent USING_DECLs and for USING_DECLs that refers to FUNCTION_DECL. -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-11-15 21:40 ` Fabien Chêne @ 2010-11-15 21:41 ` Fabien Chêne 2010-11-17 11:25 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2010-11-15 21:41 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches [-- Attachment #1: Type: text/plain, Size: 3287 bytes --] ... And the patch. 2010/11/15 Fabien Chêne <fabien.chene@gmail.com>: > Hello, > > 2010/8/20 Jason Merrill <jason@redhat.com>: >> On 08/18/2010 03:05 PM, Fabien Chêne wrote: >>> >>> +diagnose_conflicting_using_decls (tree decl, tree real_decl, tree >>> using_decl) >> >> I don't think we need to have special code to check for clashes between >> using decls and other decls; such collisions ought to be caught by the same >> code that catches two data members with the same name. It looks like this >> code in finish_member_declaration is preventing that: >> >>> /* Enter the DECL into the scope of the class. */ >>> else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) >>> || pushdecl_class_level (decl)) >> >> What happens if you just remove the USING_DECL check here? > > Sounds like it was the right thing to do. I have had to modify a bit > the parser in order to handle USING_DECLs. > I also have modified supplement_binding() to handle USING_DECLs. It is > a bit touchy, but it seems to work well. > Please also double check that lookup/using31.C is correct, I am not sure. > >> Perhaps the checking code in handle_using_decl is also unnecessary. > > Definitely. > > Regtested x86_64-unknown-linux-gnu without regressions on an old tree. > Regtesting in progress on a fresh tree. > OK to commit if it succeeds ? > > gcc/ChangeLog > > 2010-11-15 Fabien Chêne <fabien@gcc.gnu.org> > > PR c++/26256 > * dbxout.c (dbxout_type_fields): Ignore using declarations. > > > gcc/testsuite/ChangeLog > > 2010-11-15 Fabien Chêne <fabien@gcc.gnu.org> > > PR c++/26256 > * g++.dg/lookup/using23.C: New. > * g++.dg/lookup/using24.C: New. > * g++.dg/lookup/using25.C: New. > * g++.dg/lookup/using26.C: New. > * g++.dg/lookup/using27.C: New. > * g++.dg/lookup/using28.C: New. > * g++.dg/lookup/using29.C: New. > * g++.dg/lookup/using30.C: New. > * g++.dg/lookup/using31.C: New. > * g++.dg/lookup/using32.C: New. > * g++.dg/lookup/using33.C: New. > * g++.dg/lookup/using34.C: New. > * g++.dg/debug/using4.C: New. > * g++.dg/debug/using5.C: New. > * g++.old-deja/g++.other/using1.C: Adjust. > * g++.dg/template/using2.C: Likewise. > > gcc/cp/ChangeLog > > 2010-11-15 Fabien Chêne <fabien@gcc.gnu.org> > > PR c++/26256 > * search.c (lookup_field_1): Get rid of the comment saying that > USING_DECL should not be returned, and actually return USING_DECL > if appropriate. > * semantics.c (finish_member_declaration): Remove the check that > prevents USING_DECLs from being verified by pushdecl_class_level. > * typeck.c (build_class_member_access_expr): Handle USING_DECLs. > * class.c (check_field_decls): Keep using declarations. > * parser.c (cp_parser_nonclass_name): Handle USING_DECLs. > * name-lookup.c (supplement_binding): Extend the `struct stat' > hack to handle using declarations. > (push_class_level_binding): Returns early for dependent USING_DECLs > and for USING_DECLs that refers to FUNCTION_DECL. > > -- > Fabien > -- Fabien [-- Attachment #2: pr26256.patch --] [-- Type: application/octet-stream, Size: 16349 bytes --] Index: gcc/testsuite/g++.old-deja/g++.other/using1.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.other/using1.C (revision 166743) +++ gcc/testsuite/g++.old-deja/g++.other/using1.C (working copy) @@ -16,12 +16,12 @@ public: using B::b; }; -class D2 : public B { // { dg-error "" } conflicting access specifications +class D2 : public B { public: using B::a; - using B::b; + using B::b; // { dg-message "" } conflicting declaration private: - using B::b; + using B::b; // { dg-error "" } conflicts }; Index: gcc/testsuite/g++.dg/debug/using4.C =================================================================== --- gcc/testsuite/g++.dg/debug/using4.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using4.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + typedef char type; +}; + +struct B +{ + typedef int type; +}; + +struct C : A, B +{ + using A::type; + type f (type); +}; + +C::type C::f( type ) +{ + type c = 'e'; + return c; +} Index: gcc/testsuite/g++.dg/debug/using5.C =================================================================== --- gcc/testsuite/g++.dg/debug/using5.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using5.C (revision 0) @@ -0,0 +1,23 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using B::i; + int f (); +}; + +int C::f() +{ + return i; +} Index: gcc/testsuite/g++.dg/lookup/using24.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using24.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using24.C (revision 0) @@ -0,0 +1,12 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int next; }; +struct B { int next; }; +struct C : B { using B::next; }; + +struct D : A, C +{ + using C::next; + void f() { next = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using28.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using28.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using28.C (revision 0) @@ -0,0 +1,11 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int f; }; +struct B { int f; }; +struct C : A, B { using B::f; }; + +struct D : C +{ + void g() { f = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using33.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using33.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using33.C (revision 0) @@ -0,0 +1,26 @@ +// { dg-do run } + +template <class T> +struct Foo +{ + int k (float) {return 0;} +}; + +template <class T> +struct Baz +{ + int k (int) {return 1;} +}; + +template <class T> +struct Bar : Foo<T> , Baz<T> +{ + using Foo<T>::k; + using Baz<T>::k; +}; + +int main() +{ + Bar<int> bar; + return bar.k( 1.0f ); +} Index: gcc/testsuite/g++.dg/lookup/using25.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using25.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using25.C (revision 0) @@ -0,0 +1,28 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + int next; +}; + +struct B +{ + int next; +}; + +struct C : public A, public B +{ + using A::next; +}; + +void foo(C& c) { c.next = 42; } + +int main() +{ + C c; + foo (c); + c.B::next = 12; + if (c.next != 42 || c.A::next != 42 || c.B::next != 12) + __builtin_abort(); +} Index: gcc/testsuite/g++.dg/lookup/using29.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using29.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using29.C (revision 0) @@ -0,0 +1,88 @@ +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + + +struct C : A, B +{ + using A::i; // { dg-error "conflicts with previous" } + using B::i; // { dg-error "declaration" } +}; + + +struct E +{ + typedef int type; +}; + +struct F +{ + typedef int type; +}; + +struct G : E, F +{ + using E::type; // { dg-error "conflicts with previous" } + using F::type; // { dg-error "declaration" } +}; + + +struct H +{ + typedef int type; +}; + +struct I : H +{ + typedef int type; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; + + +struct I2 : H +{ + using H::type; // { dg-error "conflicts with previous" } + typedef int type; // { dg-error "declaration" } +}; + + +struct J +{ + struct type {}; +}; + +struct K : J +{ + struct type {}; // { dg-error "conflicts with previous" } + using J::type; // { dg-error "declaration" } +}; + +struct L : J +{ + using J::type; // { dg-error "conflicts with previous" } + struct type {}; // { dg-error "declaration" } +}; + + +struct M +{ + typedef int type; + struct type2 {}; +}; + +struct N : M +{ + using M::type; // { dg-error "conflicts with previous" } + using M::type; // { dg-error "declaration" } + using M::type2; // { dg-error "conflicts with previous" } + using M::type2; // { dg-error "declaration" } +}; + Index: gcc/testsuite/g++.dg/lookup/using30.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using30.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using30.C (revision 0) @@ -0,0 +1,17 @@ +// { dg-do compile } + +struct H +{ + typedef int type; +}; + + +struct J : H +{ + struct type {}; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; + + + + Index: gcc/testsuite/g++.dg/lookup/using34.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using34.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using34.C (revision 0) @@ -0,0 +1,15 @@ +// { dg-do compile } + +struct A +{ + int f (); +}; + +struct B : A +{ + using A::f; + struct f {}; + void g() { f(); struct f ff; } + struct f ff; +}; + Index: gcc/testsuite/g++.dg/lookup/using26.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using26.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using26.C (revision 0) @@ -0,0 +1,27 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + double next; +}; + +struct B +{ +private: + int next; // { dg-error "private" } +}; + +struct C +{ + int next; +}; + +struct D : A, B, C // { dg-error "context" } +{ + using B::next; + void f() + { + next = 12; + } +}; Index: gcc/testsuite/g++.dg/lookup/using31.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using31.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using31.C (revision 0) @@ -0,0 +1,12 @@ +// { dg-do compile } + +struct H2 +{ + int f (); +}; + +struct J2 : H2 +{ + struct f {}; // { dg-error "conflicts with previous" } + using H2::f; // { dg-error "declaration" } +}; Index: gcc/testsuite/g++.dg/lookup/using23.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using23.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using23.C (revision 0) @@ -0,0 +1,19 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ +private: + typedef int type; // { dg-error "private" } +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B // { dg-error "context" } +{ + using A::type; + type d; +}; Index: gcc/testsuite/g++.dg/lookup/using27.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using27.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using27.C (revision 0) @@ -0,0 +1,49 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + typedef int type; +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B +{ + using A::type; + type d; + + void f() + { + type e; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); + } + + void g(); +}; + +void C::g() +{ + type x; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); +} + +int main () +{ + if (sizeof (C::type) != sizeof (A::type)) + __builtin_abort(); + + if (sizeof (C::d) != sizeof (A::type)) + __builtin_abort(); + + C::type x; + C c; + c.f(); + c.g(); +} + Index: gcc/testsuite/g++.dg/lookup/using32.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using32.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using32.C (revision 0) @@ -0,0 +1,17 @@ +// { dg-do compile } + +struct T +{ + struct type {}; +}; + +struct T2 : T +{ + using T::type; +}; + +struct T3 : T2 +{ + struct type {}; + type t; +}; Index: gcc/testsuite/g++.dg/inherit/using4.C =================================================================== --- gcc/testsuite/g++.dg/inherit/using4.C (revision 166743) +++ gcc/testsuite/g++.dg/inherit/using4.C (working copy) @@ -9,6 +9,6 @@ struct B { }; struct D : B { - using B::f; + using B::f; using B::f; // { dg-error "repeated" } }; Index: gcc/testsuite/g++.dg/template/using2.C =================================================================== --- gcc/testsuite/g++.dg/template/using2.C (revision 166743) +++ gcc/testsuite/g++.dg/template/using2.C (working copy) @@ -7,24 +7,25 @@ template <class T> struct Foo { - int i; // { dg-error "Foo" } + int i; }; struct Baz { - int i; // { dg-error "Baz" } + int i; }; template <class T> -struct Bar : public Foo<T>, Baz { - using Foo<T>::i; - using Baz::i; +struct Bar : public Foo<T>, Baz +{ + using Foo<T>::i; // { dg-message "conflicts with previous" } + using Baz::i; // { dg-error "declaration" } - int foo () { return i; } // { dg-error "request for member" } + int foo () { return i; } }; void foo (Bar<int> &bar) { - bar.foo(); // { dg-message "instantiated" } + bar.foo(); } Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c (revision 166743) +++ gcc/cp/typeck.c (working copy) @@ -2340,6 +2340,11 @@ build_class_member_access_expr (tree obj result = build2 (COMPOUND_EXPR, TREE_TYPE (result), object, result); } + else if (TREE_CODE (member) == USING_DECL) + result = build_class_member_access_expr (object, + USING_DECL_DECLS (member), + access_path, preserve_reference, + complain); else { if (complain & tf_error) Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 166743) +++ gcc/cp/class.c (working copy) @@ -2990,15 +2990,8 @@ check_field_decls (tree t, tree *access_ if (TREE_CODE (x) == USING_DECL) { - /* Prune the access declaration from the list of fields. */ - *field = DECL_CHAIN (x); - /* Save the access declarations for our caller. */ *access_decls = tree_cons (NULL_TREE, x, *access_decls); - - /* Since we've reset *FIELD there's no reason to skip to the - next field. */ - next = field; continue; } Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 166743) +++ gcc/cp/semantics.c (working copy) @@ -2522,8 +2522,7 @@ finish_member_declaration (tree decl) } } /* Enter the DECL into the scope of the class. */ - else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) - || pushdecl_class_level (decl)) + else if (pushdecl_class_level (decl)) { /* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields go at the beginning. The reason is that lookup_field_1 Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 166743) +++ gcc/cp/parser.c (working copy) @@ -12911,6 +12911,10 @@ cp_parser_nonclass_name (cp_parser* pars /* Look up the type-name. */ type_decl = cp_parser_lookup_name_simple (parser, identifier, token->location); + /* If it is a using decl, use its underlying decl. */ + if (TREE_CODE (type_decl) == USING_DECL && !DECL_DEPENDENT_P (type_decl)) + type_decl = USING_DECL_DECLS (type_decl); + if (TREE_CODE (type_decl) != TYPE_DECL && (objc_is_id (identifier) || objc_is_class_name (identifier))) { Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c (revision 166743) +++ gcc/cp/search.c (working copy) @@ -1,7 +1,7 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -462,17 +462,15 @@ lookup_field_1 (tree type, tree name, bo } if (TREE_CODE (field) == USING_DECL) { - /* We generally treat class-scope using-declarations as - ARM-style access specifications, because support for the - ISO semantics has not been implemented. So, in general, - there's no reason to return a USING_DECL, and the rest of - the compiler cannot handle that. Once the class is - defined, USING_DECLs are purged from TYPE_FIELDS; see - handle_using_decl. However, we make special efforts to - make using-declarations in class templates and class - template partial specializations work correctly. */ if (!DECL_DEPENDENT_P (field)) - continue; + { + tree using_decl = USING_DECL_DECLS (field); + if ((TREE_CODE (using_decl) == FIELD_DECL + || TREE_CODE (using_decl) == TYPE_DECL) + && DECL_NAME (using_decl) == name) + return using_decl; + continue; + } } if (DECL_NAME (field) == name Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 166743) +++ gcc/cp/name-lookup.c (working copy) @@ -439,7 +439,10 @@ supplement_binding (cxx_binding *binding bool ok = true; timevar_push (TV_NAME_LOOKUP); - if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) + if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl) + && (TREE_CODE (bval) != USING_DECL + || (!DECL_DEPENDENT_P (bval) + && (TREE_CODE (USING_DECL_DECLS (bval)) != TYPE_DECL)))) /* The new name is the type name. */ binding->type = decl; else if (/* BVAL is null when push_class_level_binding moves an @@ -458,7 +461,8 @@ supplement_binding (cxx_binding *binding && DECL_ANTICIPATED (bval) && !DECL_HIDDEN_FRIEND_P (bval))) binding->value = decl; - else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval)) + else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval) + && TREE_CODE (decl) != USING_DECL) { /* The old binding was a type name. It was placed in VALUE field because it was thought, at the point it was @@ -2910,7 +2914,15 @@ push_class_level_binding (tree name, tre else if (TREE_CODE (x) == OVERLOAD && is_overloaded_fn (bval)) old_decl = bval; else if (TREE_CODE (x) == USING_DECL && TREE_CODE (bval) == USING_DECL) - POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true); + { + if (DECL_DEPENDENT_P (x) + || TREE_CODE (USING_DECL_DECLS (x)) == FUNCTION_DECL) + POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true); + + if (DECL_DEPENDENT_P (bval) + || TREE_CODE (USING_DECL_DECLS (bval)) == FUNCTION_DECL) + POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true); + } else if (TREE_CODE (x) == USING_DECL && is_overloaded_fn (bval)) old_decl = bval; else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (x)) Index: gcc/dbxout.c =================================================================== --- gcc/dbxout.c (revision 166743) +++ gcc/dbxout.c (working copy) @@ -1437,6 +1437,8 @@ dbxout_type_fields (tree type) if (TREE_CODE (tem) == TYPE_DECL /* Omit here the nameless fields that are used to skip bits. */ || DECL_IGNORED_P (tem) + /* Omit USING_DECL */ + || TREE_CODE (tem) >= LAST_AND_UNUSED_TREE_CODE /* Omit fields whose position or size are variable or too large to represent. */ || (TREE_CODE (tem) == FIELD_DECL ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-11-15 21:41 ` Fabien Chêne @ 2010-11-17 11:25 ` Fabien Chêne 2010-12-20 16:51 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2010-11-17 11:25 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches 2010/11/15 Fabien Chêne <fabien.chene@gmail.com>: [...] Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c (revision 166743) +++ gcc/cp/typeck.c (working copy) @@ -2340,6 +2340,11 @@ build_class_member_access_expr (tree obj result = build2 (COMPOUND_EXPR, TREE_TYPE (result), object, result); } + else if (TREE_CODE (member) == USING_DECL) + result = build_class_member_access_expr (object, + USING_DECL_DECLS (member), + access_path, preserve_reference, + complain); I guess it would be safer to also check !DECL_DEPENDENT_P (member), I will update the patch. -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-11-17 11:25 ` Fabien Chêne @ 2010-12-20 16:51 ` Fabien Chêne 2010-12-22 23:10 ` Jason Merrill 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2010-12-20 16:51 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches [-- Attachment #1: Type: text/plain, Size: 1042 bytes --] 2010/11/17 Fabien Chêne <fabien.chene@gmail.com>: > 2010/11/15 Fabien Chêne <fabien.chene@gmail.com>: > [...] > > Index: gcc/cp/typeck.c > =================================================================== > --- gcc/cp/typeck.c (revision 166743) > +++ gcc/cp/typeck.c (working copy) > @@ -2340,6 +2340,11 @@ build_class_member_access_expr (tree obj > result = build2 (COMPOUND_EXPR, TREE_TYPE (result), > object, result); > } > + else if (TREE_CODE (member) == USING_DECL) > + result = build_class_member_access_expr (object, > + USING_DECL_DECLS (member), > + access_path, preserve_reference, > + complain); > > I guess it would be safer to also check !DECL_DEPENDENT_P (member), I > will update the patch. Done in the attached patch, no regressions on x86_64-unknown-linux-gnu. OK to queue it for next stage 1 ? -- Fabien [-- Attachment #2: pr26256.patch --] [-- Type: application/octet-stream, Size: 16017 bytes --] Index: gcc/testsuite/g++.old-deja/g++.other/using1.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.other/using1.C (revision 166743) +++ gcc/testsuite/g++.old-deja/g++.other/using1.C (working copy) @@ -16,12 +16,12 @@ public: using B::b; }; -class D2 : public B { // { dg-error "" } conflicting access specifications +class D2 : public B { public: using B::a; - using B::b; + using B::b; // { dg-message "" } conflicting declaration private: - using B::b; + using B::b; // { dg-error "" } conflicts }; Index: gcc/testsuite/g++.dg/debug/using4.C =================================================================== --- gcc/testsuite/g++.dg/debug/using4.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using4.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + typedef char type; +}; + +struct B +{ + typedef int type; +}; + +struct C : A, B +{ + using A::type; + type f (type); +}; + +C::type C::f( type ) +{ + type c = 'e'; + return c; +} Index: gcc/testsuite/g++.dg/debug/using5.C =================================================================== --- gcc/testsuite/g++.dg/debug/using5.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using5.C (revision 0) @@ -0,0 +1,23 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using B::i; + int f (); +}; + +int C::f() +{ + return i; +} Index: gcc/testsuite/g++.dg/lookup/using24.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using24.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using24.C (revision 0) @@ -0,0 +1,12 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int next; }; +struct B { int next; }; +struct C : B { using B::next; }; + +struct D : A, C +{ + using C::next; + void f() { next = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using28.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using28.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using28.C (revision 0) @@ -0,0 +1,11 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int f; }; +struct B { int f; }; +struct C : A, B { using B::f; }; + +struct D : C +{ + void g() { f = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using33.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using33.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using33.C (revision 0) @@ -0,0 +1,26 @@ +// { dg-do run } + +template <class T> +struct Foo +{ + int k (float) {return 0;} +}; + +template <class T> +struct Baz +{ + int k (int) {return 1;} +}; + +template <class T> +struct Bar : Foo<T> , Baz<T> +{ + using Foo<T>::k; + using Baz<T>::k; +}; + +int main() +{ + Bar<int> bar; + return bar.k( 1.0f ); +} Index: gcc/testsuite/g++.dg/lookup/using25.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using25.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using25.C (revision 0) @@ -0,0 +1,28 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + int next; +}; + +struct B +{ + int next; +}; + +struct C : public A, public B +{ + using A::next; +}; + +void foo(C& c) { c.next = 42; } + +int main() +{ + C c; + foo (c); + c.B::next = 12; + if (c.next != 42 || c.A::next != 42 || c.B::next != 12) + __builtin_abort(); +} Index: gcc/testsuite/g++.dg/lookup/using29.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using29.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using29.C (revision 0) @@ -0,0 +1,88 @@ +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + + +struct C : A, B +{ + using A::i; // { dg-error "conflicts with previous" } + using B::i; // { dg-error "declaration" } +}; + + +struct E +{ + typedef int type; +}; + +struct F +{ + typedef int type; +}; + +struct G : E, F +{ + using E::type; // { dg-error "conflicts with previous" } + using F::type; // { dg-error "declaration" } +}; + + +struct H +{ + typedef int type; +}; + +struct I : H +{ + typedef int type; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; + + +struct I2 : H +{ + using H::type; // { dg-error "conflicts with previous" } + typedef int type; // { dg-error "declaration" } +}; + + +struct J +{ + struct type {}; +}; + +struct K : J +{ + struct type {}; // { dg-error "conflicts with previous" } + using J::type; // { dg-error "declaration" } +}; + +struct L : J +{ + using J::type; // { dg-error "conflicts with previous" } + struct type {}; // { dg-error "declaration" } +}; + + +struct M +{ + typedef int type; + struct type2 {}; +}; + +struct N : M +{ + using M::type; // { dg-error "conflicts with previous" } + using M::type; // { dg-error "declaration" } + using M::type2; // { dg-error "conflicts with previous" } + using M::type2; // { dg-error "declaration" } +}; + Index: gcc/testsuite/g++.dg/lookup/using30.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using30.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using30.C (revision 0) @@ -0,0 +1,17 @@ +// { dg-do compile } + +struct H +{ + typedef int type; +}; + + +struct J : H +{ + struct type {}; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; + + + + Index: gcc/testsuite/g++.dg/lookup/using34.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using34.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using34.C (revision 0) @@ -0,0 +1,15 @@ +// { dg-do compile } + +struct A +{ + int f (); +}; + +struct B : A +{ + using A::f; + struct f {}; + void g() { f(); struct f ff; } + struct f ff; +}; + Index: gcc/testsuite/g++.dg/lookup/using26.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using26.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using26.C (revision 0) @@ -0,0 +1,27 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + double next; +}; + +struct B +{ +private: + int next; // { dg-error "private" } +}; + +struct C +{ + int next; +}; + +struct D : A, B, C // { dg-error "context" } +{ + using B::next; + void f() + { + next = 12; + } +}; Index: gcc/testsuite/g++.dg/lookup/using31.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using31.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using31.C (revision 0) @@ -0,0 +1,12 @@ +// { dg-do compile } + +struct H2 +{ + int f (); +}; + +struct J2 : H2 +{ + struct f {}; // { dg-error "conflicts with previous" } + using H2::f; // { dg-error "declaration" } +}; Index: gcc/testsuite/g++.dg/lookup/using23.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using23.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using23.C (revision 0) @@ -0,0 +1,19 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ +private: + typedef int type; // { dg-error "private" } +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B // { dg-error "context" } +{ + using A::type; + type d; +}; Index: gcc/testsuite/g++.dg/lookup/using27.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using27.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using27.C (revision 0) @@ -0,0 +1,49 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + typedef int type; +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B +{ + using A::type; + type d; + + void f() + { + type e; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); + } + + void g(); +}; + +void C::g() +{ + type x; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); +} + +int main () +{ + if (sizeof (C::type) != sizeof (A::type)) + __builtin_abort(); + + if (sizeof (C::d) != sizeof (A::type)) + __builtin_abort(); + + C::type x; + C c; + c.f(); + c.g(); +} + Index: gcc/testsuite/g++.dg/lookup/using32.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using32.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using32.C (revision 0) @@ -0,0 +1,17 @@ +// { dg-do compile } + +struct T +{ + struct type {}; +}; + +struct T2 : T +{ + using T::type; +}; + +struct T3 : T2 +{ + struct type {}; + type t; +}; Index: gcc/testsuite/g++.dg/template/using2.C =================================================================== --- gcc/testsuite/g++.dg/template/using2.C (revision 166743) +++ gcc/testsuite/g++.dg/template/using2.C (working copy) @@ -7,24 +7,25 @@ template <class T> struct Foo { - int i; // { dg-error "Foo" } + int i; }; struct Baz { - int i; // { dg-error "Baz" } + int i; }; template <class T> -struct Bar : public Foo<T>, Baz { - using Foo<T>::i; - using Baz::i; +struct Bar : public Foo<T>, Baz +{ + using Foo<T>::i; // { dg-message "conflicts with previous" } + using Baz::i; // { dg-error "declaration" } - int foo () { return i; } // { dg-error "request for member" } + int foo () { return i; } }; void foo (Bar<int> &bar) { - bar.foo(); // { dg-message "instantiated" } + bar.foo(); } Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c (revision 166743) +++ gcc/cp/typeck.c (working copy) @@ -2340,6 +2340,11 @@ build_class_member_access_expr (tree obj result = build2 (COMPOUND_EXPR, TREE_TYPE (result), object, result); } + else if (TREE_CODE (member) == USING_DECL && !DECL_DEPENDENT_P (member)) + result = build_class_member_access_expr (object, + USING_DECL_DECLS (member), + access_path, preserve_reference, + complain); else { if (complain & tf_error) Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 166743) +++ gcc/cp/class.c (working copy) @@ -2990,15 +2990,8 @@ check_field_decls (tree t, tree *access_ if (TREE_CODE (x) == USING_DECL) { - /* Prune the access declaration from the list of fields. */ - *field = DECL_CHAIN (x); - /* Save the access declarations for our caller. */ *access_decls = tree_cons (NULL_TREE, x, *access_decls); - - /* Since we've reset *FIELD there's no reason to skip to the - next field. */ - next = field; continue; } Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 166743) +++ gcc/cp/semantics.c (working copy) @@ -2522,8 +2522,7 @@ finish_member_declaration (tree decl) } } /* Enter the DECL into the scope of the class. */ - else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) - || pushdecl_class_level (decl)) + else if (pushdecl_class_level (decl)) { /* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields go at the beginning. The reason is that lookup_field_1 Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 166743) +++ gcc/cp/parser.c (working copy) @@ -12911,6 +12911,10 @@ cp_parser_nonclass_name (cp_parser* pars /* Look up the type-name. */ type_decl = cp_parser_lookup_name_simple (parser, identifier, token->location); + /* If it is a using decl, use its underlying decl. */ + if (TREE_CODE (type_decl) == USING_DECL && !DECL_DEPENDENT_P (type_decl)) + type_decl = USING_DECL_DECLS (type_decl); + if (TREE_CODE (type_decl) != TYPE_DECL && (objc_is_id (identifier) || objc_is_class_name (identifier))) { Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c (revision 166743) +++ gcc/cp/search.c (working copy) @@ -1,7 +1,7 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -462,17 +462,15 @@ lookup_field_1 (tree type, tree name, bo } if (TREE_CODE (field) == USING_DECL) { - /* We generally treat class-scope using-declarations as - ARM-style access specifications, because support for the - ISO semantics has not been implemented. So, in general, - there's no reason to return a USING_DECL, and the rest of - the compiler cannot handle that. Once the class is - defined, USING_DECLs are purged from TYPE_FIELDS; see - handle_using_decl. However, we make special efforts to - make using-declarations in class templates and class - template partial specializations work correctly. */ if (!DECL_DEPENDENT_P (field)) - continue; + { + tree using_decl = USING_DECL_DECLS (field); + if ((TREE_CODE (using_decl) == FIELD_DECL + || TREE_CODE (using_decl) == TYPE_DECL) + && DECL_NAME (using_decl) == name) + return using_decl; + continue; + } } if (DECL_NAME (field) == name Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 166743) +++ gcc/cp/name-lookup.c (working copy) @@ -439,7 +439,10 @@ supplement_binding (cxx_binding *binding bool ok = true; timevar_push (TV_NAME_LOOKUP); - if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) + if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl) + && (TREE_CODE (bval) != USING_DECL + || (!DECL_DEPENDENT_P (bval) + && (TREE_CODE (USING_DECL_DECLS (bval)) != TYPE_DECL)))) /* The new name is the type name. */ binding->type = decl; else if (/* BVAL is null when push_class_level_binding moves an @@ -458,7 +461,8 @@ supplement_binding (cxx_binding *binding && DECL_ANTICIPATED (bval) && !DECL_HIDDEN_FRIEND_P (bval))) binding->value = decl; - else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval)) + else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval) + && TREE_CODE (decl) != USING_DECL) { /* The old binding was a type name. It was placed in VALUE field because it was thought, at the point it was @@ -2910,7 +2914,15 @@ push_class_level_binding (tree name, tre else if (TREE_CODE (x) == OVERLOAD && is_overloaded_fn (bval)) old_decl = bval; else if (TREE_CODE (x) == USING_DECL && TREE_CODE (bval) == USING_DECL) - POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true); + { + if (DECL_DEPENDENT_P (x) + || TREE_CODE (USING_DECL_DECLS (x)) == FUNCTION_DECL) + POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true); + + if (DECL_DEPENDENT_P (bval) + || TREE_CODE (USING_DECL_DECLS (bval)) == FUNCTION_DECL) + POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true); + } else if (TREE_CODE (x) == USING_DECL && is_overloaded_fn (bval)) old_decl = bval; else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (x)) Index: gcc/dbxout.c =================================================================== --- gcc/dbxout.c (revision 166743) +++ gcc/dbxout.c (working copy) @@ -1437,6 +1437,8 @@ dbxout_type_fields (tree type) if (TREE_CODE (tem) == TYPE_DECL /* Omit here the nameless fields that are used to skip bits. */ || DECL_IGNORED_P (tem) + /* Omit USING_DECL */ + || TREE_CODE (tem) >= LAST_AND_UNUSED_TREE_CODE /* Omit fields whose position or size are variable or too large to represent. */ || (TREE_CODE (tem) == FIELD_DECL ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-12-20 16:51 ` Fabien Chêne @ 2010-12-22 23:10 ` Jason Merrill 2011-03-04 8:11 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Jason Merrill @ 2010-12-22 23:10 UTC (permalink / raw) To: Fabien Chêne; +Cc: gcc-patches On 12/20/2010 07:02 AM, Fabien Chêne wrote: > + { > + tree using_decl = USING_DECL_DECLS (field); > + if ((TREE_CODE (using_decl) == FIELD_DECL > + || TREE_CODE (using_decl) == TYPE_DECL) > + && DECL_NAME (using_decl) == name) > + return using_decl; > + continue; > + } I think if a USING_DECL designates a function, it shouldn't be in TYPE_FIELDS. And if we do need any code for handling USING_DECL here, don't we need it for the sorted case above as well? > - if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) > + if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl) > + && (TREE_CODE (bval) != USING_DECL > + || (!DECL_DEPENDENT_P (bval) > + && (TREE_CODE (USING_DECL_DECLS (bval)) != TYPE_DECL)))) Why is this change needed? Why is the unconditional setting of binding->type when we see a nested class no longer appropriate? It seems to me that instead of special-casing using-declarations in supplement_binding, we want the code that currently checks the tree code of decl and bval to look through USING_DECLs. Likewise in push_class_level_binding. How are using-declarations combined with normal declarations? Jason ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2010-12-22 23:10 ` Jason Merrill @ 2011-03-04 8:11 ` Fabien Chêne 2011-03-05 20:07 ` Jason Merrill 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2011-03-04 8:11 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches Hi, Sorry for the looong delay, 2010/12/22 Jason Merrill <jason@redhat.com>: > On 12/20/2010 07:02 AM, Fabien Chêne wrote: >> >> + { >> + tree using_decl = USING_DECL_DECLS (field); >> + if ((TREE_CODE (using_decl) == FIELD_DECL >> + || TREE_CODE (using_decl) == TYPE_DECL) >> + && DECL_NAME (using_decl) == name) >> + return using_decl; >> + continue; >> + } > > I think if a USING_DECL designates a function, it shouldn't be in > TYPE_FIELDS. And if we do need any code for handling USING_DECL here, don't > we need it for the sorted case above as well? > >> - if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) >> + if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl) >> + && (TREE_CODE (bval) != USING_DECL >> + || (!DECL_DEPENDENT_P (bval) >> + && (TREE_CODE (USING_DECL_DECLS (bval)) != TYPE_DECL)))) > > Why is this change needed? Why is the unconditional setting of > binding->type when we see a nested class no longer appropriate? > > It seems to me that instead of special-casing using-declarations in > supplement_binding, we want the code that currently checks the tree code of > decl and bval to look through USING_DECLs. Likewise in > push_class_level_binding. > > How are using-declarations combined with normal declarations? Hmm, I've implemented what you were suggesting, and I don't understand the following check in supplement_binding: else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval)) { /* The old binding was a type name. It was placed in VALUE field because it was thought, at the point it was declared, to be the only entity with such a name. Move the type name into the type slot; it is now hidden by the new binding. */ binding->type = bval; binding->value = decl; binding->value_is_inherited = false; } Why is it usefull ? It prevents the following illegal code from being rejected: struct A { struct type {}; typedef int type; }; Hence, the same now happens with using declarations. -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-03-04 8:11 ` Fabien Chêne @ 2011-03-05 20:07 ` Jason Merrill 2011-03-08 21:48 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Jason Merrill @ 2011-03-05 20:07 UTC (permalink / raw) To: Fabien Chêne; +Cc: gcc-patches On 03/04/2011 03:11 AM, Fabien Chêne wrote: > Hmm, I've implemented what you were suggesting, and I don't understand > the following check in supplement_binding: > > else if (TREE_CODE (bval) == TYPE_DECL&& DECL_ARTIFICIAL (bval)) > { > /* The old binding was a type name. It was placed in > VALUE field because it was thought, at the point it was > declared, to be the only entity with such a name. Move the > type name into the type slot; it is now hidden by the new > binding. */ > binding->type = bval; > binding->value = decl; > binding->value_is_inherited = false; > } > > Why is it usefull ? It prevents the following illegal code from being rejected: > > struct A > { > struct type {}; > typedef int type; > }; That's a bug. I guess the check above needs to make sure that decl is not a TYPE_DECL. Jason ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-03-05 20:07 ` Jason Merrill @ 2011-03-08 21:48 ` Fabien Chêne 2011-06-15 19:42 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2011-03-08 21:48 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches 2011/3/5 Jason Merrill <jason@redhat.com>: > On 03/04/2011 03:11 AM, Fabien Chêne wrote: >> >> Hmm, I've implemented what you were suggesting, and I don't understand >> the following check in supplement_binding: >> >> else if (TREE_CODE (bval) == TYPE_DECL&& DECL_ARTIFICIAL (bval)) >> { >> /* The old binding was a type name. It was placed in >> VALUE field because it was thought, at the point it was >> declared, to be the only entity with such a name. Move the >> type name into the type slot; it is now hidden by the new >> binding. */ >> binding->type = bval; >> binding->value = decl; >> binding->value_is_inherited = false; >> } >> >> Why is it usefull ? It prevents the following illegal code from being >> rejected: >> >> struct A >> { >> struct type {}; >> typedef int type; >> }; > > That's a bug. I guess the check above needs to make sure that decl is not a > TYPE_DECL. OK, FYI I have opened PR c++/48010 for this bug, which I am going to fix first. -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-03-08 21:48 ` Fabien Chêne @ 2011-06-15 19:42 ` Fabien Chêne 2011-06-22 15:56 ` Jason Merrill 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2011-06-15 19:42 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches Hi, After updating the patch, I now see a failure on c++0x forward enums. Consider the below code: template <class T> struct S1 { enum class E1; enum class E1; }; Currently, the second declaration of E1 relies on a successfull call to supplement_binding_1. With the patch I am working on, it no longer succeeds, because a new check is needed, in order to fail if (target_)bval is a type (nearly similar to the fix for c++/48010). if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl) && (TREE_CODE (target_bval) != TYPE_DECL I don't really see a good solution to make it work. As I already did for c++/48010, we can add the below check... || same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval) But, same_type_p does not returns true, and it seems difficult to make it return true because the underlying type of the DECL is not yet set when calling pushtag1 in start_enum. Otherwise, perhaps that it would be better if the second declaration of E1 does not rely on supplement_binding_1. What do you think ? -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-06-15 19:42 ` Fabien Chêne @ 2011-06-22 15:56 ` Jason Merrill 2011-09-17 18:49 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Jason Merrill @ 2011-06-22 15:56 UTC (permalink / raw) To: Fabien Chêne; +Cc: gcc-patches On 06/15/2011 01:58 PM, Fabien Chêne wrote: > Otherwise, perhaps that it would be better if the second declaration > of E1 does not rely on supplement_binding_1. > What do you think ? I agree. We should be using xref_tag for this like we do with classes, so we don't try to push the same tag more than once. Jason ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-06-22 15:56 ` Jason Merrill @ 2011-09-17 18:49 ` Fabien Chêne 2011-09-20 1:53 ` Jason Merrill 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2011-09-17 18:49 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches [-- Attachment #1: Type: text/plain, Size: 3178 bytes --] Hi! (Again, sorry for the long delay, but I indeed have very few time to work on it) 2011/6/22 Jason Merrill <jason@redhat.com>: > On 06/15/2011 01:58 PM, Fabien Chęne wrote: >> >> Otherwise, perhaps that it would be better if the second declaration >> of E1 does not rely on supplement_binding_1. >> What do you think ? > > I agree. We should be using xref_tag for this like we do with classes, so > we don't try to push the same tag more than once. Ah, yes it works for the previous testcase, but I can't manage to make it work for the below example: template<typename T> struct S1 { enum E : T; // { dg-error "previous definition" } enum E : int; // { dg-error "different underlying type" } }; template struct S1<short>; // { dg-message "required from here" } I tried various things without success, and I ended up hacking supplement_binding_1 to handle those ENUMERAL_TYPEs. I am all ear for another solution ... Attached is an updated patch that should address most of your previous comments (except for c++0X enums). Tested x86_64_unknown-linux-gnu without new regressions. Is it in better shape ? gcc/ChangeLog 2011-09-15 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * dbxout.c (dbxout_type_fields): Ignore using declarations. gcc/testsuite/ChangeLog 2011-09-15 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * g++.dg/lookup/using23.C: New. * g++.dg/lookup/using24.C: New. * g++.dg/lookup/using25.C: New. * g++.dg/lookup/using26.C: New. * g++.dg/lookup/using27.C: New. * g++.dg/lookup/using28.C: New. * g++.dg/lookup/using29.C: New. * g++.dg/lookup/using30.C: New. * g++.dg/lookup/using31.C: New. * g++.dg/lookup/using32.C: New. * g++.dg/lookup/using33.C: New. * g++.dg/lookup/using34.C: New. * g++.dg/lookup/using35.C: New. * g++.dg/debug/using4.C: New. * g++.dg/debug/using5.C: New. * g++.dg/cpp0x/forw_enum10.C: New. * g++.old-deja/g++.other/using1.C: Adjust. * g++.dg/template/using2.C: Likewise. gcc/cp/ChangeLog 2011-09-15 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * search.c (lookup_field_1): Get rid of the comment saying that USING_DECL should not be returned, and actually return USING_DECL if appropriate. * semantics.c (finish_member_declaration): Remove the check that prevents USING_DECLs from being verified by pushdecl_class_level. * typeck.c (build_class_member_access_expr): Handle USING_DECLs. * class.c (check_field_decls): Keep using declarations. * parser.c (cp_parser_nonclass_name): Handle USING_DECLs. * decl.c (start_enum): Call xref_tag whenever possible. * name-lookup.c (strip_using_decl): New function. (supplement_binding_1): Call strip_using_decl on decl and bval. Perform most of the checks with USING_DECLs stripped. Also check that the target decl and the target bval does not refer to the same declaration. Add a hack for handling ENUMERAL_TYPE. (push_class_level_binding): Call strip_using_decl on decl and bval. Perform most of the checks with USING_DECLs stripped. Return true if both decl and bval refer to USING_DECLs and are dependent. -- Fabien [-- Attachment #2: pr26256.patch --] [-- Type: application/octet-stream, Size: 23082 bytes --] Index: gcc/testsuite/g++.old-deja/g++.other/using1.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.other/using1.C (revision 178088) +++ gcc/testsuite/g++.old-deja/g++.other/using1.C (working copy) @@ -16,12 +16,12 @@ public: using B::b; }; -class D2 : public B { // { dg-error "" } conflicting access specifications +class D2 : public B { public: using B::a; - using B::b; + using B::b; // { dg-message "" } conflicting declaration private: - using B::b; + using B::b; // { dg-error "" } conflicts }; Index: gcc/testsuite/g++.dg/debug/using4.C =================================================================== --- gcc/testsuite/g++.dg/debug/using4.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using4.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + typedef char type; +}; + +struct B +{ + typedef int type; +}; + +struct C : A, B +{ + using A::type; + type f (type); +}; + +C::type C::f( type ) +{ + type c = 'e'; + return c; +} Index: gcc/testsuite/g++.dg/debug/using5.C =================================================================== --- gcc/testsuite/g++.dg/debug/using5.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using5.C (revision 0) @@ -0,0 +1,23 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using B::i; + int f (); +}; + +int C::f() +{ + return i; +} Index: gcc/testsuite/g++.dg/lookup/using24.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using24.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using24.C (revision 0) @@ -0,0 +1,12 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int next; }; +struct B { int next; }; +struct C : B { using B::next; }; + +struct D : A, C +{ + using C::next; + void f() { next = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using28.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using28.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using28.C (revision 0) @@ -0,0 +1,11 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int f; }; +struct B { int f; }; +struct C : A, B { using B::f; }; + +struct D : C +{ + void g() { f = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using33.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using33.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using33.C (revision 0) @@ -0,0 +1,26 @@ +// { dg-do run } + +template <class T> +struct Foo +{ + int k (float) {return 0;} +}; + +template <class T> +struct Baz +{ + int k (int) {return 1;} +}; + +template <class T> +struct Bar : Foo<T> , Baz<T> +{ + using Foo<T>::k; + using Baz<T>::k; +}; + +int main() +{ + Bar<int> bar; + return bar.k( 1.0f ); +} Index: gcc/testsuite/g++.dg/lookup/using25.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using25.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using25.C (revision 0) @@ -0,0 +1,28 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + int next; +}; + +struct B +{ + int next; +}; + +struct C : public A, public B +{ + using A::next; +}; + +void foo(C& c) { c.next = 42; } + +int main() +{ + C c; + foo (c); + c.B::next = 12; + if (c.next != 42 || c.A::next != 42 || c.B::next != 12) + __builtin_abort(); +} Index: gcc/testsuite/g++.dg/lookup/using29.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using29.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using29.C (revision 0) @@ -0,0 +1,88 @@ +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + + +struct C : A, B +{ + using A::i; // { dg-error "conflicts with previous" } + using B::i; // { dg-error "declaration" } +}; + + +struct E +{ + typedef int type; +}; + +struct F +{ + typedef int type; +}; + +struct G : E, F +{ + using E::type; // { dg-error "conflicts with previous" } + using F::type; // { dg-error "declaration" } +}; + + +struct H +{ + typedef int type; +}; + +struct I : H +{ + typedef int type; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; + + +struct I2 : H +{ + using H::type; // { dg-error "conflicts with previous" } + typedef int type; // { dg-error "declaration" } +}; + + +struct J +{ + struct type {}; +}; + +struct K : J +{ + struct type {}; // { dg-error "conflicts with previous" } + using J::type; // { dg-error "declaration" } +}; + +struct L : J +{ + using J::type; // { dg-error "conflicts with previous" } + struct type {}; // { dg-error "declaration" } +}; + + +struct M +{ + typedef int type; + struct type2 {}; +}; + +struct N : M +{ + using M::type; // { dg-error "conflicts with previous" } + using M::type; // { dg-error "declaration" } + using M::type2; // { dg-error "conflicts with previous" } + using M::type2; // { dg-error "declaration" } +}; + Index: gcc/testsuite/g++.dg/lookup/using30.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using30.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using30.C (revision 0) @@ -0,0 +1,16 @@ +// { dg-do compile } + +struct H +{ + typedef int type; +}; + +struct J : H +{ + struct type {}; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; + + + + Index: gcc/testsuite/g++.dg/lookup/using34.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using34.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using34.C (revision 0) @@ -0,0 +1,15 @@ +// { dg-do compile } + +struct A +{ + int f (); +}; + +struct B : A +{ + using A::f; + struct f {}; + void g() { f(); struct f ff; } + struct f ff; +}; + Index: gcc/testsuite/g++.dg/lookup/using26.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using26.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using26.C (revision 0) @@ -0,0 +1,27 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + double next; +}; + +struct B +{ +private: + int next; // { dg-error "private" } +}; + +struct C +{ + int next; +}; + +struct D : A, B, C // { dg-error "context" } +{ + using B::next; + void f() + { + next = 12; + } +}; Index: gcc/testsuite/g++.dg/lookup/using31.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using31.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using31.C (revision 0) @@ -0,0 +1,12 @@ +// { dg-do compile } + +struct H2 +{ + int f (); +}; + +struct J2 : H2 +{ + struct f {}; + using H2::f; +}; Index: gcc/testsuite/g++.dg/lookup/using23.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using23.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using23.C (revision 0) @@ -0,0 +1,19 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ +private: + typedef int type; // { dg-error "private" } +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B // { dg-error "context" } +{ + using A::type; + type d; +}; Index: gcc/testsuite/g++.dg/lookup/using27.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using27.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using27.C (revision 0) @@ -0,0 +1,49 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + typedef int type; +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B +{ + using A::type; + type d; + + void f() + { + type e; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); + } + + void g(); +}; + +void C::g() +{ + type x; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); +} + +int main () +{ + if (sizeof (C::type) != sizeof (A::type)) + __builtin_abort(); + + if (sizeof (C::d) != sizeof (A::type)) + __builtin_abort(); + + C::type x; + C c; + c.f(); + c.g(); +} + Index: gcc/testsuite/g++.dg/lookup/using32.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using32.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using32.C (revision 0) @@ -0,0 +1,17 @@ +// { dg-do compile } + +struct T +{ + struct type {}; +}; + +struct T2 : T +{ + using T::type; +}; + +struct T3 : T2 +{ + struct type {}; + type t; +}; Index: gcc/testsuite/g++.dg/cpp0x/forw_enum10.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/forw_enum10.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/forw_enum10.C (revision 0) @@ -0,0 +1,32 @@ +// { dg-do compile } +// { dg-options "-std=c++0x" } + +//This error is diagnosed at instantiation time +template<typename T> struct S1 +{ + enum E : T; // { dg-error "previous definition" } + enum E : int; // { dg-error "different underlying type" } +}; +template struct S1<short>; // { dg-message "required from here" } + +template<typename T> struct S2 +{ + enum E : T; + enum E : T; +}; +template struct S2<short>; + +template<typename T1, typename T2> struct S3 +{ + enum E : T1; + enum E : T2; +}; +template struct S3<short,short>; + +template<typename T1, typename T2> struct S4 +{ + enum E : T1; // { dg-error "previous definition" } + enum E : T2; // { dg-error "different underlying type" } +}; +template struct S4<short,char>; // { dg-message "required from here" } + Index: gcc/testsuite/g++.dg/template/using2.C =================================================================== --- gcc/testsuite/g++.dg/template/using2.C (revision 178088) +++ gcc/testsuite/g++.dg/template/using2.C (working copy) @@ -7,24 +7,25 @@ template <class T> struct Foo { - int i; // { dg-error "Foo" } + int i; }; struct Baz { - int i; // { dg-error "Baz" } + int i; }; template <class T> -struct Bar : public Foo<T>, Baz { - using Foo<T>::i; - using Baz::i; +struct Bar : public Foo<T>, Baz +{ + using Foo<T>::i; // { dg-message "conflicts with previous" } + using Baz::i; // { dg-error "declaration" } - int foo () { return i; } // { dg-error "request for member" } + int foo () { return i; } }; void foo (Bar<int> &bar) { - bar.foo(); // { dg-message "required" } + bar.foo(); } Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c (revision 178088) +++ gcc/cp/typeck.c (working copy) @@ -2329,6 +2329,11 @@ build_class_member_access_expr (tree obj result = build2 (COMPOUND_EXPR, TREE_TYPE (result), object, result); } + else if (TREE_CODE (member) == USING_DECL && !DECL_DEPENDENT_P (member)) + result = build_class_member_access_expr (object, + USING_DECL_DECLS (member), + access_path, preserve_reference, + complain); else { if (complain & tf_error) Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 178088) +++ gcc/cp/class.c (working copy) @@ -3016,15 +3016,8 @@ check_field_decls (tree t, tree *access_ if (TREE_CODE (x) == USING_DECL) { - /* Prune the access declaration from the list of fields. */ - *field = DECL_CHAIN (x); - /* Save the access declarations for our caller. */ *access_decls = tree_cons (NULL_TREE, x, *access_decls); - - /* Since we've reset *FIELD there's no reason to skip to the - next field. */ - next = field; continue; } Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 178088) +++ gcc/cp/decl.c (working copy) @@ -11937,8 +11937,20 @@ start_enum (tree name, tree enumtype, tr *is_new = true; } prevtype = enumtype; - enumtype = cxx_make_type (ENUMERAL_TYPE); - enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); + + /* do not push the decl more than once */ + if (!enumtype + || (underlying_type + && dependent_type_p (underlying_type)) + || (ENUM_UNDERLYING_TYPE (enumtype) + && dependent_type_p (ENUM_UNDERLYING_TYPE (enumtype)))) + { + enumtype = cxx_make_type (ENUMERAL_TYPE); + enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); + } + else + enumtype = xref_tag (enum_type, name, /*tag_scope=*/ts_current, false); + if (enumtype == error_mark_node) return error_mark_node; Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 178088) +++ gcc/cp/semantics.c (working copy) @@ -2670,8 +2670,7 @@ finish_member_declaration (tree decl) } } /* Enter the DECL into the scope of the class. */ - else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) - || pushdecl_class_level (decl)) + else if (pushdecl_class_level (decl)) { /* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields go at the beginning. The reason is that lookup_field_1 Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 178088) +++ gcc/cp/parser.c (working copy) @@ -13046,6 +13046,10 @@ cp_parser_nonclass_name (cp_parser* pars /* Look up the type-name. */ type_decl = cp_parser_lookup_name_simple (parser, identifier, token->location); + /* If it is a using decl, use its underlying decl. */ + if (TREE_CODE (type_decl) == USING_DECL && !DECL_DEPENDENT_P (type_decl)) + type_decl = USING_DECL_DECLS (type_decl); + if (TREE_CODE (type_decl) != TYPE_DECL && (objc_is_id (identifier) || objc_is_class_name (identifier))) { Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c (revision 178088) +++ gcc/cp/search.c (working copy) @@ -1,7 +1,7 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -462,17 +462,15 @@ lookup_field_1 (tree type, tree name, bo } if (TREE_CODE (field) == USING_DECL) { - /* We generally treat class-scope using-declarations as - ARM-style access specifications, because support for the - ISO semantics has not been implemented. So, in general, - there's no reason to return a USING_DECL, and the rest of - the compiler cannot handle that. Once the class is - defined, USING_DECLs are purged from TYPE_FIELDS; see - handle_using_decl. However, we make special efforts to - make using-declarations in class templates and class - template partial specializations work correctly. */ if (!DECL_DEPENDENT_P (field)) - continue; + { + tree using_decl = USING_DECL_DECLS (field); + if ((TREE_CODE (using_decl) == FIELD_DECL + || TREE_CODE (using_decl) == TYPE_DECL) + && DECL_NAME (using_decl) == name) + return using_decl; + continue; + } } if (DECL_NAME (field) == name Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 178088) +++ gcc/cp/name-lookup.c (working copy) @@ -53,6 +53,7 @@ static bool qualified_lookup_using_names static tree lookup_type_current_level (tree); static tree push_using_directive (tree); static tree lookup_extern_c_fun_in_all_ns (tree); +static tree strip_using_decl (tree); /* The :: namespace. */ @@ -394,6 +395,14 @@ pop_binding (tree id, tree decl) } } +static tree +strip_using_decl (tree decl) +{ + while (TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) + decl = USING_DECL_DECLS (decl); + return decl; +} + /* BINDING records an existing declaration for a name in the current scope. But, DECL is another declaration for that same identifier in the same scope. This is the `struct stat' hack whereby a non-typedef @@ -417,29 +426,36 @@ supplement_binding_1 (cxx_binding *bindi { tree bval = binding->value; bool ok = true; + tree target_bval = strip_using_decl (bval); + tree target_decl = strip_using_decl (decl); - if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) + if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl) + && target_decl != target_bval + && (TREE_CODE (target_bval) != TYPE_DECL + || (TREE_CODE (TREE_TYPE (target_decl)) == ENUMERAL_TYPE + && TREE_CODE (TREE_TYPE (target_bval)) == ENUMERAL_TYPE))) /* The new name is the type name. */ binding->type = decl; - else if (/* BVAL is null when push_class_level_binding moves an + else if (/* TARGET_BVAL is null when push_class_level_binding moves an inherited type-binding out of the way to make room for a new value binding. */ - !bval - /* BVAL is error_mark_node when DECL's name has been used + !target_bval + /* TARGET_BVAL is error_mark_node when TARGET_DECL's name has been used in a non-class scope prior declaration. In that case, we should have already issued a diagnostic; for graceful error recovery purpose, pretend this was the intended declaration for that name. */ - || bval == error_mark_node - /* If BVAL is anticipated but has not yet been declared, + || target_bval == error_mark_node + /* If TARGET_BVAL is anticipated but has not yet been declared, pretend it is not there at all. */ - || (TREE_CODE (bval) == FUNCTION_DECL - && DECL_ANTICIPATED (bval) - && !DECL_HIDDEN_FRIEND_P (bval))) + || (TREE_CODE (target_bval) == FUNCTION_DECL + && DECL_ANTICIPATED (target_bval) + && !DECL_HIDDEN_FRIEND_P (target_bval))) binding->value = decl; - else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval) - && (TREE_CODE (decl) != TYPE_DECL - || same_type_p (TREE_TYPE (decl), TREE_TYPE (bval)))) + else if (TREE_CODE (target_bval) == TYPE_DECL && DECL_ARTIFICIAL (target_bval) + && target_decl != target_bval + && (TREE_CODE (target_decl) != TYPE_DECL + || same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval)))) { /* The old binding was a type name. It was placed in VALUE field because it was thought, at the point it was @@ -450,15 +466,15 @@ supplement_binding_1 (cxx_binding *bindi binding->value = decl; binding->value_is_inherited = false; } - else if (TREE_CODE (bval) == TYPE_DECL - && TREE_CODE (decl) == TYPE_DECL - && DECL_NAME (decl) == DECL_NAME (bval) + else if (TREE_CODE (target_bval) == TYPE_DECL + && TREE_CODE (target_decl) == TYPE_DECL + && DECL_NAME (target_decl) == DECL_NAME (target_bval) && binding->scope->kind != sk_class - && (same_type_p (TREE_TYPE (decl), TREE_TYPE (bval)) + && (same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval)) /* If either type involves template parameters, we must wait until instantiation. */ - || uses_template_parms (TREE_TYPE (decl)) - || uses_template_parms (TREE_TYPE (bval)))) + || uses_template_parms (TREE_TYPE (target_decl)) + || uses_template_parms (TREE_TYPE (target_bval)))) /* We have two typedef-names, both naming the same type to have the same name. In general, this is OK because of: @@ -480,9 +496,9 @@ supplement_binding_1 (cxx_binding *bindi A member shall not be declared twice in the member-specification. */ - else if (TREE_CODE (decl) == VAR_DECL && TREE_CODE (bval) == VAR_DECL - && DECL_EXTERNAL (decl) && DECL_EXTERNAL (bval) - && !DECL_CLASS_SCOPE_P (decl)) + else if (TREE_CODE (target_decl) == VAR_DECL && TREE_CODE (target_bval) == VAR_DECL + && DECL_EXTERNAL (target_decl) && DECL_EXTERNAL (target_bval) + && !DECL_CLASS_SCOPE_P (target_decl)) { duplicate_decls (decl, binding->value, /*newdecl_is_friend=*/false); ok = false; @@ -3018,6 +3034,8 @@ push_class_level_binding_1 (tree name, t { tree bval = binding->value; tree old_decl = NULL_TREE; + tree target_decl = strip_using_decl (decl); + tree target_bval = strip_using_decl (bval); if (INHERITED_VALUE_BINDING_P (binding)) { @@ -3025,8 +3043,8 @@ push_class_level_binding_1 (tree name, t tag name, slide it over to make room for the new binding. The old binding is still visible if explicitly qualified with a class-key. */ - if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval) - && !(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x))) + if (TREE_CODE (target_bval) == TYPE_DECL && DECL_ARTIFICIAL (target_bval) + && !(TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl))) { old_decl = binding->type; binding->type = bval; @@ -3038,18 +3056,21 @@ push_class_level_binding_1 (tree name, t old_decl = bval; /* Any inherited type declaration is hidden by the type declaration in the derived class. */ - if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)) + if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl)) binding->type = NULL_TREE; } } - else if (TREE_CODE (x) == OVERLOAD && is_overloaded_fn (bval)) - old_decl = bval; - else if (TREE_CODE (x) == USING_DECL && TREE_CODE (bval) == USING_DECL) - return true; - else if (TREE_CODE (x) == USING_DECL && is_overloaded_fn (bval)) + else if (TREE_CODE (target_decl) == OVERLOAD && is_overloaded_fn (target_bval)) old_decl = bval; - else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (x)) + else if (TREE_CODE (decl) == USING_DECL + && DECL_DEPENDENT_P (decl) + && TREE_CODE (bval) == USING_DECL + && DECL_DEPENDENT_P (bval)) return true; + else if (TREE_CODE (decl) == USING_DECL && is_overloaded_fn (target_bval)) + old_decl = bval; + else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (target_decl)) + return true; if (old_decl && binding->scope == class_binding_level) { Index: gcc/dbxout.c =================================================================== --- gcc/dbxout.c (revision 178088) +++ gcc/dbxout.c (working copy) @@ -1518,6 +1518,8 @@ dbxout_type_fields (tree type) if (TREE_CODE (tem) == TYPE_DECL /* Omit here the nameless fields that are used to skip bits. */ || DECL_IGNORED_P (tem) + /* Omit USING_DECL */ + || TREE_CODE (tem) >= LAST_AND_UNUSED_TREE_CODE /* Omit fields whose position or size are variable or too large to represent. */ || (TREE_CODE (tem) == FIELD_DECL ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-17 18:49 ` Fabien Chêne @ 2011-09-20 1:53 ` Jason Merrill 2011-09-21 18:33 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Jason Merrill @ 2011-09-20 1:53 UTC (permalink / raw) To: Fabien Chêne; +Cc: gcc-patches On 09/17/2011 09:44 AM, Fabien Chêne wrote: > I tried various things without success, and I ended up hacking > supplement_binding_1 to handle those ENUMERAL_TYPEs. > I am all ear for another solution ... Your solution seems reasonable to me, but it needs a comment, along the lines of /* We allow pushing an enum multiple times in a class template in order to handle late matching of underlying type on an opaque-enum-declaration followed by an enum-specifier. */ And I guess limit it to dependent class scope. Incidentally, repeating opaque-enum-declarations at class scope is invalid under 9.2/1: -- A member shall not be declared twice in the member-specification, except that a nested class or member class template can be declared and then later defined, and except that an enumeration can be introduced with an opaque-enum-declaration and later redeclared with an enum-specifier. -- So struct A { enum E: int; enum E: int { e1 }; }; is OK, but struct B { enum E: int; enum E: int; }; is not. > +static tree > +strip_using_decl (tree decl) Needs a comment. Also, this function has a loop in it, but various other places in the patch that look through USING_DECLs don't loop. > if (!DECL_DEPENDENT_P (field)) > - continue; > + { > + tree using_decl = USING_DECL_DECLS (field); > + if ((TREE_CODE (using_decl) == FIELD_DECL > + || TREE_CODE (using_decl) == TYPE_DECL) > + && DECL_NAME (using_decl) == name) > + return using_decl; > + continue; > + } This section needs a comment. Why do we look through USING_DECL for these two kinds of member but not others? ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-20 1:53 ` Jason Merrill @ 2011-09-21 18:33 ` Fabien Chêne 2011-09-21 18:52 ` Fabien Chêne 2011-09-21 19:01 ` Jason Merrill 0 siblings, 2 replies; 40+ messages in thread From: Fabien Chêne @ 2011-09-21 18:33 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches [-- Attachment #1: Type: text/plain, Size: 2511 bytes --] Hi, 2011/9/20 Jason Merrill <jason@redhat.com>: > On 09/17/2011 09:44 AM, Fabien Chêne wrote: >> >> I tried various things without success, and I ended up hacking >> supplement_binding_1 to handle those ENUMERAL_TYPEs. >> I am all ear for another solution ... > > Your solution seems reasonable to me, but it needs a comment, along the > lines of > > /* We allow pushing an enum multiple times in a class template in order to > handle late matching of underlying type on an opaque-enum-declaration > followed by an enum-specifier. */ Done. > And I guess limit it to dependent class scope. Incidentally, repeating > opaque-enum-declarations at class scope is invalid under 9.2/1: > > -- > A member shall not be declared twice in the member-specification, except > that a nested class or member class template can be declared and then later > defined, and except that an enumeration can be introduced with an > opaque-enum-declaration and later redeclared with an enum-specifier. > -- > > So > > struct A > { > enum E: int; > enum E: int { e1 }; > }; > > is OK, but > > struct B > { > enum E: int; > enum E: int; > }; > > is not. Hence, I think there is currently a bug here. Moreover, some tests are checking the above example (forw_enum{3,4}.C at least). However, I think that fixing this bug is beyond the scope of this patch. I'll fill in a bug for this issue. >> +static tree >> +strip_using_decl (tree decl) > > Needs a comment. Also, this function has a loop in it, but various other > places in the patch that look through USING_DECLs don't loop. Done. >> if (!DECL_DEPENDENT_P (field)) >> - continue; >> + { >> + tree using_decl = USING_DECL_DECLS (field); >> + if ((TREE_CODE (using_decl) == FIELD_DECL >> + || TREE_CODE (using_decl) == TYPE_DECL) >> + && DECL_NAME (using_decl) == name) >> + return using_decl; >> + continue; >> + } > > This section needs a comment. Why do we look through USING_DECL for these > two kinds of member but not others? I was looking explicitely for a FIELD_DECL or a TYPE_DECL because it was crashing if I didn't. In fact, it was simply that DECL_NAME needs at least tree_minimal, which OVERLOAD doesn't have. Is there a way to properly check that DECL_NAME will succeed ? Attached an updated patch, regtested on x86_64-unknown-linux-gnu. -- Fabien [-- Attachment #2: pr26256.patch --] [-- Type: application/octet-stream, Size: 23882 bytes --] Index: gcc/testsuite/g++.old-deja/g++.other/using1.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.other/using1.C (revision 178088) +++ gcc/testsuite/g++.old-deja/g++.other/using1.C (working copy) @@ -16,12 +16,12 @@ public: using B::b; }; -class D2 : public B { // { dg-error "" } conflicting access specifications +class D2 : public B { public: using B::a; - using B::b; + using B::b; // { dg-message "" } conflicting declaration private: - using B::b; + using B::b; // { dg-error "" } conflicts }; Index: gcc/testsuite/g++.dg/debug/using4.C =================================================================== --- gcc/testsuite/g++.dg/debug/using4.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using4.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + typedef char type; +}; + +struct B +{ + typedef int type; +}; + +struct C : A, B +{ + using A::type; + type f (type); +}; + +C::type C::f( type ) +{ + type c = 'e'; + return c; +} Index: gcc/testsuite/g++.dg/debug/using5.C =================================================================== --- gcc/testsuite/g++.dg/debug/using5.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using5.C (revision 0) @@ -0,0 +1,23 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using B::i; + int f (); +}; + +int C::f() +{ + return i; +} Index: gcc/testsuite/g++.dg/lookup/using24.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using24.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using24.C (revision 0) @@ -0,0 +1,12 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int next; }; +struct B { int next; }; +struct C : B { using B::next; }; + +struct D : A, C +{ + using C::next; + void f() { next = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using28.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using28.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using28.C (revision 0) @@ -0,0 +1,11 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int f; }; +struct B { int f; }; +struct C : A, B { using B::f; }; + +struct D : C +{ + void g() { f = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using33.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using33.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using33.C (revision 0) @@ -0,0 +1,26 @@ +// { dg-do run } + +template <class T> +struct Foo +{ + int k (float) {return 0;} +}; + +template <class T> +struct Baz +{ + int k (int) {return 1;} +}; + +template <class T> +struct Bar : Foo<T> , Baz<T> +{ + using Foo<T>::k; + using Baz<T>::k; +}; + +int main() +{ + Bar<int> bar; + return bar.k( 1.0f ); +} Index: gcc/testsuite/g++.dg/lookup/using25.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using25.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using25.C (revision 0) @@ -0,0 +1,28 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + int next; +}; + +struct B +{ + int next; +}; + +struct C : public A, public B +{ + using A::next; +}; + +void foo(C& c) { c.next = 42; } + +int main() +{ + C c; + foo (c); + c.B::next = 12; + if (c.next != 42 || c.A::next != 42 || c.B::next != 12) + __builtin_abort(); +} Index: gcc/testsuite/g++.dg/lookup/using29.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using29.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using29.C (revision 0) @@ -0,0 +1,88 @@ +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + + +struct C : A, B +{ + using A::i; // { dg-error "conflicts with previous" } + using B::i; // { dg-error "declaration" } +}; + + +struct E +{ + typedef int type; +}; + +struct F +{ + typedef int type; +}; + +struct G : E, F +{ + using E::type; // { dg-error "conflicts with previous" } + using F::type; // { dg-error "declaration" } +}; + + +struct H +{ + typedef int type; +}; + +struct I : H +{ + typedef int type; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; + + +struct I2 : H +{ + using H::type; // { dg-error "conflicts with previous" } + typedef int type; // { dg-error "declaration" } +}; + + +struct J +{ + struct type {}; +}; + +struct K : J +{ + struct type {}; // { dg-error "conflicts with previous" } + using J::type; // { dg-error "declaration" } +}; + +struct L : J +{ + using J::type; // { dg-error "conflicts with previous" } + struct type {}; // { dg-error "declaration" } +}; + + +struct M +{ + typedef int type; + struct type2 {}; +}; + +struct N : M +{ + using M::type; // { dg-error "conflicts with previous" } + using M::type; // { dg-error "declaration" } + using M::type2; // { dg-error "conflicts with previous" } + using M::type2; // { dg-error "declaration" } +}; + Index: gcc/testsuite/g++.dg/lookup/using30.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using30.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using30.C (revision 0) @@ -0,0 +1,16 @@ +// { dg-do compile } + +struct H +{ + typedef int type; +}; + +struct J : H +{ + struct type {}; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; + + + + Index: gcc/testsuite/g++.dg/lookup/using34.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using34.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using34.C (revision 0) @@ -0,0 +1,15 @@ +// { dg-do compile } + +struct A +{ + int f (); +}; + +struct B : A +{ + using A::f; + struct f {}; + void g() { f(); struct f ff; } + struct f ff; +}; + Index: gcc/testsuite/g++.dg/lookup/using26.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using26.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using26.C (revision 0) @@ -0,0 +1,27 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + double next; +}; + +struct B +{ +private: + int next; // { dg-error "private" } +}; + +struct C +{ + int next; +}; + +struct D : A, B, C // { dg-error "context" } +{ + using B::next; + void f() + { + next = 12; + } +}; Index: gcc/testsuite/g++.dg/lookup/using31.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using31.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using31.C (revision 0) @@ -0,0 +1,12 @@ +// { dg-do compile } + +struct H2 +{ + int f (); +}; + +struct J2 : H2 +{ + struct f {}; + using H2::f; +}; Index: gcc/testsuite/g++.dg/lookup/using23.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using23.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using23.C (revision 0) @@ -0,0 +1,19 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ +private: + typedef int type; // { dg-error "private" } +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B // { dg-error "context" } +{ + using A::type; + type d; +}; Index: gcc/testsuite/g++.dg/lookup/using27.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using27.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using27.C (revision 0) @@ -0,0 +1,49 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + typedef int type; +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B +{ + using A::type; + type d; + + void f() + { + type e; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); + } + + void g(); +}; + +void C::g() +{ + type x; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); +} + +int main () +{ + if (sizeof (C::type) != sizeof (A::type)) + __builtin_abort(); + + if (sizeof (C::d) != sizeof (A::type)) + __builtin_abort(); + + C::type x; + C c; + c.f(); + c.g(); +} + Index: gcc/testsuite/g++.dg/lookup/using32.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using32.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using32.C (revision 0) @@ -0,0 +1,17 @@ +// { dg-do compile } + +struct T +{ + struct type {}; +}; + +struct T2 : T +{ + using T::type; +}; + +struct T3 : T2 +{ + struct type {}; + type t; +}; Index: gcc/testsuite/g++.dg/cpp0x/forw_enum10.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/forw_enum10.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/forw_enum10.C (revision 0) @@ -0,0 +1,32 @@ +// { dg-do compile } +// { dg-options "-std=c++0x" } + +//This error is diagnosed at instantiation time +template<typename T> struct S1 +{ + enum E : T; // { dg-error "previous definition" } + enum E : int; // { dg-error "different underlying type" } +}; +template struct S1<short>; // { dg-message "required from here" } + +template<typename T> struct S2 +{ + enum E : T; + enum E : T; +}; +template struct S2<short>; + +template<typename T1, typename T2> struct S3 +{ + enum E : T1; + enum E : T2; +}; +template struct S3<short,short>; + +template<typename T1, typename T2> struct S4 +{ + enum E : T1; // { dg-error "previous definition" } + enum E : T2; // { dg-error "different underlying type" } +}; +template struct S4<short,char>; // { dg-message "required from here" } + Index: gcc/testsuite/g++.dg/template/using2.C =================================================================== --- gcc/testsuite/g++.dg/template/using2.C (revision 178088) +++ gcc/testsuite/g++.dg/template/using2.C (working copy) @@ -7,24 +7,25 @@ template <class T> struct Foo { - int i; // { dg-error "Foo" } + int i; }; struct Baz { - int i; // { dg-error "Baz" } + int i; }; template <class T> -struct Bar : public Foo<T>, Baz { - using Foo<T>::i; - using Baz::i; +struct Bar : public Foo<T>, Baz +{ + using Foo<T>::i; // { dg-message "conflicts with previous" } + using Baz::i; // { dg-error "declaration" } - int foo () { return i; } // { dg-error "request for member" } + int foo () { return i; } }; void foo (Bar<int> &bar) { - bar.foo(); // { dg-message "required" } + bar.foo(); } Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c (revision 178088) +++ gcc/cp/typeck.c (working copy) @@ -2109,6 +2109,7 @@ build_class_member_access_expr (tree obj tree object_type; tree member_scope; tree result = NULL_TREE; + tree using_decl = NULL_TREE; if (error_operand_p (object) || error_operand_p (member)) return error_mark_node; @@ -2329,6 +2330,11 @@ build_class_member_access_expr (tree obj result = build2 (COMPOUND_EXPR, TREE_TYPE (result), object, result); } + else if ((using_decl = strip_using_decl (member)) != member) + result = build_class_member_access_expr (object, + using_decl, + access_path, preserve_reference, + complain); else { if (complain & tf_error) Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 178088) +++ gcc/cp/class.c (working copy) @@ -3016,15 +3016,8 @@ check_field_decls (tree t, tree *access_ if (TREE_CODE (x) == USING_DECL) { - /* Prune the access declaration from the list of fields. */ - *field = DECL_CHAIN (x); - /* Save the access declarations for our caller. */ *access_decls = tree_cons (NULL_TREE, x, *access_decls); - - /* Since we've reset *FIELD there's no reason to skip to the - next field. */ - next = field; continue; } Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 178088) +++ gcc/cp/decl.c (working copy) @@ -11937,8 +11937,20 @@ start_enum (tree name, tree enumtype, tr *is_new = true; } prevtype = enumtype; - enumtype = cxx_make_type (ENUMERAL_TYPE); - enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); + + /* do not push the decl more than once */ + if (!enumtype + || (underlying_type + && dependent_type_p (underlying_type)) + || (ENUM_UNDERLYING_TYPE (enumtype) + && dependent_type_p (ENUM_UNDERLYING_TYPE (enumtype)))) + { + enumtype = cxx_make_type (ENUMERAL_TYPE); + enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); + } + else + enumtype = xref_tag (enum_type, name, /*tag_scope=*/ts_current, false); + if (enumtype == error_mark_node) return error_mark_node; Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 178088) +++ gcc/cp/semantics.c (working copy) @@ -2670,8 +2670,7 @@ finish_member_declaration (tree decl) } } /* Enter the DECL into the scope of the class. */ - else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) - || pushdecl_class_level (decl)) + else if (pushdecl_class_level (decl)) { /* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields go at the beginning. The reason is that lookup_field_1 Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 178088) +++ gcc/cp/parser.c (working copy) @@ -13046,6 +13046,9 @@ cp_parser_nonclass_name (cp_parser* pars /* Look up the type-name. */ type_decl = cp_parser_lookup_name_simple (parser, identifier, token->location); + /* If it is a using decl, use its underlying decl. */ + type_decl = strip_using_decl (type_decl); + if (TREE_CODE (type_decl) != TYPE_DECL && (objc_is_id (identifier) || objc_is_class_name (identifier))) { Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 178088) +++ gcc/cp/cp-tree.h (working copy) @@ -5776,7 +5776,8 @@ extern void cxx_omp_finish_clause (tree extern bool cxx_omp_privatize_by_reference (const_tree); /* in name-lookup.c */ -extern void suggest_alternatives_for (location_t, tree); +extern void suggest_alternatives_for (location_t, tree); +extern tree strip_using_decl (tree); /* -- end of C++ */ Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c (revision 178088) +++ gcc/cp/search.c (working copy) @@ -1,7 +1,7 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -462,17 +462,14 @@ lookup_field_1 (tree type, tree name, bo } if (TREE_CODE (field) == USING_DECL) { - /* We generally treat class-scope using-declarations as - ARM-style access specifications, because support for the - ISO semantics has not been implemented. So, in general, - there's no reason to return a USING_DECL, and the rest of - the compiler cannot handle that. Once the class is - defined, USING_DECLs are purged from TYPE_FIELDS; see - handle_using_decl. However, we make special efforts to - make using-declarations in class templates and class - template partial specializations work correctly. */ if (!DECL_DEPENDENT_P (field)) - continue; + { + tree using_decl = USING_DECL_DECLS (field); + if (TREE_CODE (using_decl) != OVERLOAD + && DECL_NAME (using_decl) == name) + return using_decl; + continue; + } } if (DECL_NAME (field) == name Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 178088) +++ gcc/cp/name-lookup.c (working copy) @@ -394,6 +394,16 @@ pop_binding (tree id, tree decl) } } +/* Strip non dependent using declarations. */ + +tree +strip_using_decl (tree decl) +{ + while (TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) + decl = USING_DECL_DECLS (decl); + return decl; +} + /* BINDING records an existing declaration for a name in the current scope. But, DECL is another declaration for that same identifier in the same scope. This is the `struct stat' hack whereby a non-typedef @@ -417,29 +427,45 @@ supplement_binding_1 (cxx_binding *bindi { tree bval = binding->value; bool ok = true; + tree target_bval = strip_using_decl (bval); + tree target_decl = strip_using_decl (decl); - if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) + if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl) + && target_decl != target_bval + && (TREE_CODE (target_bval) != TYPE_DECL + /* We allow pushing an enum multiple times in a class + * template in order to handle late matching of underlying + * type on an opaque-enum-declaration followed by an + * enum-specifier. */ + || (TREE_CODE (TREE_TYPE (target_decl)) == ENUMERAL_TYPE + && TREE_CODE (TREE_TYPE (target_bval)) == ENUMERAL_TYPE + && (dependent_type_p (ENUM_UNDERLYING_TYPE + (TREE_TYPE (target_decl))) + || dependent_type_p (ENUM_UNDERLYING_TYPE + (TREE_TYPE (target_bval)))) + ))) /* The new name is the type name. */ binding->type = decl; - else if (/* BVAL is null when push_class_level_binding moves an + else if (/* TARGET_BVAL is null when push_class_level_binding moves an inherited type-binding out of the way to make room for a new value binding. */ - !bval - /* BVAL is error_mark_node when DECL's name has been used + !target_bval + /* TARGET_BVAL is error_mark_node when TARGET_DECL's name has been used in a non-class scope prior declaration. In that case, we should have already issued a diagnostic; for graceful error recovery purpose, pretend this was the intended declaration for that name. */ - || bval == error_mark_node - /* If BVAL is anticipated but has not yet been declared, + || target_bval == error_mark_node + /* If TARGET_BVAL is anticipated but has not yet been declared, pretend it is not there at all. */ - || (TREE_CODE (bval) == FUNCTION_DECL - && DECL_ANTICIPATED (bval) - && !DECL_HIDDEN_FRIEND_P (bval))) + || (TREE_CODE (target_bval) == FUNCTION_DECL + && DECL_ANTICIPATED (target_bval) + && !DECL_HIDDEN_FRIEND_P (target_bval))) binding->value = decl; - else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval) - && (TREE_CODE (decl) != TYPE_DECL - || same_type_p (TREE_TYPE (decl), TREE_TYPE (bval)))) + else if (TREE_CODE (target_bval) == TYPE_DECL && DECL_ARTIFICIAL (target_bval) + && target_decl != target_bval + && (TREE_CODE (target_decl) != TYPE_DECL + || same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval)))) { /* The old binding was a type name. It was placed in VALUE field because it was thought, at the point it was @@ -450,15 +476,15 @@ supplement_binding_1 (cxx_binding *bindi binding->value = decl; binding->value_is_inherited = false; } - else if (TREE_CODE (bval) == TYPE_DECL - && TREE_CODE (decl) == TYPE_DECL - && DECL_NAME (decl) == DECL_NAME (bval) + else if (TREE_CODE (target_bval) == TYPE_DECL + && TREE_CODE (target_decl) == TYPE_DECL + && DECL_NAME (target_decl) == DECL_NAME (target_bval) && binding->scope->kind != sk_class - && (same_type_p (TREE_TYPE (decl), TREE_TYPE (bval)) + && (same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval)) /* If either type involves template parameters, we must wait until instantiation. */ - || uses_template_parms (TREE_TYPE (decl)) - || uses_template_parms (TREE_TYPE (bval)))) + || uses_template_parms (TREE_TYPE (target_decl)) + || uses_template_parms (TREE_TYPE (target_bval)))) /* We have two typedef-names, both naming the same type to have the same name. In general, this is OK because of: @@ -480,9 +506,9 @@ supplement_binding_1 (cxx_binding *bindi A member shall not be declared twice in the member-specification. */ - else if (TREE_CODE (decl) == VAR_DECL && TREE_CODE (bval) == VAR_DECL - && DECL_EXTERNAL (decl) && DECL_EXTERNAL (bval) - && !DECL_CLASS_SCOPE_P (decl)) + else if (TREE_CODE (target_decl) == VAR_DECL && TREE_CODE (target_bval) == VAR_DECL + && DECL_EXTERNAL (target_decl) && DECL_EXTERNAL (target_bval) + && !DECL_CLASS_SCOPE_P (target_decl)) { duplicate_decls (decl, binding->value, /*newdecl_is_friend=*/false); ok = false; @@ -3018,6 +3044,8 @@ push_class_level_binding_1 (tree name, t { tree bval = binding->value; tree old_decl = NULL_TREE; + tree target_decl = strip_using_decl (decl); + tree target_bval = strip_using_decl (bval); if (INHERITED_VALUE_BINDING_P (binding)) { @@ -3025,8 +3053,8 @@ push_class_level_binding_1 (tree name, t tag name, slide it over to make room for the new binding. The old binding is still visible if explicitly qualified with a class-key. */ - if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval) - && !(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x))) + if (TREE_CODE (target_bval) == TYPE_DECL && DECL_ARTIFICIAL (target_bval) + && !(TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl))) { old_decl = binding->type; binding->type = bval; @@ -3038,18 +3066,21 @@ push_class_level_binding_1 (tree name, t old_decl = bval; /* Any inherited type declaration is hidden by the type declaration in the derived class. */ - if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)) + if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl)) binding->type = NULL_TREE; } } - else if (TREE_CODE (x) == OVERLOAD && is_overloaded_fn (bval)) - old_decl = bval; - else if (TREE_CODE (x) == USING_DECL && TREE_CODE (bval) == USING_DECL) - return true; - else if (TREE_CODE (x) == USING_DECL && is_overloaded_fn (bval)) + else if (TREE_CODE (target_decl) == OVERLOAD && is_overloaded_fn (target_bval)) old_decl = bval; - else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (x)) + else if (TREE_CODE (decl) == USING_DECL + && DECL_DEPENDENT_P (decl) + && TREE_CODE (bval) == USING_DECL + && DECL_DEPENDENT_P (bval)) return true; + else if (TREE_CODE (decl) == USING_DECL && is_overloaded_fn (target_bval)) + old_decl = bval; + else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (target_decl)) + return true; if (old_decl && binding->scope == class_binding_level) { Index: gcc/dbxout.c =================================================================== --- gcc/dbxout.c (revision 178088) +++ gcc/dbxout.c (working copy) @@ -1518,6 +1518,8 @@ dbxout_type_fields (tree type) if (TREE_CODE (tem) == TYPE_DECL /* Omit here the nameless fields that are used to skip bits. */ || DECL_IGNORED_P (tem) + /* Omit USING_DECL */ + || TREE_CODE (tem) >= LAST_AND_UNUSED_TREE_CODE /* Omit fields whose position or size are variable or too large to represent. */ || (TREE_CODE (tem) == FIELD_DECL ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-21 18:33 ` Fabien Chêne @ 2011-09-21 18:52 ` Fabien Chêne 2011-09-21 19:01 ` Jason Merrill 1 sibling, 0 replies; 40+ messages in thread From: Fabien Chêne @ 2011-09-21 18:52 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches ... with the ChangeLog gcc/ChangeLog 2011-09-21 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * dbxout.c (dbxout_type_fields): Ignore using declarations. gcc/testsuite/ChangeLog 2011-09-21 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * g++.dg/lookup/using23.C: New. * g++.dg/lookup/using24.C: New. * g++.dg/lookup/using25.C: New. * g++.dg/lookup/using26.C: New. * g++.dg/lookup/using27.C: New. * g++.dg/lookup/using28.C: New. * g++.dg/lookup/using29.C: New. * g++.dg/lookup/using30.C: New. * g++.dg/lookup/using31.C: New. * g++.dg/lookup/using32.C: New. * g++.dg/lookup/using33.C: New. * g++.dg/lookup/using34.C: New. * g++.dg/lookup/using35.C: New. * g++.dg/debug/using4.C: New. * g++.dg/debug/using5.C: New. * g++.dg/cpp0x/forw_enum10.C: New. * g++.old-deja/g++.other/using1.C: Adjust. * g++.dg/template/using2.C: Likewise. gcc/cp/ChangeLog 2011-09-21 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * search.c (lookup_field_1): Get rid of the comment saying that USING_DECL should not be returned, and actually return USING_DECL if appropriate. * semantics.c (finish_member_declaration): Remove the check that prevents USING_DECLs from being verified by pushdecl_class_level. * typeck.c (build_class_member_access_expr): Handle USING_DECLs. * class.c (check_field_decls): Keep using declarations. * parser.c (cp_parser_nonclass_name): Handle USING_DECLs. * decl.c (start_enum): Call xref_tag whenever possible. * name-lookup.c (strip_using_decl): New function. (supplement_binding_1): Call strip_using_decl on decl and bval. Perform most of the checks with USING_DECLs stripped. Also check that the target decl and the target bval does not refer to the same declaration. Allow pushing an enum multiple times in a template class. (push_class_level_binding): Call strip_using_decl on decl and bval. Perform most of the checks with USING_DECLs stripped. Return true if both decl and bval refer to USING_DECLs and are dependent. -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-21 18:33 ` Fabien Chêne 2011-09-21 18:52 ` Fabien Chêne @ 2011-09-21 19:01 ` Jason Merrill 2011-09-22 10:34 ` Fabien Chêne 1 sibling, 1 reply; 40+ messages in thread From: Jason Merrill @ 2011-09-21 19:01 UTC (permalink / raw) To: Fabien Chêne; +Cc: gcc-patches On 09/21/2011 01:59 PM, Fabien Chêne wrote: >>> if (!DECL_DEPENDENT_P (field)) >>> - continue; >>> + { >>> + tree using_decl = USING_DECL_DECLS (field); >>> + if ((TREE_CODE (using_decl) == FIELD_DECL >>> + || TREE_CODE (using_decl) == TYPE_DECL) >>> +&& DECL_NAME (using_decl) == name) >>> + return using_decl; >>> + continue; >>> + } >> >> This section needs a comment. Why do we look through USING_DECL for these >> two kinds of member but not others? > > I was looking explicitely for a FIELD_DECL or a TYPE_DECL because it > was crashing if I didn't. In fact, it was simply that DECL_NAME needs > at least tree_minimal, which OVERLOAD doesn't have. Is there a way to > properly check that DECL_NAME will succeed ? You could check DECL_P first, but don't we want to return the OVERLOAD here, too? You can use get_first_fn to get a FUNCTION_DECL out of anything that satisfies is_overloaded_fn. Jason ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-21 19:01 ` Jason Merrill @ 2011-09-22 10:34 ` Fabien Chêne 2011-09-22 16:50 ` Jason Merrill 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2011-09-22 10:34 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches 2011/9/21 Jason Merrill <jason@redhat.com>: > On 09/21/2011 01:59 PM, Fabien Chêne wrote: >>>> >>>> if (!DECL_DEPENDENT_P (field)) >>>> - continue; >>>> + { >>>> + tree using_decl = USING_DECL_DECLS (field); >>>> + if ((TREE_CODE (using_decl) == FIELD_DECL >>>> + || TREE_CODE (using_decl) == TYPE_DECL) >>>> +&& DECL_NAME (using_decl) == name) >>>> + return using_decl; >>>> + continue; >>>> + } >>> >>> This section needs a comment. Why do we look through USING_DECL for >>> these >>> two kinds of member but not others? >> >> I was looking explicitely for a FIELD_DECL or a TYPE_DECL because it >> was crashing if I didn't. In fact, it was simply that DECL_NAME needs >> at least tree_minimal, which OVERLOAD doesn't have. Is there a way to >> properly check that DECL_NAME will succeed ? > > You could check DECL_P first, but don't we want to return the OVERLOAD here, > too? You can use get_first_fn to get a FUNCTION_DECL out of anything that > satisfies is_overloaded_fn. I would have thought that we want to do something with OVERLOAD here, in order to get rid of PR c++/30195 and c++/25994 (removing a wrong diagnostic additionaly)... But those PRs are already fixed by this patch without doing anything with OVERLOAD. Consequently, I don't really know why it would be needed, but I can certainly do it if you prefer. Have you got an example in mind where it would be needed ? -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-22 10:34 ` Fabien Chêne @ 2011-09-22 16:50 ` Jason Merrill 2011-09-22 23:01 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Jason Merrill @ 2011-09-22 16:50 UTC (permalink / raw) To: Fabien Chêne; +Cc: gcc-patches On 09/22/2011 04:22 AM, Fabien Chêne wrote: > I would have thought that we want to do something with OVERLOAD here, > in order to get rid of PR c++/30195 and c++/25994 (removing a wrong > diagnostic additionaly)... But those PRs are already fixed by this > patch without doing anything with OVERLOAD. Consequently, I don't > really know why it would be needed, but I can certainly do it if you > prefer. Have you got an example in mind where it would be needed ? I don't, it just seemed strange to handle functions differently from other decls here. But when I look more closely I see that we're in lookup_field_1, which isn't interested in functions, so I guess we do want to ignore function using-declarations here. But check for is_overloaded_fn rather than just OVERLOAD. Also, it looks like the new code doesn't respect want_type. Jason ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-22 16:50 ` Jason Merrill @ 2011-09-22 23:01 ` Fabien Chêne 2011-09-22 23:48 ` Jason Merrill 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2011-09-22 23:01 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches 2011/9/22 Jason Merrill <jason@redhat.com>: > On 09/22/2011 04:22 AM, Fabien Chêne wrote: >> >> I would have thought that we want to do something with OVERLOAD here, >> in order to get rid of PR c++/30195 and c++/25994 (removing a wrong >> diagnostic additionaly)... But those PRs are already fixed by this >> patch without doing anything with OVERLOAD. Consequently, I don't >> really know why it would be needed, but I can certainly do it if you >> prefer. Have you got an example in mind where it would be needed ? > > I don't, it just seemed strange to handle functions differently from other > decls here. But when I look more closely I see that we're in > lookup_field_1, which isn't interested in functions, so I guess we do want > to ignore function using-declarations here. That's strange because if we do return FUNCTION_DECL, PR c++/30195 seems solved. > But check for is_overloaded_fn rather than just OVERLOAD. Also, it looks like the new code doesn't respect want_type. Er, I'm a bit lost, do you mean something like that ? if (TREE_CODE (field) == USING_DECL) { tree target_field = strip_using_decl (field); if (target_field != field) { if (DECL_P (target_field) && DECL_NAME (target_field) == name || (is_overloaded_fn (target_field) && DECL_NAME (get_first_fn (target_field)) == name)) { if (!want_type || TREE_CODE (target_field) == TYPE_DECL) return target_field; } continue; } } Thanks, -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-22 23:01 ` Fabien Chêne @ 2011-09-22 23:48 ` Jason Merrill 2011-09-23 8:57 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Jason Merrill @ 2011-09-22 23:48 UTC (permalink / raw) To: Fabien Chêne; +Cc: gcc-patches On 09/22/2011 05:11 PM, Fabien Chêne wrote: > 2011/9/22 Jason Merrill<jason@redhat.com>: >> I don't, it just seemed strange to handle functions differently from other >> decls here. But when I look more closely I see that we're in >> lookup_field_1, which isn't interested in functions, so I guess we do want >> to ignore function using-declarations here. > > That's strange because if we do return FUNCTION_DECL, PR c++/30195 seems solved. It works for that testcase, but we need to handle functions in lookup_fnfields_1 since it's also called from other places. >> But check for is_overloaded_fn rather than just OVERLOAD. Also, it looks like the new code doesn't respect want_type. > > Er, I'm a bit lost, do you mean something like that ? > > if (TREE_CODE (field) == USING_DECL) > { > tree target_field = strip_using_decl (field); > if (target_field != field) > { > if (DECL_P (target_field)&& DECL_NAME (target_field) == name > || (is_overloaded_fn (target_field) > && DECL_NAME (get_first_fn (target_field)) == name)) > { > if (!want_type > || TREE_CODE (target_field) == TYPE_DECL) > return target_field; > } > > continue; > } > } I was thinking more like tree decl = field; if (TREE_CODE (decl) == USING_DECL) { decl = strip_using_decl (decl); if (is_overloaded_fn (decl)) continue; } if (DECL_NAME (decl) == name ... Jason ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-22 23:48 ` Jason Merrill @ 2011-09-23 8:57 ` Fabien Chêne 2011-09-25 20:49 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2011-09-23 8:57 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches 2011/9/23 Jason Merrill <jason@redhat.com>: > On 09/22/2011 05:11 PM, Fabien Chêne wrote: >> >> 2011/9/22 Jason Merrill<jason@redhat.com>: > >>> I don't, it just seemed strange to handle functions differently from >>> other >>> decls here. But when I look more closely I see that we're in >>> lookup_field_1, which isn't interested in functions, so I guess we do >>> want >>> to ignore function using-declarations here. >> >> That's strange because if we do return FUNCTION_DECL, PR c++/30195 seems >> solved. > > It works for that testcase, but we need to handle functions in > lookup_fnfields_1 since it's also called from other places. Aha, hence, I'll tackle this issue in another patch, one PR at a time ! >>> But check for is_overloaded_fn rather than just OVERLOAD. Also, it looks >>> like the new code doesn't respect want_type. >> >> Er, I'm a bit lost, do you mean something like that ? >> >> if (TREE_CODE (field) == USING_DECL) >> { >> tree target_field = strip_using_decl (field); >> if (target_field != field) >> { >> if (DECL_P (target_field)&& DECL_NAME (target_field) == name >> || (is_overloaded_fn (target_field) >> && DECL_NAME (get_first_fn (target_field)) == name)) >> { >> if (!want_type >> || TREE_CODE (target_field) == TYPE_DECL) >> return target_field; >> } >> >> continue; >> } >> } > > I was thinking more like > > tree decl = field; > if (TREE_CODE (decl) == USING_DECL) > { > decl = strip_using_decl (decl); > if (is_overloaded_fn (decl)) continue; > } > if (DECL_NAME (decl) == name > ... I should have got it... Thank you anyway. I will update the patch accordingly at the begining of the next week, I hope. -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-23 8:57 ` Fabien Chêne @ 2011-09-25 20:49 ` Fabien Chêne 2011-09-25 21:05 ` Paolo Carlini 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2011-09-25 20:49 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches [-- Attachment #1: Type: text/plain, Size: 2546 bytes --] I've updated the patch. I can't resist to tackle PR 25994 at the same time. There was a diagnostic about conflicting using declarations in add_method, which is no longer necessary and bogus in the case of PR 25994, so I just removed it. Duplicated using declarations are now diagnosed in supplement_binding_1. Tested x86_64-unknown-linux-gnu, OK to commit? gcc/ChangeLog 2011-09-21 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 * dbxout.c (dbxout_type_fields): Ignore using declarations. gcc/testsuite/ChangeLog 2011-09-21 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 PR c++/25994 * g++.dg/lookup/using23.C: New. * g++.dg/lookup/using24.C: New. * g++.dg/lookup/using25.C: New. * g++.dg/lookup/using26.C: New. * g++.dg/lookup/using27.C: New. * g++.dg/lookup/using28.C: New. * g++.dg/lookup/using29.C: New. * g++.dg/lookup/using30.C: New. * g++.dg/lookup/using31.C: New. * g++.dg/lookup/using32.C: New. * g++.dg/lookup/using33.C: New. * g++.dg/lookup/using34.C: New. * g++.dg/lookup/using35.C: New. * g++.dg/lookup/using36.C: New. * g++.dg/debug/using4.C: New. * g++.dg/debug/using5.C: New. * g++.dg/cpp0x/forw_enum10.C: New. * g++.old-deja/g++.other/using1.C: Adjust. * g++.dg/template/using2.C: Likewise. gcc/cp/ChangeLog 2011-09-21 Fabien Chêne <fabien@gcc.gnu.org> PR c++/26256 PR c++/25994 * search.c (lookup_field_1): Get rid of the comment saying that USING_DECL should not be returned, and actually return USING_DECL if appropriate. * semantics.c (finish_member_declaration): Remove the check that prevents USING_DECLs from being verified by pushdecl_class_level. * typeck.c (build_class_member_access_expr): Handle USING_DECLs. * class.c (check_field_decls): Keep using declarations. (add_method): Remove a wrong diagnostic about conflicting using declarations. * parser.c (cp_parser_nonclass_name): Handle USING_DECLs. * decl.c (start_enum): Call xref_tag whenever possible. * name-lookup.c (strip_using_decl): New function. (supplement_binding_1): Call strip_using_decl on decl and bval. Perform most of the checks with USING_DECLs stripped. Also check that the target decl and the target bval does not refer to the same declaration. Allow pushing an enum multiple times in a template class. (push_class_level_binding): Call strip_using_decl on decl and bval. Perform most of the checks with USING_DECLs stripped. Return true if both decl and bval refer to USING_DECLs and are dependent. -- Fabien [-- Attachment #2: patch_26256 --] [-- Type: application/octet-stream, Size: 25883 bytes --] Index: gcc/testsuite/g++.old-deja/g++.other/using1.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.other/using1.C (revision 178088) +++ gcc/testsuite/g++.old-deja/g++.other/using1.C (working copy) @@ -16,12 +16,12 @@ public: using B::b; }; -class D2 : public B { // { dg-error "" } conflicting access specifications +class D2 : public B { public: using B::a; - using B::b; + using B::b; // { dg-message "" } conflicting declaration private: - using B::b; + using B::b; // { dg-error "" } conflicts }; Index: gcc/testsuite/g++.dg/debug/using4.C =================================================================== --- gcc/testsuite/g++.dg/debug/using4.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using4.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + typedef char type; +}; + +struct B +{ + typedef int type; +}; + +struct C : A, B +{ + using A::type; + type f (type); +}; + +C::type C::f( type ) +{ + type c = 'e'; + return c; +} Index: gcc/testsuite/g++.dg/debug/using5.C =================================================================== --- gcc/testsuite/g++.dg/debug/using5.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using5.C (revision 0) @@ -0,0 +1,23 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using B::i; + int f (); +}; + +int C::f() +{ + return i; +} Index: gcc/testsuite/g++.dg/lookup/using36.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using36.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using36.C (revision 0) @@ -0,0 +1,31 @@ +// PR c++/25994 +// { dg-do run } + +struct B1 +{ + void f (char) {} + void f (double) { __builtin_abort(); } +}; + +struct B2 +{ + void f (double) { __builtin_abort(); } + void f (int) {} +}; + +struct D : public B1, public B2 +{ + using B1::f; + using B2::f; + void g () + { + f ('a'); // should call B1::f(char) + f (33); // should call B2::f(int) + } +}; + +int main() +{ + D d; + d.g(); +} Index: gcc/testsuite/g++.dg/lookup/using24.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using24.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using24.C (revision 0) @@ -0,0 +1,12 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int next; }; +struct B { int next; }; +struct C : B { using B::next; }; + +struct D : A, C +{ + using C::next; + void f() { next = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using28.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using28.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using28.C (revision 0) @@ -0,0 +1,11 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int f; }; +struct B { int f; }; +struct C : A, B { using B::f; }; + +struct D : C +{ + void g() { f = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using33.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using33.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using33.C (revision 0) @@ -0,0 +1,26 @@ +// { dg-do run } + +template <class T> +struct Foo +{ + int k (float) {return 0;} +}; + +template <class T> +struct Baz +{ + int k (int) {return 1;} +}; + +template <class T> +struct Bar : Foo<T> , Baz<T> +{ + using Foo<T>::k; + using Baz<T>::k; +}; + +int main() +{ + Bar<int> bar; + return bar.k( 1.0f ); +} Index: gcc/testsuite/g++.dg/lookup/using25.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using25.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using25.C (revision 0) @@ -0,0 +1,28 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + int next; +}; + +struct B +{ + int next; +}; + +struct C : public A, public B +{ + using A::next; +}; + +void foo(C& c) { c.next = 42; } + +int main() +{ + C c; + foo (c); + c.B::next = 12; + if (c.next != 42 || c.A::next != 42 || c.B::next != 12) + __builtin_abort(); +} Index: gcc/testsuite/g++.dg/lookup/using29.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using29.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using29.C (revision 0) @@ -0,0 +1,88 @@ +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + + +struct C : A, B +{ + using A::i; // { dg-error "conflicts with previous" } + using B::i; // { dg-error "declaration" } +}; + + +struct E +{ + typedef int type; +}; + +struct F +{ + typedef int type; +}; + +struct G : E, F +{ + using E::type; // { dg-error "conflicts with previous" } + using F::type; // { dg-error "declaration" } +}; + + +struct H +{ + typedef int type; +}; + +struct I : H +{ + typedef int type; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; + + +struct I2 : H +{ + using H::type; // { dg-error "conflicts with previous" } + typedef int type; // { dg-error "declaration" } +}; + + +struct J +{ + struct type {}; +}; + +struct K : J +{ + struct type {}; // { dg-error "conflicts with previous" } + using J::type; // { dg-error "declaration" } +}; + +struct L : J +{ + using J::type; // { dg-error "conflicts with previous" } + struct type {}; // { dg-error "declaration" } +}; + + +struct M +{ + typedef int type; + struct type2 {}; +}; + +struct N : M +{ + using M::type; // { dg-error "conflicts with previous" } + using M::type; // { dg-error "declaration" } + using M::type2; // { dg-error "conflicts with previous" } + using M::type2; // { dg-error "declaration" } +}; + Index: gcc/testsuite/g++.dg/lookup/using30.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using30.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using30.C (revision 0) @@ -0,0 +1,16 @@ +// { dg-do compile } + +struct H +{ + typedef int type; +}; + +struct J : H +{ + struct type {}; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; + + + + Index: gcc/testsuite/g++.dg/lookup/using34.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using34.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using34.C (revision 0) @@ -0,0 +1,15 @@ +// { dg-do compile } + +struct A +{ + int f (); +}; + +struct B : A +{ + using A::f; + struct f {}; + void g() { f(); struct f ff; } + struct f ff; +}; + Index: gcc/testsuite/g++.dg/lookup/using26.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using26.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using26.C (revision 0) @@ -0,0 +1,27 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + double next; +}; + +struct B +{ +private: + int next; // { dg-error "private" } +}; + +struct C +{ + int next; +}; + +struct D : A, B, C // { dg-error "context" } +{ + using B::next; + void f() + { + next = 12; + } +}; Index: gcc/testsuite/g++.dg/lookup/using31.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using31.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using31.C (revision 0) @@ -0,0 +1,12 @@ +// { dg-do compile } + +struct H2 +{ + int f (); +}; + +struct J2 : H2 +{ + struct f {}; + using H2::f; +}; Index: gcc/testsuite/g++.dg/lookup/using35.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using35.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using35.C (revision 0) @@ -0,0 +1,12 @@ +// { dg-do compile } + +struct A { typedef int type; }; +struct B { typedef int type; }; +struct C : B { using B::type; }; + +struct D : A, C +{ + using C::type; + void f() { type t = 0;} +}; + Index: gcc/testsuite/g++.dg/lookup/using23.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using23.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using23.C (revision 0) @@ -0,0 +1,19 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ +private: + typedef int type; // { dg-error "private" } +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B // { dg-error "context" } +{ + using A::type; + type d; +}; Index: gcc/testsuite/g++.dg/lookup/using27.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using27.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using27.C (revision 0) @@ -0,0 +1,49 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + typedef int type; +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B +{ + using A::type; + type d; + + void f() + { + type e; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); + } + + void g(); +}; + +void C::g() +{ + type x; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); +} + +int main () +{ + if (sizeof (C::type) != sizeof (A::type)) + __builtin_abort(); + + if (sizeof (C::d) != sizeof (A::type)) + __builtin_abort(); + + C::type x; + C c; + c.f(); + c.g(); +} + Index: gcc/testsuite/g++.dg/lookup/using32.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using32.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using32.C (revision 0) @@ -0,0 +1,17 @@ +// { dg-do compile } + +struct T +{ + struct type {}; +}; + +struct T2 : T +{ + using T::type; +}; + +struct T3 : T2 +{ + struct type {}; + type t; +}; Index: gcc/testsuite/g++.dg/cpp0x/forw_enum10.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/forw_enum10.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/forw_enum10.C (revision 0) @@ -0,0 +1,32 @@ +// { dg-do compile } +// { dg-options "-std=c++0x" } + +//This error is diagnosed at instantiation time +template<typename T> struct S1 +{ + enum E : T; // { dg-error "previous definition" } + enum E : int; // { dg-error "different underlying type" } +}; +template struct S1<short>; // { dg-message "required from here" } + +template<typename T> struct S2 +{ + enum E : T; + enum E : T; +}; +template struct S2<short>; + +template<typename T1, typename T2> struct S3 +{ + enum E : T1; + enum E : T2; +}; +template struct S3<short,short>; + +template<typename T1, typename T2> struct S4 +{ + enum E : T1; // { dg-error "previous definition" } + enum E : T2; // { dg-error "different underlying type" } +}; +template struct S4<short,char>; // { dg-message "required from here" } + Index: gcc/testsuite/g++.dg/template/using2.C =================================================================== --- gcc/testsuite/g++.dg/template/using2.C (revision 178088) +++ gcc/testsuite/g++.dg/template/using2.C (working copy) @@ -7,24 +7,25 @@ template <class T> struct Foo { - int i; // { dg-error "Foo" } + int i; }; struct Baz { - int i; // { dg-error "Baz" } + int i; }; template <class T> -struct Bar : public Foo<T>, Baz { - using Foo<T>::i; - using Baz::i; +struct Bar : public Foo<T>, Baz +{ + using Foo<T>::i; // { dg-message "conflicts with previous" } + using Baz::i; // { dg-error "declaration" } - int foo () { return i; } // { dg-error "request for member" } + int foo () { return i; } }; void foo (Bar<int> &bar) { - bar.foo(); // { dg-message "required" } + bar.foo(); } Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c (revision 178088) +++ gcc/cp/typeck.c (working copy) @@ -2109,6 +2109,7 @@ build_class_member_access_expr (tree obj tree object_type; tree member_scope; tree result = NULL_TREE; + tree using_decl = NULL_TREE; if (error_operand_p (object) || error_operand_p (member)) return error_mark_node; @@ -2329,6 +2330,11 @@ build_class_member_access_expr (tree obj result = build2 (COMPOUND_EXPR, TREE_TYPE (result), object, result); } + else if ((using_decl = strip_using_decl (member)) != member) + result = build_class_member_access_expr (object, + using_decl, + access_path, preserve_reference, + complain); else { if (complain & tf_error) Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 178088) +++ gcc/cp/class.c (working copy) @@ -1053,9 +1053,6 @@ add_method (tree type, tree method, tree return false; if (DECL_CONTEXT (fn) == DECL_CONTEXT (method)) error ("repeated using declaration %q+D", using_decl); - else - error ("using declaration %q+D conflicts with a previous using declaration", - using_decl); } else { @@ -3016,15 +3013,8 @@ check_field_decls (tree t, tree *access_ if (TREE_CODE (x) == USING_DECL) { - /* Prune the access declaration from the list of fields. */ - *field = DECL_CHAIN (x); - /* Save the access declarations for our caller. */ *access_decls = tree_cons (NULL_TREE, x, *access_decls); - - /* Since we've reset *FIELD there's no reason to skip to the - next field. */ - next = field; continue; } Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 178088) +++ gcc/cp/decl.c (working copy) @@ -11937,8 +11937,20 @@ start_enum (tree name, tree enumtype, tr *is_new = true; } prevtype = enumtype; - enumtype = cxx_make_type (ENUMERAL_TYPE); - enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); + + /* do not push the decl more than once */ + if (!enumtype + || (underlying_type + && dependent_type_p (underlying_type)) + || (ENUM_UNDERLYING_TYPE (enumtype) + && dependent_type_p (ENUM_UNDERLYING_TYPE (enumtype)))) + { + enumtype = cxx_make_type (ENUMERAL_TYPE); + enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); + } + else + enumtype = xref_tag (enum_type, name, /*tag_scope=*/ts_current, false); + if (enumtype == error_mark_node) return error_mark_node; Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 178088) +++ gcc/cp/semantics.c (working copy) @@ -2670,8 +2670,7 @@ finish_member_declaration (tree decl) } } /* Enter the DECL into the scope of the class. */ - else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) - || pushdecl_class_level (decl)) + else if (pushdecl_class_level (decl)) { /* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields go at the beginning. The reason is that lookup_field_1 Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 178088) +++ gcc/cp/parser.c (working copy) @@ -13046,6 +13046,9 @@ cp_parser_nonclass_name (cp_parser* pars /* Look up the type-name. */ type_decl = cp_parser_lookup_name_simple (parser, identifier, token->location); + /* If it is a using decl, use its underlying decl. */ + type_decl = strip_using_decl (type_decl); + if (TREE_CODE (type_decl) != TYPE_DECL && (objc_is_id (identifier) || objc_is_class_name (identifier))) { Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 178088) +++ gcc/cp/cp-tree.h (working copy) @@ -5776,7 +5776,8 @@ extern void cxx_omp_finish_clause (tree extern bool cxx_omp_privatize_by_reference (const_tree); /* in name-lookup.c */ -extern void suggest_alternatives_for (location_t, tree); +extern void suggest_alternatives_for (location_t, tree); +extern tree strip_using_decl (tree); /* -- end of C++ */ Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c (revision 178088) +++ gcc/cp/search.c (working copy) @@ -1,7 +1,7 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -449,6 +449,8 @@ lookup_field_1 (tree type, tree name, bo #endif /* GATHER_STATISTICS */ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) { + tree decl = field; + #ifdef GATHER_STATISTICS n_fields_searched++; #endif /* GATHER_STATISTICS */ @@ -460,26 +462,19 @@ lookup_field_1 (tree type, tree name, bo if (temp) return temp; } - if (TREE_CODE (field) == USING_DECL) + + if (TREE_CODE (decl) == USING_DECL) { - /* We generally treat class-scope using-declarations as - ARM-style access specifications, because support for the - ISO semantics has not been implemented. So, in general, - there's no reason to return a USING_DECL, and the rest of - the compiler cannot handle that. Once the class is - defined, USING_DECLs are purged from TYPE_FIELDS; see - handle_using_decl. However, we make special efforts to - make using-declarations in class templates and class - template partial specializations work correctly. */ - if (!DECL_DEPENDENT_P (field)) + decl = strip_using_decl (decl); + if (is_overloaded_fn (decl)) continue; } - if (DECL_NAME (field) == name + if (DECL_NAME (decl) == name && (!want_type - || TREE_CODE (field) == TYPE_DECL - || DECL_CLASS_TEMPLATE_P (field))) - return field; + || TREE_CODE (decl) == TYPE_DECL + || DECL_CLASS_TEMPLATE_P (decl))) + return decl; } /* Not found. */ if (name == vptr_identifier) Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 178088) +++ gcc/cp/name-lookup.c (working copy) @@ -394,6 +394,16 @@ pop_binding (tree id, tree decl) } } +/* Strip non dependent using declarations. */ + +tree +strip_using_decl (tree decl) +{ + while (TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) + decl = USING_DECL_DECLS (decl); + return decl; +} + /* BINDING records an existing declaration for a name in the current scope. But, DECL is another declaration for that same identifier in the same scope. This is the `struct stat' hack whereby a non-typedef @@ -417,29 +427,45 @@ supplement_binding_1 (cxx_binding *bindi { tree bval = binding->value; bool ok = true; + tree target_bval = strip_using_decl (bval); + tree target_decl = strip_using_decl (decl); - if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) + if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl) + && target_decl != target_bval + && (TREE_CODE (target_bval) != TYPE_DECL + /* We allow pushing an enum multiple times in a class + * template in order to handle late matching of underlying + * type on an opaque-enum-declaration followed by an + * enum-specifier. */ + || (TREE_CODE (TREE_TYPE (target_decl)) == ENUMERAL_TYPE + && TREE_CODE (TREE_TYPE (target_bval)) == ENUMERAL_TYPE + && (dependent_type_p (ENUM_UNDERLYING_TYPE + (TREE_TYPE (target_decl))) + || dependent_type_p (ENUM_UNDERLYING_TYPE + (TREE_TYPE (target_bval)))) + ))) /* The new name is the type name. */ binding->type = decl; - else if (/* BVAL is null when push_class_level_binding moves an + else if (/* TARGET_BVAL is null when push_class_level_binding moves an inherited type-binding out of the way to make room for a new value binding. */ - !bval - /* BVAL is error_mark_node when DECL's name has been used + !target_bval + /* TARGET_BVAL is error_mark_node when TARGET_DECL's name has been used in a non-class scope prior declaration. In that case, we should have already issued a diagnostic; for graceful error recovery purpose, pretend this was the intended declaration for that name. */ - || bval == error_mark_node - /* If BVAL is anticipated but has not yet been declared, + || target_bval == error_mark_node + /* If TARGET_BVAL is anticipated but has not yet been declared, pretend it is not there at all. */ - || (TREE_CODE (bval) == FUNCTION_DECL - && DECL_ANTICIPATED (bval) - && !DECL_HIDDEN_FRIEND_P (bval))) + || (TREE_CODE (target_bval) == FUNCTION_DECL + && DECL_ANTICIPATED (target_bval) + && !DECL_HIDDEN_FRIEND_P (target_bval))) binding->value = decl; - else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval) - && (TREE_CODE (decl) != TYPE_DECL - || same_type_p (TREE_TYPE (decl), TREE_TYPE (bval)))) + else if (TREE_CODE (target_bval) == TYPE_DECL && DECL_ARTIFICIAL (target_bval) + && target_decl != target_bval + && (TREE_CODE (target_decl) != TYPE_DECL + || same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval)))) { /* The old binding was a type name. It was placed in VALUE field because it was thought, at the point it was @@ -450,15 +476,15 @@ supplement_binding_1 (cxx_binding *bindi binding->value = decl; binding->value_is_inherited = false; } - else if (TREE_CODE (bval) == TYPE_DECL - && TREE_CODE (decl) == TYPE_DECL - && DECL_NAME (decl) == DECL_NAME (bval) + else if (TREE_CODE (target_bval) == TYPE_DECL + && TREE_CODE (target_decl) == TYPE_DECL + && DECL_NAME (target_decl) == DECL_NAME (target_bval) && binding->scope->kind != sk_class - && (same_type_p (TREE_TYPE (decl), TREE_TYPE (bval)) + && (same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval)) /* If either type involves template parameters, we must wait until instantiation. */ - || uses_template_parms (TREE_TYPE (decl)) - || uses_template_parms (TREE_TYPE (bval)))) + || uses_template_parms (TREE_TYPE (target_decl)) + || uses_template_parms (TREE_TYPE (target_bval)))) /* We have two typedef-names, both naming the same type to have the same name. In general, this is OK because of: @@ -480,9 +506,9 @@ supplement_binding_1 (cxx_binding *bindi A member shall not be declared twice in the member-specification. */ - else if (TREE_CODE (decl) == VAR_DECL && TREE_CODE (bval) == VAR_DECL - && DECL_EXTERNAL (decl) && DECL_EXTERNAL (bval) - && !DECL_CLASS_SCOPE_P (decl)) + else if (TREE_CODE (target_decl) == VAR_DECL && TREE_CODE (target_bval) == VAR_DECL + && DECL_EXTERNAL (target_decl) && DECL_EXTERNAL (target_bval) + && !DECL_CLASS_SCOPE_P (target_decl)) { duplicate_decls (decl, binding->value, /*newdecl_is_friend=*/false); ok = false; @@ -3018,6 +3044,8 @@ push_class_level_binding_1 (tree name, t { tree bval = binding->value; tree old_decl = NULL_TREE; + tree target_decl = strip_using_decl (decl); + tree target_bval = strip_using_decl (bval); if (INHERITED_VALUE_BINDING_P (binding)) { @@ -3025,8 +3053,8 @@ push_class_level_binding_1 (tree name, t tag name, slide it over to make room for the new binding. The old binding is still visible if explicitly qualified with a class-key. */ - if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval) - && !(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x))) + if (TREE_CODE (target_bval) == TYPE_DECL && DECL_ARTIFICIAL (target_bval) + && !(TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl))) { old_decl = binding->type; binding->type = bval; @@ -3038,18 +3066,21 @@ push_class_level_binding_1 (tree name, t old_decl = bval; /* Any inherited type declaration is hidden by the type declaration in the derived class. */ - if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)) + if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl)) binding->type = NULL_TREE; } } - else if (TREE_CODE (x) == OVERLOAD && is_overloaded_fn (bval)) - old_decl = bval; - else if (TREE_CODE (x) == USING_DECL && TREE_CODE (bval) == USING_DECL) - return true; - else if (TREE_CODE (x) == USING_DECL && is_overloaded_fn (bval)) + else if (TREE_CODE (target_decl) == OVERLOAD && is_overloaded_fn (target_bval)) old_decl = bval; - else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (x)) + else if (TREE_CODE (decl) == USING_DECL + && DECL_DEPENDENT_P (decl) + && TREE_CODE (bval) == USING_DECL + && DECL_DEPENDENT_P (bval)) return true; + else if (TREE_CODE (decl) == USING_DECL && is_overloaded_fn (target_bval)) + old_decl = bval; + else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (target_decl)) + return true; if (old_decl && binding->scope == class_binding_level) { Index: gcc/dbxout.c =================================================================== --- gcc/dbxout.c (revision 178088) +++ gcc/dbxout.c (working copy) @@ -1518,6 +1518,8 @@ dbxout_type_fields (tree type) if (TREE_CODE (tem) == TYPE_DECL /* Omit here the nameless fields that are used to skip bits. */ || DECL_IGNORED_P (tem) + /* Omit USING_DECL */ + || TREE_CODE (tem) >= LAST_AND_UNUSED_TREE_CODE /* Omit fields whose position or size are variable or too large to represent. */ || (TREE_CODE (tem) == FIELD_DECL ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-25 20:49 ` Fabien Chêne @ 2011-09-25 21:05 ` Paolo Carlini 2011-09-25 21:48 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Paolo Carlini @ 2011-09-25 21:05 UTC (permalink / raw) To: Fabien Chêne; +Cc: Jason Merrill, gcc-patches ... nitpicking, of course, but in the testcases you have many blank trailing lines (and also some gratuitus, imho, blank lines in the middle) Paolo ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-25 21:05 ` Paolo Carlini @ 2011-09-25 21:48 ` Fabien Chêne 2011-09-25 22:35 ` Paolo Carlini 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2011-09-25 21:48 UTC (permalink / raw) To: Paolo Carlini; +Cc: Jason Merrill, gcc-patches [-- Attachment #1: Type: text/plain, Size: 321 bytes --] 2011/9/25 Paolo Carlini <pcarlini@gmail.com>: > ... nitpicking, of course, but in the testcases you have many blank trailing lines (and also some gratuitus, imho, blank lines in the middle) Indeed, I've removed the blank trailing lines, and some in the middle, not all though, I like it readable as well ;-) -- Fabien [-- Attachment #2: 26256.txt --] [-- Type: text/plain, Size: 26385 bytes --] Index: gcc/testsuite/g++.old-deja/g++.other/using1.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.other/using1.C (revision 178088) +++ gcc/testsuite/g++.old-deja/g++.other/using1.C (working copy) @@ -16,12 +16,12 @@ public: using B::b; }; -class D2 : public B { // { dg-error "" } conflicting access specifications +class D2 : public B { public: using B::a; - using B::b; + using B::b; // { dg-message "" } conflicting declaration private: - using B::b; + using B::b; // { dg-error "" } conflicts }; Index: gcc/testsuite/g++.dg/debug/using4.C =================================================================== --- gcc/testsuite/g++.dg/debug/using4.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using4.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + typedef char type; +}; + +struct B +{ + typedef int type; +}; + +struct C : A, B +{ + using A::type; + type f (type); +}; + +C::type C::f( type ) +{ + type c = 'e'; + return c; +} Index: gcc/testsuite/g++.dg/debug/using5.C =================================================================== --- gcc/testsuite/g++.dg/debug/using5.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using5.C (revision 0) @@ -0,0 +1,23 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using B::i; + int f (); +}; + +int C::f() +{ + return i; +} Index: gcc/testsuite/g++.dg/lookup/using36.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using36.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using36.C (revision 0) @@ -0,0 +1,31 @@ +// PR c++/25994 +// { dg-do run } + +struct B1 +{ + void f (char) {} + void f (double) { __builtin_abort(); } +}; + +struct B2 +{ + void f (double) { __builtin_abort(); } + void f (int) {} +}; + +struct D : public B1, public B2 +{ + using B1::f; + using B2::f; + void g () + { + f ('a'); // should call B1::f(char) + f (33); // should call B2::f(int) + } +}; + +int main() +{ + D d; + d.g(); +} Index: gcc/testsuite/g++.dg/lookup/using24.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using24.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using24.C (revision 0) @@ -0,0 +1,12 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int next; }; +struct B { int next; }; +struct C : B { using B::next; }; + +struct D : A, C +{ + using C::next; + void f() { next = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using28.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using28.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using28.C (revision 0) @@ -0,0 +1,11 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int f; }; +struct B { int f; }; +struct C : A, B { using B::f; }; + +struct D : C +{ + void g() { f = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using33.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using33.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using33.C (revision 0) @@ -0,0 +1,26 @@ +// { dg-do run } + +template <class T> +struct Foo +{ + int k (float) {return 0;} +}; + +template <class T> +struct Baz +{ + int k (int) {return 1;} +}; + +template <class T> +struct Bar : Foo<T> , Baz<T> +{ + using Foo<T>::k; + using Baz<T>::k; +}; + +int main() +{ + Bar<int> bar; + return bar.k( 1.0f ); +} Index: gcc/testsuite/g++.dg/lookup/using25.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using25.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using25.C (revision 0) @@ -0,0 +1,28 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + int next; +}; + +struct B +{ + int next; +}; + +struct C : public A, public B +{ + using A::next; +}; + +void foo(C& c) { c.next = 42; } + +int main() +{ + C c; + foo (c); + c.B::next = 12; + if (c.next != 42 || c.A::next != 42 || c.B::next != 12) + __builtin_abort(); +} Index: gcc/testsuite/g++.dg/lookup/using29.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using29.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using29.C (revision 0) @@ -0,0 +1,81 @@ +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using A::i; // { dg-error "conflicts with previous" } + using B::i; // { dg-error "declaration" } +}; + +struct E +{ + typedef int type; +}; + +struct F +{ + typedef int type; +}; + +struct G : E, F +{ + using E::type; // { dg-error "conflicts with previous" } + using F::type; // { dg-error "declaration" } +}; + +struct H +{ + typedef int type; +}; + +struct I : H +{ + typedef int type; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; + +struct I2 : H +{ + using H::type; // { dg-error "conflicts with previous" } + typedef int type; // { dg-error "declaration" } +}; + +struct J +{ + struct type {}; +}; + +struct K : J +{ + struct type {}; // { dg-error "conflicts with previous" } + using J::type; // { dg-error "declaration" } +}; + +struct L : J +{ + using J::type; // { dg-error "conflicts with previous" } + struct type {}; // { dg-error "declaration" } +}; + +struct M +{ + typedef int type; + struct type2 {}; +}; + +struct N : M +{ + using M::type; // { dg-error "conflicts with previous" } + using M::type; // { dg-error "declaration" } + using M::type2; // { dg-error "conflicts with previous" } + using M::type2; // { dg-error "declaration" } +}; Index: gcc/testsuite/g++.dg/lookup/using30.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using30.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using30.C (revision 0) @@ -0,0 +1,8 @@ +// { dg-do compile } + +struct H { typedef int type; }; +struct J : H +{ + struct type {}; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; Index: gcc/testsuite/g++.dg/lookup/using34.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using34.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using34.C (revision 0) @@ -0,0 +1,10 @@ +// { dg-do compile } + +struct A { int f (); }; +struct B : A +{ + using A::f; + struct f {}; + void g() { f(); struct f ff; } + struct f ff; +}; Index: gcc/testsuite/g++.dg/lookup/using26.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using26.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using26.C (revision 0) @@ -0,0 +1,27 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + double next; +}; + +struct B +{ +private: + int next; // { dg-error "private" } +}; + +struct C +{ + int next; +}; + +struct D : A, B, C // { dg-error "context" } +{ + using B::next; + void f() + { + next = 12; + } +}; Index: gcc/testsuite/g++.dg/lookup/using31.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using31.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using31.C (revision 0) @@ -0,0 +1,8 @@ +// { dg-do compile } + +struct H2 { int f (); }; +struct J2 : H2 +{ + struct f {}; + using H2::f; +}; Index: gcc/testsuite/g++.dg/lookup/using35.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using35.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using35.C (revision 0) @@ -0,0 +1,11 @@ +// { dg-do compile } + +struct A { typedef int type; }; +struct B { typedef int type; }; +struct C : B { using B::type; }; + +struct D : A, C +{ + using C::type; + void f() { type t = 0;} +}; Index: gcc/testsuite/g++.dg/lookup/using23.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using23.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using23.C (revision 0) @@ -0,0 +1,19 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ +private: + typedef int type; // { dg-error "private" } +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B // { dg-error "context" } +{ + using A::type; + type d; +}; Index: gcc/testsuite/g++.dg/lookup/using27.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using27.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using27.C (revision 0) @@ -0,0 +1,48 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + typedef int type; +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B +{ + using A::type; + type d; + + void f() + { + type e; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); + } + + void g(); +}; + +void C::g() +{ + type x; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); +} + +int main () +{ + if (sizeof (C::type) != sizeof (A::type)) + __builtin_abort(); + + if (sizeof (C::d) != sizeof (A::type)) + __builtin_abort(); + + C::type x; + C c; + c.f(); + c.g(); +} Index: gcc/testsuite/g++.dg/lookup/using32.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using32.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using32.C (revision 0) @@ -0,0 +1,9 @@ +// { dg-do compile } + +struct T { struct type {}; }; +struct T2 : T { using T::type; }; +struct T3 : T2 +{ + struct type {}; + type t; +}; Index: gcc/testsuite/g++.dg/cpp0x/forw_enum10.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/forw_enum10.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/forw_enum10.C (revision 0) @@ -0,0 +1,32 @@ +// { dg-do compile } +// { dg-options "-std=c++0x" } + +//This error is diagnosed at instantiation time +template<typename T> struct S1 +{ + enum E : T; // { dg-error "previous definition" } + enum E : int; // { dg-error "different underlying type" } +}; +template struct S1<short>; // { dg-message "required from here" } + +template<typename T> struct S2 +{ + enum E : T; + enum E : T; +}; +template struct S2<short>; + +template<typename T1, typename T2> struct S3 +{ + enum E : T1; + enum E : T2; +}; +template struct S3<short,short>; + +template<typename T1, typename T2> struct S4 +{ + enum E : T1; // { dg-error "previous definition" } + enum E : T2; // { dg-error "different underlying type" } +}; +template struct S4<short,char>; // { dg-message "required from here" } + Index: gcc/testsuite/g++.dg/template/using2.C =================================================================== --- gcc/testsuite/g++.dg/template/using2.C (revision 178088) +++ gcc/testsuite/g++.dg/template/using2.C (working copy) @@ -7,24 +7,25 @@ template <class T> struct Foo { - int i; // { dg-error "Foo" } + int i; }; struct Baz { - int i; // { dg-error "Baz" } + int i; }; template <class T> -struct Bar : public Foo<T>, Baz { - using Foo<T>::i; - using Baz::i; +struct Bar : public Foo<T>, Baz +{ + using Foo<T>::i; // { dg-message "conflicts with previous" } + using Baz::i; // { dg-error "declaration" } - int foo () { return i; } // { dg-error "request for member" } + int foo () { return i; } }; void foo (Bar<int> &bar) { - bar.foo(); // { dg-message "required" } + bar.foo(); } Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c (revision 178088) +++ gcc/cp/typeck.c (working copy) @@ -2109,6 +2109,7 @@ build_class_member_access_expr (tree obj tree object_type; tree member_scope; tree result = NULL_TREE; + tree using_decl = NULL_TREE; if (error_operand_p (object) || error_operand_p (member)) return error_mark_node; @@ -2329,6 +2330,11 @@ build_class_member_access_expr (tree obj result = build2 (COMPOUND_EXPR, TREE_TYPE (result), object, result); } + else if ((using_decl = strip_using_decl (member)) != member) + result = build_class_member_access_expr (object, + using_decl, + access_path, preserve_reference, + complain); else { if (complain & tf_error) Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 178088) +++ gcc/cp/class.c (working copy) @@ -1053,9 +1053,6 @@ add_method (tree type, tree method, tree return false; if (DECL_CONTEXT (fn) == DECL_CONTEXT (method)) error ("repeated using declaration %q+D", using_decl); - else - error ("using declaration %q+D conflicts with a previous using declaration", - using_decl); } else { @@ -3016,15 +3013,8 @@ check_field_decls (tree t, tree *access_ if (TREE_CODE (x) == USING_DECL) { - /* Prune the access declaration from the list of fields. */ - *field = DECL_CHAIN (x); - /* Save the access declarations for our caller. */ *access_decls = tree_cons (NULL_TREE, x, *access_decls); - - /* Since we've reset *FIELD there's no reason to skip to the - next field. */ - next = field; continue; } Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 178088) +++ gcc/cp/decl.c (working copy) @@ -11937,8 +11937,20 @@ start_enum (tree name, tree enumtype, tr *is_new = true; } prevtype = enumtype; - enumtype = cxx_make_type (ENUMERAL_TYPE); - enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); + + /* do not push the decl more than once */ + if (!enumtype + || (underlying_type + && dependent_type_p (underlying_type)) + || (ENUM_UNDERLYING_TYPE (enumtype) + && dependent_type_p (ENUM_UNDERLYING_TYPE (enumtype)))) + { + enumtype = cxx_make_type (ENUMERAL_TYPE); + enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); + } + else + enumtype = xref_tag (enum_type, name, /*tag_scope=*/ts_current, false); + if (enumtype == error_mark_node) return error_mark_node; Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 178088) +++ gcc/cp/semantics.c (working copy) @@ -2670,8 +2670,7 @@ finish_member_declaration (tree decl) } } /* Enter the DECL into the scope of the class. */ - else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) - || pushdecl_class_level (decl)) + else if (pushdecl_class_level (decl)) { /* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields go at the beginning. The reason is that lookup_field_1 Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 178088) +++ gcc/cp/parser.c (working copy) @@ -13046,6 +13046,9 @@ cp_parser_nonclass_name (cp_parser* pars /* Look up the type-name. */ type_decl = cp_parser_lookup_name_simple (parser, identifier, token->location); + /* If it is a using decl, use its underlying decl. */ + type_decl = strip_using_decl (type_decl); + if (TREE_CODE (type_decl) != TYPE_DECL && (objc_is_id (identifier) || objc_is_class_name (identifier))) { Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 178088) +++ gcc/cp/cp-tree.h (working copy) @@ -5776,7 +5776,8 @@ extern void cxx_omp_finish_clause (tree extern bool cxx_omp_privatize_by_reference (const_tree); /* in name-lookup.c */ -extern void suggest_alternatives_for (location_t, tree); +extern void suggest_alternatives_for (location_t, tree); +extern tree strip_using_decl (tree); /* -- end of C++ */ Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c (revision 178088) +++ gcc/cp/search.c (working copy) @@ -1,7 +1,7 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -449,6 +449,8 @@ lookup_field_1 (tree type, tree name, bo #endif /* GATHER_STATISTICS */ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) { + tree decl = field; + #ifdef GATHER_STATISTICS n_fields_searched++; #endif /* GATHER_STATISTICS */ @@ -460,26 +462,19 @@ lookup_field_1 (tree type, tree name, bo if (temp) return temp; } - if (TREE_CODE (field) == USING_DECL) + + if (TREE_CODE (decl) == USING_DECL) { - /* We generally treat class-scope using-declarations as - ARM-style access specifications, because support for the - ISO semantics has not been implemented. So, in general, - there's no reason to return a USING_DECL, and the rest of - the compiler cannot handle that. Once the class is - defined, USING_DECLs are purged from TYPE_FIELDS; see - handle_using_decl. However, we make special efforts to - make using-declarations in class templates and class - template partial specializations work correctly. */ - if (!DECL_DEPENDENT_P (field)) + decl = strip_using_decl (decl); + if (is_overloaded_fn (decl)) continue; } - if (DECL_NAME (field) == name + if (DECL_NAME (decl) == name && (!want_type - || TREE_CODE (field) == TYPE_DECL - || DECL_CLASS_TEMPLATE_P (field))) - return field; + || TREE_CODE (decl) == TYPE_DECL + || DECL_CLASS_TEMPLATE_P (decl))) + return decl; } /* Not found. */ if (name == vptr_identifier) @@ -1423,7 +1418,7 @@ lookup_fnfields_1 (tree type, tree name) #endif /* GATHER_STATISTICS */ tmp = VEC_index (tree, method_vec, i); - tmp = DECL_NAME (OVL_CURRENT (tmp)); + tmp = DECL_NAME (strip_using_decl (OVL_CURRENT (tmp))); if (tmp > name) hi = i; else if (tmp < name) @@ -1438,7 +1433,7 @@ lookup_fnfields_1 (tree type, tree name) #ifdef GATHER_STATISTICS n_outer_fields_searched++; #endif /* GATHER_STATISTICS */ - if (DECL_NAME (OVL_CURRENT (fn)) == name) + if (DECL_NAME (strip_using_decl (OVL_CURRENT (fn))) == name) return i; } Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 178088) +++ gcc/cp/name-lookup.c (working copy) @@ -394,6 +394,16 @@ pop_binding (tree id, tree decl) } } +/* Strip non dependent using declarations. */ + +tree +strip_using_decl (tree decl) +{ + while (TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) + decl = USING_DECL_DECLS (decl); + return decl; +} + /* BINDING records an existing declaration for a name in the current scope. But, DECL is another declaration for that same identifier in the same scope. This is the `struct stat' hack whereby a non-typedef @@ -417,29 +427,45 @@ supplement_binding_1 (cxx_binding *bindi { tree bval = binding->value; bool ok = true; + tree target_bval = strip_using_decl (bval); + tree target_decl = strip_using_decl (decl); - if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) + if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl) + && target_decl != target_bval + && (TREE_CODE (target_bval) != TYPE_DECL + /* We allow pushing an enum multiple times in a class + * template in order to handle late matching of underlying + * type on an opaque-enum-declaration followed by an + * enum-specifier. */ + || (TREE_CODE (TREE_TYPE (target_decl)) == ENUMERAL_TYPE + && TREE_CODE (TREE_TYPE (target_bval)) == ENUMERAL_TYPE + && (dependent_type_p (ENUM_UNDERLYING_TYPE + (TREE_TYPE (target_decl))) + || dependent_type_p (ENUM_UNDERLYING_TYPE + (TREE_TYPE (target_bval)))) + ))) /* The new name is the type name. */ binding->type = decl; - else if (/* BVAL is null when push_class_level_binding moves an + else if (/* TARGET_BVAL is null when push_class_level_binding moves an inherited type-binding out of the way to make room for a new value binding. */ - !bval - /* BVAL is error_mark_node when DECL's name has been used + !target_bval + /* TARGET_BVAL is error_mark_node when TARGET_DECL's name has been used in a non-class scope prior declaration. In that case, we should have already issued a diagnostic; for graceful error recovery purpose, pretend this was the intended declaration for that name. */ - || bval == error_mark_node - /* If BVAL is anticipated but has not yet been declared, + || target_bval == error_mark_node + /* If TARGET_BVAL is anticipated but has not yet been declared, pretend it is not there at all. */ - || (TREE_CODE (bval) == FUNCTION_DECL - && DECL_ANTICIPATED (bval) - && !DECL_HIDDEN_FRIEND_P (bval))) + || (TREE_CODE (target_bval) == FUNCTION_DECL + && DECL_ANTICIPATED (target_bval) + && !DECL_HIDDEN_FRIEND_P (target_bval))) binding->value = decl; - else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval) - && (TREE_CODE (decl) != TYPE_DECL - || same_type_p (TREE_TYPE (decl), TREE_TYPE (bval)))) + else if (TREE_CODE (target_bval) == TYPE_DECL && DECL_ARTIFICIAL (target_bval) + && target_decl != target_bval + && (TREE_CODE (target_decl) != TYPE_DECL + || same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval)))) { /* The old binding was a type name. It was placed in VALUE field because it was thought, at the point it was @@ -450,15 +476,15 @@ supplement_binding_1 (cxx_binding *bindi binding->value = decl; binding->value_is_inherited = false; } - else if (TREE_CODE (bval) == TYPE_DECL - && TREE_CODE (decl) == TYPE_DECL - && DECL_NAME (decl) == DECL_NAME (bval) + else if (TREE_CODE (target_bval) == TYPE_DECL + && TREE_CODE (target_decl) == TYPE_DECL + && DECL_NAME (target_decl) == DECL_NAME (target_bval) && binding->scope->kind != sk_class - && (same_type_p (TREE_TYPE (decl), TREE_TYPE (bval)) + && (same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval)) /* If either type involves template parameters, we must wait until instantiation. */ - || uses_template_parms (TREE_TYPE (decl)) - || uses_template_parms (TREE_TYPE (bval)))) + || uses_template_parms (TREE_TYPE (target_decl)) + || uses_template_parms (TREE_TYPE (target_bval)))) /* We have two typedef-names, both naming the same type to have the same name. In general, this is OK because of: @@ -480,9 +506,9 @@ supplement_binding_1 (cxx_binding *bindi A member shall not be declared twice in the member-specification. */ - else if (TREE_CODE (decl) == VAR_DECL && TREE_CODE (bval) == VAR_DECL - && DECL_EXTERNAL (decl) && DECL_EXTERNAL (bval) - && !DECL_CLASS_SCOPE_P (decl)) + else if (TREE_CODE (target_decl) == VAR_DECL && TREE_CODE (target_bval) == VAR_DECL + && DECL_EXTERNAL (target_decl) && DECL_EXTERNAL (target_bval) + && !DECL_CLASS_SCOPE_P (target_decl)) { duplicate_decls (decl, binding->value, /*newdecl_is_friend=*/false); ok = false; @@ -3018,6 +3044,8 @@ push_class_level_binding_1 (tree name, t { tree bval = binding->value; tree old_decl = NULL_TREE; + tree target_decl = strip_using_decl (decl); + tree target_bval = strip_using_decl (bval); if (INHERITED_VALUE_BINDING_P (binding)) { @@ -3025,8 +3053,8 @@ push_class_level_binding_1 (tree name, t tag name, slide it over to make room for the new binding. The old binding is still visible if explicitly qualified with a class-key. */ - if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval) - && !(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x))) + if (TREE_CODE (target_bval) == TYPE_DECL && DECL_ARTIFICIAL (target_bval) + && !(TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl))) { old_decl = binding->type; binding->type = bval; @@ -3038,18 +3066,21 @@ push_class_level_binding_1 (tree name, t old_decl = bval; /* Any inherited type declaration is hidden by the type declaration in the derived class. */ - if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)) + if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl)) binding->type = NULL_TREE; } } - else if (TREE_CODE (x) == OVERLOAD && is_overloaded_fn (bval)) - old_decl = bval; - else if (TREE_CODE (x) == USING_DECL && TREE_CODE (bval) == USING_DECL) - return true; - else if (TREE_CODE (x) == USING_DECL && is_overloaded_fn (bval)) + else if (TREE_CODE (target_decl) == OVERLOAD && is_overloaded_fn (target_bval)) old_decl = bval; - else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (x)) + else if (TREE_CODE (decl) == USING_DECL + && DECL_DEPENDENT_P (decl) + && TREE_CODE (bval) == USING_DECL + && DECL_DEPENDENT_P (bval)) return true; + else if (TREE_CODE (decl) == USING_DECL && is_overloaded_fn (target_bval)) + old_decl = bval; + else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (target_decl)) + return true; if (old_decl && binding->scope == class_binding_level) { Index: gcc/dbxout.c =================================================================== --- gcc/dbxout.c (revision 178088) +++ gcc/dbxout.c (working copy) @@ -1518,6 +1518,8 @@ dbxout_type_fields (tree type) if (TREE_CODE (tem) == TYPE_DECL /* Omit here the nameless fields that are used to skip bits. */ || DECL_IGNORED_P (tem) + /* Omit USING_DECL */ + || TREE_CODE (tem) >= LAST_AND_UNUSED_TREE_CODE /* Omit fields whose position or size are variable or too large to represent. */ || (TREE_CODE (tem) == FIELD_DECL ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-25 21:48 ` Fabien Chêne @ 2011-09-25 22:35 ` Paolo Carlini 2011-09-26 1:28 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Paolo Carlini @ 2011-09-25 22:35 UTC (permalink / raw) To: Fabien Chêne; +Cc: Paolo Carlini, Jason Merrill, gcc-patches Hi, > Indeed, I've removed the blank trailing lines, and some in the middle, > not all though, I like it readable as well ;-) Thanks! Paolo ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-25 22:35 ` Paolo Carlini @ 2011-09-26 1:28 ` Fabien Chêne 2011-09-26 14:28 ` Jason Merrill 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2011-09-26 1:28 UTC (permalink / raw) To: Paolo Carlini; +Cc: Jason Merrill, gcc-patches [-- Attachment #1: Type: text/plain, Size: 175 bytes --] Jason, Please ignore the previous patch, where I have introduced an unintentional modification for PR c++/30195 in search.c, here is a new one, sorry about that. -- Fabien [-- Attachment #2: 26256.txt --] [-- Type: text/plain, Size: 25803 bytes --] Index: gcc/testsuite/g++.old-deja/g++.other/using1.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.other/using1.C (revision 178088) +++ gcc/testsuite/g++.old-deja/g++.other/using1.C (working copy) @@ -16,12 +16,12 @@ public: using B::b; }; -class D2 : public B { // { dg-error "" } conflicting access specifications +class D2 : public B { public: using B::a; - using B::b; + using B::b; // { dg-message "" } conflicting declaration private: - using B::b; + using B::b; // { dg-error "" } conflicts }; Index: gcc/testsuite/g++.dg/debug/using4.C =================================================================== --- gcc/testsuite/g++.dg/debug/using4.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using4.C (revision 0) @@ -0,0 +1,24 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + typedef char type; +}; + +struct B +{ + typedef int type; +}; + +struct C : A, B +{ + using A::type; + type f (type); +}; + +C::type C::f( type ) +{ + type c = 'e'; + return c; +} Index: gcc/testsuite/g++.dg/debug/using5.C =================================================================== --- gcc/testsuite/g++.dg/debug/using5.C (revision 0) +++ gcc/testsuite/g++.dg/debug/using5.C (revision 0) @@ -0,0 +1,23 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using B::i; + int f (); +}; + +int C::f() +{ + return i; +} Index: gcc/testsuite/g++.dg/lookup/using36.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using36.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using36.C (revision 0) @@ -0,0 +1,31 @@ +// PR c++/25994 +// { dg-do run } + +struct B1 +{ + void f (char) {} + void f (double) { __builtin_abort(); } +}; + +struct B2 +{ + void f (double) { __builtin_abort(); } + void f (int) {} +}; + +struct D : public B1, public B2 +{ + using B1::f; + using B2::f; + void g () + { + f ('a'); // should call B1::f(char) + f (33); // should call B2::f(int) + } +}; + +int main() +{ + D d; + d.g(); +} Index: gcc/testsuite/g++.dg/lookup/using24.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using24.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using24.C (revision 0) @@ -0,0 +1,12 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int next; }; +struct B { int next; }; +struct C : B { using B::next; }; + +struct D : A, C +{ + using C::next; + void f() { next = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using28.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using28.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using28.C (revision 0) @@ -0,0 +1,11 @@ +// PR c++/26256 +// { dg-do compile } + +struct A { int f; }; +struct B { int f; }; +struct C : A, B { using B::f; }; + +struct D : C +{ + void g() { f = 1; } +}; Index: gcc/testsuite/g++.dg/lookup/using33.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using33.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using33.C (revision 0) @@ -0,0 +1,26 @@ +// { dg-do run } + +template <class T> +struct Foo +{ + int k (float) {return 0;} +}; + +template <class T> +struct Baz +{ + int k (int) {return 1;} +}; + +template <class T> +struct Bar : Foo<T> , Baz<T> +{ + using Foo<T>::k; + using Baz<T>::k; +}; + +int main() +{ + Bar<int> bar; + return bar.k( 1.0f ); +} Index: gcc/testsuite/g++.dg/lookup/using25.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using25.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using25.C (revision 0) @@ -0,0 +1,28 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + int next; +}; + +struct B +{ + int next; +}; + +struct C : public A, public B +{ + using A::next; +}; + +void foo(C& c) { c.next = 42; } + +int main() +{ + C c; + foo (c); + c.B::next = 12; + if (c.next != 42 || c.A::next != 42 || c.B::next != 12) + __builtin_abort(); +} Index: gcc/testsuite/g++.dg/lookup/using29.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using29.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using29.C (revision 0) @@ -0,0 +1,81 @@ +// { dg-do compile } + +struct A +{ + int i; +}; + +struct B +{ + int i; +}; + +struct C : A, B +{ + using A::i; // { dg-error "conflicts with previous" } + using B::i; // { dg-error "declaration" } +}; + +struct E +{ + typedef int type; +}; + +struct F +{ + typedef int type; +}; + +struct G : E, F +{ + using E::type; // { dg-error "conflicts with previous" } + using F::type; // { dg-error "declaration" } +}; + +struct H +{ + typedef int type; +}; + +struct I : H +{ + typedef int type; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; + +struct I2 : H +{ + using H::type; // { dg-error "conflicts with previous" } + typedef int type; // { dg-error "declaration" } +}; + +struct J +{ + struct type {}; +}; + +struct K : J +{ + struct type {}; // { dg-error "conflicts with previous" } + using J::type; // { dg-error "declaration" } +}; + +struct L : J +{ + using J::type; // { dg-error "conflicts with previous" } + struct type {}; // { dg-error "declaration" } +}; + +struct M +{ + typedef int type; + struct type2 {}; +}; + +struct N : M +{ + using M::type; // { dg-error "conflicts with previous" } + using M::type; // { dg-error "declaration" } + using M::type2; // { dg-error "conflicts with previous" } + using M::type2; // { dg-error "declaration" } +}; Index: gcc/testsuite/g++.dg/lookup/using30.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using30.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using30.C (revision 0) @@ -0,0 +1,8 @@ +// { dg-do compile } + +struct H { typedef int type; }; +struct J : H +{ + struct type {}; // { dg-error "conflicts with previous" } + using H::type; // { dg-error "declaration" } +}; Index: gcc/testsuite/g++.dg/lookup/using34.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using34.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using34.C (revision 0) @@ -0,0 +1,10 @@ +// { dg-do compile } + +struct A { int f (); }; +struct B : A +{ + using A::f; + struct f {}; + void g() { f(); struct f ff; } + struct f ff; +}; Index: gcc/testsuite/g++.dg/lookup/using26.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using26.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using26.C (revision 0) @@ -0,0 +1,27 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ + double next; +}; + +struct B +{ +private: + int next; // { dg-error "private" } +}; + +struct C +{ + int next; +}; + +struct D : A, B, C // { dg-error "context" } +{ + using B::next; + void f() + { + next = 12; + } +}; Index: gcc/testsuite/g++.dg/lookup/using31.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using31.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using31.C (revision 0) @@ -0,0 +1,8 @@ +// { dg-do compile } + +struct H2 { int f (); }; +struct J2 : H2 +{ + struct f {}; + using H2::f; +}; Index: gcc/testsuite/g++.dg/lookup/using35.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using35.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using35.C (revision 0) @@ -0,0 +1,11 @@ +// { dg-do compile } + +struct A { typedef int type; }; +struct B { typedef int type; }; +struct C : B { using B::type; }; + +struct D : A, C +{ + using C::type; + void f() { type t = 0;} +}; Index: gcc/testsuite/g++.dg/lookup/using23.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using23.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using23.C (revision 0) @@ -0,0 +1,19 @@ +// PR c++/26256 +// { dg-do compile } + +struct A +{ +private: + typedef int type; // { dg-error "private" } +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B // { dg-error "context" } +{ + using A::type; + type d; +}; Index: gcc/testsuite/g++.dg/lookup/using27.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using27.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using27.C (revision 0) @@ -0,0 +1,48 @@ +// PR c++/26256 +// { dg-do run } + +struct A +{ + typedef int type; +}; + +struct B +{ + typedef double type; +}; + +struct C : A, B +{ + using A::type; + type d; + + void f() + { + type e; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); + } + + void g(); +}; + +void C::g() +{ + type x; + if (sizeof (type) != sizeof (A::type)) + __builtin_abort(); +} + +int main () +{ + if (sizeof (C::type) != sizeof (A::type)) + __builtin_abort(); + + if (sizeof (C::d) != sizeof (A::type)) + __builtin_abort(); + + C::type x; + C c; + c.f(); + c.g(); +} Index: gcc/testsuite/g++.dg/lookup/using32.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using32.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using32.C (revision 0) @@ -0,0 +1,9 @@ +// { dg-do compile } + +struct T { struct type {}; }; +struct T2 : T { using T::type; }; +struct T3 : T2 +{ + struct type {}; + type t; +}; Index: gcc/testsuite/g++.dg/cpp0x/forw_enum10.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/forw_enum10.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/forw_enum10.C (revision 0) @@ -0,0 +1,32 @@ +// { dg-do compile } +// { dg-options "-std=c++0x" } + +//This error is diagnosed at instantiation time +template<typename T> struct S1 +{ + enum E : T; // { dg-error "previous definition" } + enum E : int; // { dg-error "different underlying type" } +}; +template struct S1<short>; // { dg-message "required from here" } + +template<typename T> struct S2 +{ + enum E : T; + enum E : T; +}; +template struct S2<short>; + +template<typename T1, typename T2> struct S3 +{ + enum E : T1; + enum E : T2; +}; +template struct S3<short,short>; + +template<typename T1, typename T2> struct S4 +{ + enum E : T1; // { dg-error "previous definition" } + enum E : T2; // { dg-error "different underlying type" } +}; +template struct S4<short,char>; // { dg-message "required from here" } + Index: gcc/testsuite/g++.dg/template/using2.C =================================================================== --- gcc/testsuite/g++.dg/template/using2.C (revision 178088) +++ gcc/testsuite/g++.dg/template/using2.C (working copy) @@ -7,24 +7,25 @@ template <class T> struct Foo { - int i; // { dg-error "Foo" } + int i; }; struct Baz { - int i; // { dg-error "Baz" } + int i; }; template <class T> -struct Bar : public Foo<T>, Baz { - using Foo<T>::i; - using Baz::i; +struct Bar : public Foo<T>, Baz +{ + using Foo<T>::i; // { dg-message "conflicts with previous" } + using Baz::i; // { dg-error "declaration" } - int foo () { return i; } // { dg-error "request for member" } + int foo () { return i; } }; void foo (Bar<int> &bar) { - bar.foo(); // { dg-message "required" } + bar.foo(); } Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c (revision 178088) +++ gcc/cp/typeck.c (working copy) @@ -2109,6 +2109,7 @@ build_class_member_access_expr (tree obj tree object_type; tree member_scope; tree result = NULL_TREE; + tree using_decl = NULL_TREE; if (error_operand_p (object) || error_operand_p (member)) return error_mark_node; @@ -2329,6 +2330,11 @@ build_class_member_access_expr (tree obj result = build2 (COMPOUND_EXPR, TREE_TYPE (result), object, result); } + else if ((using_decl = strip_using_decl (member)) != member) + result = build_class_member_access_expr (object, + using_decl, + access_path, preserve_reference, + complain); else { if (complain & tf_error) Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 178088) +++ gcc/cp/class.c (working copy) @@ -1053,9 +1053,6 @@ add_method (tree type, tree method, tree return false; if (DECL_CONTEXT (fn) == DECL_CONTEXT (method)) error ("repeated using declaration %q+D", using_decl); - else - error ("using declaration %q+D conflicts with a previous using declaration", - using_decl); } else { @@ -3016,15 +3013,8 @@ check_field_decls (tree t, tree *access_ if (TREE_CODE (x) == USING_DECL) { - /* Prune the access declaration from the list of fields. */ - *field = DECL_CHAIN (x); - /* Save the access declarations for our caller. */ *access_decls = tree_cons (NULL_TREE, x, *access_decls); - - /* Since we've reset *FIELD there's no reason to skip to the - next field. */ - next = field; continue; } Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 178088) +++ gcc/cp/decl.c (working copy) @@ -11937,8 +11937,20 @@ start_enum (tree name, tree enumtype, tr *is_new = true; } prevtype = enumtype; - enumtype = cxx_make_type (ENUMERAL_TYPE); - enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); + + /* do not push the decl more than once */ + if (!enumtype + || (underlying_type + && dependent_type_p (underlying_type)) + || (ENUM_UNDERLYING_TYPE (enumtype) + && dependent_type_p (ENUM_UNDERLYING_TYPE (enumtype)))) + { + enumtype = cxx_make_type (ENUMERAL_TYPE); + enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); + } + else + enumtype = xref_tag (enum_type, name, /*tag_scope=*/ts_current, false); + if (enumtype == error_mark_node) return error_mark_node; Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 178088) +++ gcc/cp/semantics.c (working copy) @@ -2670,8 +2670,7 @@ finish_member_declaration (tree decl) } } /* Enter the DECL into the scope of the class. */ - else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) - || pushdecl_class_level (decl)) + else if (pushdecl_class_level (decl)) { /* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields go at the beginning. The reason is that lookup_field_1 Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 178088) +++ gcc/cp/parser.c (working copy) @@ -13046,6 +13046,9 @@ cp_parser_nonclass_name (cp_parser* pars /* Look up the type-name. */ type_decl = cp_parser_lookup_name_simple (parser, identifier, token->location); + /* If it is a using decl, use its underlying decl. */ + type_decl = strip_using_decl (type_decl); + if (TREE_CODE (type_decl) != TYPE_DECL && (objc_is_id (identifier) || objc_is_class_name (identifier))) { Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 178088) +++ gcc/cp/cp-tree.h (working copy) @@ -5776,7 +5776,8 @@ extern void cxx_omp_finish_clause (tree extern bool cxx_omp_privatize_by_reference (const_tree); /* in name-lookup.c */ -extern void suggest_alternatives_for (location_t, tree); +extern void suggest_alternatives_for (location_t, tree); +extern tree strip_using_decl (tree); /* -- end of C++ */ Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c (revision 178088) +++ gcc/cp/search.c (working copy) @@ -1,7 +1,7 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -449,6 +449,8 @@ lookup_field_1 (tree type, tree name, bo #endif /* GATHER_STATISTICS */ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) { + tree decl = field; + #ifdef GATHER_STATISTICS n_fields_searched++; #endif /* GATHER_STATISTICS */ @@ -460,26 +462,19 @@ lookup_field_1 (tree type, tree name, bo if (temp) return temp; } - if (TREE_CODE (field) == USING_DECL) + + if (TREE_CODE (decl) == USING_DECL) { - /* We generally treat class-scope using-declarations as - ARM-style access specifications, because support for the - ISO semantics has not been implemented. So, in general, - there's no reason to return a USING_DECL, and the rest of - the compiler cannot handle that. Once the class is - defined, USING_DECLs are purged from TYPE_FIELDS; see - handle_using_decl. However, we make special efforts to - make using-declarations in class templates and class - template partial specializations work correctly. */ - if (!DECL_DEPENDENT_P (field)) + decl = strip_using_decl (decl); + if (is_overloaded_fn (decl)) continue; } - if (DECL_NAME (field) == name + if (DECL_NAME (decl) == name && (!want_type - || TREE_CODE (field) == TYPE_DECL - || DECL_CLASS_TEMPLATE_P (field))) - return field; + || TREE_CODE (decl) == TYPE_DECL + || DECL_CLASS_TEMPLATE_P (decl))) + return decl; } /* Not found. */ if (name == vptr_identifier) Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 178088) +++ gcc/cp/name-lookup.c (working copy) @@ -394,6 +394,16 @@ pop_binding (tree id, tree decl) } } +/* Strip non dependent using declarations. */ + +tree +strip_using_decl (tree decl) +{ + while (TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) + decl = USING_DECL_DECLS (decl); + return decl; +} + /* BINDING records an existing declaration for a name in the current scope. But, DECL is another declaration for that same identifier in the same scope. This is the `struct stat' hack whereby a non-typedef @@ -417,29 +427,45 @@ supplement_binding_1 (cxx_binding *bindi { tree bval = binding->value; bool ok = true; + tree target_bval = strip_using_decl (bval); + tree target_decl = strip_using_decl (decl); - if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) + if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl) + && target_decl != target_bval + && (TREE_CODE (target_bval) != TYPE_DECL + /* We allow pushing an enum multiple times in a class + * template in order to handle late matching of underlying + * type on an opaque-enum-declaration followed by an + * enum-specifier. */ + || (TREE_CODE (TREE_TYPE (target_decl)) == ENUMERAL_TYPE + && TREE_CODE (TREE_TYPE (target_bval)) == ENUMERAL_TYPE + && (dependent_type_p (ENUM_UNDERLYING_TYPE + (TREE_TYPE (target_decl))) + || dependent_type_p (ENUM_UNDERLYING_TYPE + (TREE_TYPE (target_bval)))) + ))) /* The new name is the type name. */ binding->type = decl; - else if (/* BVAL is null when push_class_level_binding moves an + else if (/* TARGET_BVAL is null when push_class_level_binding moves an inherited type-binding out of the way to make room for a new value binding. */ - !bval - /* BVAL is error_mark_node when DECL's name has been used + !target_bval + /* TARGET_BVAL is error_mark_node when TARGET_DECL's name has been used in a non-class scope prior declaration. In that case, we should have already issued a diagnostic; for graceful error recovery purpose, pretend this was the intended declaration for that name. */ - || bval == error_mark_node - /* If BVAL is anticipated but has not yet been declared, + || target_bval == error_mark_node + /* If TARGET_BVAL is anticipated but has not yet been declared, pretend it is not there at all. */ - || (TREE_CODE (bval) == FUNCTION_DECL - && DECL_ANTICIPATED (bval) - && !DECL_HIDDEN_FRIEND_P (bval))) + || (TREE_CODE (target_bval) == FUNCTION_DECL + && DECL_ANTICIPATED (target_bval) + && !DECL_HIDDEN_FRIEND_P (target_bval))) binding->value = decl; - else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval) - && (TREE_CODE (decl) != TYPE_DECL - || same_type_p (TREE_TYPE (decl), TREE_TYPE (bval)))) + else if (TREE_CODE (target_bval) == TYPE_DECL && DECL_ARTIFICIAL (target_bval) + && target_decl != target_bval + && (TREE_CODE (target_decl) != TYPE_DECL + || same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval)))) { /* The old binding was a type name. It was placed in VALUE field because it was thought, at the point it was @@ -450,15 +476,15 @@ supplement_binding_1 (cxx_binding *bindi binding->value = decl; binding->value_is_inherited = false; } - else if (TREE_CODE (bval) == TYPE_DECL - && TREE_CODE (decl) == TYPE_DECL - && DECL_NAME (decl) == DECL_NAME (bval) + else if (TREE_CODE (target_bval) == TYPE_DECL + && TREE_CODE (target_decl) == TYPE_DECL + && DECL_NAME (target_decl) == DECL_NAME (target_bval) && binding->scope->kind != sk_class - && (same_type_p (TREE_TYPE (decl), TREE_TYPE (bval)) + && (same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval)) /* If either type involves template parameters, we must wait until instantiation. */ - || uses_template_parms (TREE_TYPE (decl)) - || uses_template_parms (TREE_TYPE (bval)))) + || uses_template_parms (TREE_TYPE (target_decl)) + || uses_template_parms (TREE_TYPE (target_bval)))) /* We have two typedef-names, both naming the same type to have the same name. In general, this is OK because of: @@ -480,9 +506,9 @@ supplement_binding_1 (cxx_binding *bindi A member shall not be declared twice in the member-specification. */ - else if (TREE_CODE (decl) == VAR_DECL && TREE_CODE (bval) == VAR_DECL - && DECL_EXTERNAL (decl) && DECL_EXTERNAL (bval) - && !DECL_CLASS_SCOPE_P (decl)) + else if (TREE_CODE (target_decl) == VAR_DECL && TREE_CODE (target_bval) == VAR_DECL + && DECL_EXTERNAL (target_decl) && DECL_EXTERNAL (target_bval) + && !DECL_CLASS_SCOPE_P (target_decl)) { duplicate_decls (decl, binding->value, /*newdecl_is_friend=*/false); ok = false; @@ -3018,6 +3044,8 @@ push_class_level_binding_1 (tree name, t { tree bval = binding->value; tree old_decl = NULL_TREE; + tree target_decl = strip_using_decl (decl); + tree target_bval = strip_using_decl (bval); if (INHERITED_VALUE_BINDING_P (binding)) { @@ -3025,8 +3053,8 @@ push_class_level_binding_1 (tree name, t tag name, slide it over to make room for the new binding. The old binding is still visible if explicitly qualified with a class-key. */ - if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval) - && !(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x))) + if (TREE_CODE (target_bval) == TYPE_DECL && DECL_ARTIFICIAL (target_bval) + && !(TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl))) { old_decl = binding->type; binding->type = bval; @@ -3038,18 +3066,21 @@ push_class_level_binding_1 (tree name, t old_decl = bval; /* Any inherited type declaration is hidden by the type declaration in the derived class. */ - if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)) + if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl)) binding->type = NULL_TREE; } } - else if (TREE_CODE (x) == OVERLOAD && is_overloaded_fn (bval)) - old_decl = bval; - else if (TREE_CODE (x) == USING_DECL && TREE_CODE (bval) == USING_DECL) - return true; - else if (TREE_CODE (x) == USING_DECL && is_overloaded_fn (bval)) + else if (TREE_CODE (target_decl) == OVERLOAD && is_overloaded_fn (target_bval)) old_decl = bval; - else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (x)) + else if (TREE_CODE (decl) == USING_DECL + && DECL_DEPENDENT_P (decl) + && TREE_CODE (bval) == USING_DECL + && DECL_DEPENDENT_P (bval)) return true; + else if (TREE_CODE (decl) == USING_DECL && is_overloaded_fn (target_bval)) + old_decl = bval; + else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (target_decl)) + return true; if (old_decl && binding->scope == class_binding_level) { Index: gcc/dbxout.c =================================================================== --- gcc/dbxout.c (revision 178088) +++ gcc/dbxout.c (working copy) @@ -1518,6 +1518,8 @@ dbxout_type_fields (tree type) if (TREE_CODE (tem) == TYPE_DECL /* Omit here the nameless fields that are used to skip bits. */ || DECL_IGNORED_P (tem) + /* Omit USING_DECL */ + || TREE_CODE (tem) >= LAST_AND_UNUSED_TREE_CODE /* Omit fields whose position or size are variable or too large to represent. */ || (TREE_CODE (tem) == FIELD_DECL ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-26 1:28 ` Fabien Chêne @ 2011-09-26 14:28 ` Jason Merrill 2011-10-10 20:35 ` Fabien Chêne 0 siblings, 1 reply; 40+ messages in thread From: Jason Merrill @ 2011-09-26 14:28 UTC (permalink / raw) To: Fabien Chêne; +Cc: Paolo Carlini, gcc-patches On 09/25/2011 05:06 PM, Fabien Chêne wrote: > + else if ((using_decl = strip_using_decl (member)) != member) > + /* If it is a using decl, use its underlying decl. */ > + type_decl = strip_using_decl (type_decl); > - if (DECL_NAME (field) == name > + if (DECL_NAME (decl) == name > && (!want_type > - || TREE_CODE (field) == TYPE_DECL > - || DECL_CLASS_TEMPLATE_P (field))) > - return field; > + || TREE_CODE (decl) == TYPE_DECL > + || DECL_CLASS_TEMPLATE_P (decl))) > + return decl; Why do we need to strip the USING_DECL both in lookup_field_1 and in callers? > + /* do not push the decl more than once */ Comments should start with a capital letter and end with a period. This should also say "unless we need to compare underlying types at instantiation time" > + /* We allow pushing an enum multiple times in a class > + * template in order to handle late matching of underlying > + * type on an opaque-enum-declaration followed by an > + * enum-specifier. */ And we don't put * at the beginning of each line. > + enumtype = xref_tag (enum_type, name, /*tag_scope=*/ts_current, false); > + /* TARGET_BVAL is error_mark_node when TARGET_DECL's name has been used > + else if (TREE_CODE (target_bval) == TYPE_DECL && DECL_ARTIFICIAL (target_bval) > + || same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval)))) > + else if (TREE_CODE (target_decl) == VAR_DECL && TREE_CODE (target_bval) == VAR_DECL > + if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl)) > + else if (TREE_CODE (target_decl) == OVERLOAD && is_overloaded_fn (target_bval)) > + else if (TREE_CODE (decl) == USING_DECL && is_overloaded_fn (target_bval)) > + else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (target_decl)) These lines go past 80 characters. Jason ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-09-26 14:28 ` Jason Merrill @ 2011-10-10 20:35 ` Fabien Chêne 2011-10-11 15:35 ` Jason Merrill 0 siblings, 1 reply; 40+ messages in thread From: Fabien Chêne @ 2011-10-10 20:35 UTC (permalink / raw) To: Jason Merrill; +Cc: Paolo Carlini, gcc-patches Hi, 2011/9/26 Jason Merrill <jason@redhat.com>: > On 09/25/2011 05:06 PM, Fabien Chêne wrote: >> >> + else if ((using_decl = strip_using_decl (member)) != member) > >> + /* If it is a using decl, use its underlying decl. */ >> + type_decl = strip_using_decl (type_decl); > >> - if (DECL_NAME (field) == name >> + if (DECL_NAME (decl) == name >> && (!want_type >> - || TREE_CODE (field) == TYPE_DECL >> - || DECL_CLASS_TEMPLATE_P (field))) >> - return field; >> + || TREE_CODE (decl) == TYPE_DECL >> + || DECL_CLASS_TEMPLATE_P (decl))) >> + return decl; > > Why do we need to strip the USING_DECL both in lookup_field_1 and in > callers? Sorry but I've failed to see why you called them callers of lookup_field_1, could you elaborate ? -- Fabien ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [Patch] PR c++/26256 2011-10-10 20:35 ` Fabien Chêne @ 2011-10-11 15:35 ` Jason Merrill 0 siblings, 0 replies; 40+ messages in thread From: Jason Merrill @ 2011-10-11 15:35 UTC (permalink / raw) To: Fabien Chêne; +Cc: Paolo Carlini, gcc-patches On 10/10/2011 03:59 PM, Fabien Chêne wrote: > Sorry but I've failed to see why you called them callers of > lookup_field_1, could you elaborate ? Hmm, I was assuming that the other functions would have gotten their decls via lookup_field_1, but I suppose that isn't true for unqualified lookup that finds the name in class_binding_level. Never mind. Jason ^ permalink raw reply [flat|nested] 40+ messages in thread
end of thread, other threads:[~2011-10-11 15:12 UTC | newest] Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2010-05-11 19:44 [Patch] PR c++/26256 Fabien Chêne 2010-05-16 19:20 ` Fabien Chêne 2010-06-08 21:50 ` Jason Merrill 2010-06-09 9:23 ` Fabien Chêne 2010-06-09 9:23 ` Fabien Chêne 2010-06-09 12:17 ` Jason Merrill 2010-06-16 21:21 ` Fabien Chêne 2010-06-17 8:39 ` Fabien Chêne 2010-06-18 8:18 ` Jason Merrill 2010-07-30 13:42 ` Fabien Chêne 2010-08-18 19:29 ` Fabien Chêne 2010-08-20 23:29 ` Jason Merrill 2010-11-15 21:40 ` Fabien Chêne 2010-11-15 21:41 ` Fabien Chêne 2010-11-17 11:25 ` Fabien Chêne 2010-12-20 16:51 ` Fabien Chêne 2010-12-22 23:10 ` Jason Merrill 2011-03-04 8:11 ` Fabien Chêne 2011-03-05 20:07 ` Jason Merrill 2011-03-08 21:48 ` Fabien Chêne 2011-06-15 19:42 ` Fabien Chêne 2011-06-22 15:56 ` Jason Merrill 2011-09-17 18:49 ` Fabien Chêne 2011-09-20 1:53 ` Jason Merrill 2011-09-21 18:33 ` Fabien Chêne 2011-09-21 18:52 ` Fabien Chêne 2011-09-21 19:01 ` Jason Merrill 2011-09-22 10:34 ` Fabien Chêne 2011-09-22 16:50 ` Jason Merrill 2011-09-22 23:01 ` Fabien Chêne 2011-09-22 23:48 ` Jason Merrill 2011-09-23 8:57 ` Fabien Chêne 2011-09-25 20:49 ` Fabien Chêne 2011-09-25 21:05 ` Paolo Carlini 2011-09-25 21:48 ` Fabien Chêne 2011-09-25 22:35 ` Paolo Carlini 2011-09-26 1:28 ` Fabien Chêne 2011-09-26 14:28 ` Jason Merrill 2011-10-10 20:35 ` Fabien Chêne 2011-10-11 15:35 ` Jason Merrill
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).