Patchwork C++ PATCH for c++/56358 (inheriting ctors breaking lookup)

login
register
mail settings
Submitter Jason Merrill
Date Feb. 27, 2013, 4:37 p.m.
Message ID <512E3641.10807@redhat.com>
Download mbox | patch
Permalink /patch/223649/
State New
Headers show

Comments

Jason Merrill - Feb. 27, 2013, 4:37 p.m.
We were trying to keep the USING_DECL for an inheriting constructor from 
interfering with name lookup, but it still did.  It occurred to me that 
the obvious way to avoid it interfering with the name of the base is to 
give the USING_DECL the constructor name, and then we can remove some of 
the special handling.

Tested x86_64-pc-linux-gnu, applying to trunk.
Gabriel Dos Reis - Feb. 28, 2013, 2:01 a.m.
On Wed, Feb 27, 2013 at 10:37 AM, Jason Merrill <jason@redhat.com> wrote:
> We were trying to keep the USING_DECL for an inheriting constructor from
> interfering with name lookup, but it still did.  It occurred to me that the
> obvious way to avoid it interfering with the name of the base is to give the
> USING_DECL the constructor name, and then we can remove some of the special
> handling.
>
> Tested x86_64-pc-linux-gnu, applying to trunk.

I like it when a bug fix consists of removing code or running less code :-)

-- Gaby

Patch

commit 57dd2e9e8586a6d6b0134904a8eb2cb0bd4fc09b
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Feb 26 13:01:48 2013 -0500

    	PR c++/56358
    	PR c++/56323
    	* name-lookup.c (do_class_using_decl): Use ctor_identifier instead
    	of the base name for inheriting ctors.
    	(push_class_level_binding_1): Remove inheriting ctor handling.
    	* pt.c (tsubst_decl) [USING_DECL]: Likewise.
    	* class.c (add_implicitly_declared_members): Adjust.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index eaa109a..2a0351f 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -3010,11 +3010,10 @@  add_implicitly_declared_members (tree t, tree* access_decls,
     {
       tree using_decl = TREE_VALUE (*access_decls);
       tree decl = USING_DECL_DECLS (using_decl);
-      if (DECL_SELF_REFERENCE_P (decl))
+      if (DECL_NAME (using_decl) == ctor_identifier)
 	{
 	  /* declare, then remove the decl */
-	  tree ctor_list = lookup_fnfields_slot (TREE_TYPE (decl),
-						 ctor_identifier);
+	  tree ctor_list = decl;
 	  location_t loc = input_location;
 	  input_location = DECL_SOURCE_LOCATION (using_decl);
 	  if (ctor_list)
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 1f3c042..2a47331 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -3027,13 +3027,6 @@  push_class_level_binding_1 (tree name, tree x)
       && TREE_TYPE (decl) == error_mark_node)
     decl = TREE_VALUE (decl);
 
-  if (TREE_CODE (decl) == USING_DECL
-      && TYPE_NAME (USING_DECL_SCOPE (decl))
-      && DECL_NAME (decl) == TYPE_IDENTIFIER (USING_DECL_SCOPE (decl)))
-    /* This using-declaration declares inheriting constructors; it does not
-       redeclare the name of a template parameter.  */
-    return true;
-
   if (!check_template_shadow (decl))
     return false;
 
@@ -3225,12 +3218,14 @@  do_class_using_decl (tree scope, tree name)
       error ("%<%T::%D%> names destructor", scope, name);
       return NULL_TREE;
     }
-  if (TYPE_NAME (scope) && name == TYPE_IDENTIFIER (scope))
-    /* 3.4.3.1 says that using B::B always names the constructor even if B
-       is a typedef; now replace the second B with the real name.  */
-    name = TYPE_IDENTIFIER (TYPE_MAIN_VARIANT (scope));
-  if (MAYBE_CLASS_TYPE_P (scope) && constructor_name_p (name, scope))
-    maybe_warn_cpp0x (CPP0X_INHERITING_CTORS);
+  /* Using T::T declares inheriting ctors, even if T is a typedef.  */
+  if (MAYBE_CLASS_TYPE_P (scope)
+      && ((TYPE_NAME (scope) && name == TYPE_IDENTIFIER (scope))
+	  || constructor_name_p (name, scope)))
+    {
+      maybe_warn_cpp0x (CPP0X_INHERITING_CTORS);
+      name = ctor_identifier;
+    }
   if (constructor_name_p (name, current_class_type))
     {
       error ("%<%T::%D%> names constructor in %qT",
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9b7fc3a..eb9fc7f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10490,14 +10490,9 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
       if (DECL_DEPENDENT_P (t)
 	  || uses_template_parms (USING_DECL_SCOPE (t)))
 	{
-	  tree scope = USING_DECL_SCOPE (t);
 	  tree inst_scope = tsubst_copy (USING_DECL_SCOPE (t), args,
 					 complain, in_decl);
 	  tree name = tsubst_copy (DECL_NAME (t), args, complain, in_decl);
-	  /* Handle 'using T::T'.  */
-	  if (TYPE_NAME (scope)
-	      && name == TYPE_IDENTIFIER (scope))
-	    name = TYPE_IDENTIFIER (inst_scope);
 	  r = do_class_using_decl (inst_scope, name);
 	  if (!r)
 	    r = error_mark_node;
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor18.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor18.C
new file mode 100644
index 0000000..0573555
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor18.C
@@ -0,0 +1,22 @@ 
+// PR c++/56358
+// { dg-do compile { target c++11 } }
+
+struct foo {
+  explicit foo(int) {}
+};
+
+template<typename T>
+struct bar: T {
+  using T::T;
+
+  // Bad
+  explicit bar(): T(0) {}
+
+  void baz()
+  {
+    // Also bad
+    using qux = T;
+  }
+};
+
+bar<foo> b, b2(42);
diff --git a/gcc/testsuite/g++.dg/inherit/using5.C b/gcc/testsuite/g++.dg/inherit/using5.C
index 89c7ca0..b8e5107 100644
--- a/gcc/testsuite/g++.dg/inherit/using5.C
+++ b/gcc/testsuite/g++.dg/inherit/using5.C
@@ -6,7 +6,7 @@ 
 
 template<int> struct A
 {
-  A::A; // { dg-error "constructor" }
+  A::A; // { dg-error "constructor|not a base" }
 };
 
 struct B
diff --git a/gcc/testsuite/g++.old-deja/g++.other/using3.C b/gcc/testsuite/g++.old-deja/g++.other/using3.C
index f30ecbc..3df78f0 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/using3.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/using3.C
@@ -8,5 +8,5 @@  typedef struct {
 } S;
 
 struct B: S{
-  using S::S;        // { dg-error "" } no such field
+  using S::S;	       // { dg-error "" "" { target c++98 } } no such field
 };