public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [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).