diff mbox series

c++: ICE with USING_DECL redeclaration [PR98687]

Message ID 20210115052607.476396-1-polacek@redhat.com
State New
Headers show
Series c++: ICE with USING_DECL redeclaration [PR98687] | expand

Commit Message

Marek Polacek Jan. 15, 2021, 5:26 a.m. UTC
My recent patch that introduced push_using_decl_bindings didn't
handle USING_DECL redeclaration, therefore things broke.  This
patch amends that.  Note that I don't know if the other parts of
finish_nonmember_using_decl are needed (e.g. the binding->type
setting) -- I couldn't trigger it by any of my hand-made testcases.

Sorry for not thinking harder about redeclarations in the original
patch :(.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

gcc/cp/ChangeLog:

	PR c++/98687
	* name-lookup.c (push_using_decl_bindings): If we found an
	existing local binding, update it if it's not identical.

gcc/testsuite/ChangeLog:

	PR c++/98687
	* g++.dg/lookup/using64.C: New test.
	* g++.dg/lookup/using65.C: New test.
---
 gcc/cp/name-lookup.c                  | 20 ++++++++-
 gcc/testsuite/g++.dg/lookup/using64.C | 60 +++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/lookup/using65.C | 17 ++++++++
 3 files changed, 95 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/lookup/using64.C
 create mode 100644 gcc/testsuite/g++.dg/lookup/using65.C


base-commit: 5fff80fd79c36a1a940b331d20905061d61ee5e6

Comments

Jason Merrill Jan. 18, 2021, 10:18 p.m. UTC | #1
On 1/15/21 12:26 AM, Marek Polacek wrote:
> My recent patch that introduced push_using_decl_bindings didn't
> handle USING_DECL redeclaration, therefore things broke.  This
> patch amends that.  Note that I don't know if the other parts of
> finish_nonmember_using_decl are needed (e.g. the binding->type
> setting) -- I couldn't trigger it by any of my hand-made testcases.

I'd expect it to be exercised by something along the lines of

struct A { };

void f()
{
   int A;
   using ::A;
   struct A a;
}

Let's factor the code out of finish_nonmember_using_decl rather than 
copy it.

> Sorry for not thinking harder about redeclarations in the original
> patch :(.
> 
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/98687
> 	* name-lookup.c (push_using_decl_bindings): If we found an
> 	existing local binding, update it if it's not identical.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/98687
> 	* g++.dg/lookup/using64.C: New test.
> 	* g++.dg/lookup/using65.C: New test.
> ---
>   gcc/cp/name-lookup.c                  | 20 ++++++++-
>   gcc/testsuite/g++.dg/lookup/using64.C | 60 +++++++++++++++++++++++++++
>   gcc/testsuite/g++.dg/lookup/using65.C | 17 ++++++++
>   3 files changed, 95 insertions(+), 2 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/lookup/using64.C
>   create mode 100644 gcc/testsuite/g++.dg/lookup/using65.C
> 
> diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
> index b4b6c0b81b5..857d90914ca 100644
> --- a/gcc/cp/name-lookup.c
> +++ b/gcc/cp/name-lookup.c
> @@ -9285,8 +9285,24 @@ push_operator_bindings ()
>   void
>   push_using_decl_bindings (tree decl)
>   {
> -  push_local_binding (DECL_NAME (decl), USING_DECL_DECLS (decl),
> -		      /*using*/true);
> +  tree name = DECL_NAME (decl);
> +  tree value = USING_DECL_DECLS (decl);
> +
> +  cxx_binding *binding = find_local_binding (current_binding_level, name);
> +  if (binding)
> +    {
> +      if (value == binding->value)
> +	/* Redeclaration of this USING_DECL.  */;
> +      else if (binding->value && TREE_CODE (value) == OVERLOAD)
> +	{
> +	  /* We already have this binding, so replace it.  */
> +	  update_local_overload (IDENTIFIER_BINDING (name), value);
> +	  IDENTIFIER_BINDING (name)->value = value;
> +	}
> +    }
> +  else
> +    /* Install the new binding.  */
> +    push_local_binding (DECL_NAME (decl), value, /*using*/true);
>   }
>   
>   #include "gt-cp-name-lookup.h"
> diff --git a/gcc/testsuite/g++.dg/lookup/using64.C b/gcc/testsuite/g++.dg/lookup/using64.C
> new file mode 100644
> index 00000000000..42bce331e19
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/lookup/using64.C
> @@ -0,0 +1,60 @@
> +// PR c++/98687
> +// { dg-do compile }
> +
> +struct S { };
> +
> +namespace N {
> +  template <typename T>
> +  bool operator==(T, int);
> +
> +  template <typename T>
> +  void X(T);
> +}
> +
> +namespace M {
> +  template <typename T>
> +  bool operator==(T, double);
> +}
> +
> +template<typename T>
> +bool fn1 (T t)
> +{
> +  using N::operator==;
> +  return t == 1;
> +}
> +
> +template<typename T>
> +bool fn2 (T t)
> +{
> +  // Redeclaration.
> +  using N::operator==;
> +  using N::operator==;
> +  return t == 1;
> +}
> +
> +template<typename T>
> +bool fn3 (T t)
> +{
> +  // Need update_local_overload.
> +  using N::operator==;
> +  using M::operator==;
> +  return t == 1;
> +}
> +
> +template<typename T>
> +void fn4 (T t)
> +{
> +  struct X { };
> +  using N::X;
> +  X(1);
> +}
> +
> +void
> +g ()
> +{
> +  S s;
> +  fn1 (s);
> +  fn2 (s);
> +  fn3 (s);
> +  fn4 (s);
> +}
> diff --git a/gcc/testsuite/g++.dg/lookup/using65.C b/gcc/testsuite/g++.dg/lookup/using65.C
> new file mode 100644
> index 00000000000..bc6c086197f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/lookup/using65.C
> @@ -0,0 +1,17 @@
> +// PR c++/98687
> +// { dg-do compile }
> +
> +extern "C" namespace std {
> +  double log1p(double);
> +}
> +namespace std_fallback {
> +  template <typename> void log1p();
> +}
> +template <typename> struct log1p_impl {
> +  static int run() {
> +    using std::log1p;
> +    using std_fallback::log1p;
> +    return 0;
> +  }
> +};
> +void log1p() { log1p_impl<int>::run(); }
> 
> base-commit: 5fff80fd79c36a1a940b331d20905061d61ee5e6
>
Marek Polacek Jan. 19, 2021, 8:47 p.m. UTC | #2
On Mon, Jan 18, 2021 at 05:18:46PM -0500, Jason Merrill wrote:
> On 1/15/21 12:26 AM, Marek Polacek wrote:
> > My recent patch that introduced push_using_decl_bindings didn't
> > handle USING_DECL redeclaration, therefore things broke.  This
> > patch amends that.  Note that I don't know if the other parts of
> > finish_nonmember_using_decl are needed (e.g. the binding->type
> > setting) -- I couldn't trigger it by any of my hand-made testcases.
> 
> I'd expect it to be exercised by something along the lines of
> 
> struct A { };
> 
> void f()
> {
>   int A;
>   using ::A;
>   struct A a;
> }

Hmm, I already had a test for the struct stat hack, but I've added this one
to using64.C, thanks.
 
> Let's factor the code out of finish_nonmember_using_decl rather than copy
> it.

Done here.  A small complication was that name_lookup is local to
name-lookup.c so I had to add an overload to handle this.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
My recent patch that introduced push_using_decl_bindings didn't
handle USING_DECL redeclaration, therefore things broke.  This patch
amends that by breaking out a part of finish_nonmember_using_decl
out to a separate function, push_using_decl_bindings, and calling it.
It needs an overload, because name_lookup is only available inside
of name-lookup.c.

gcc/cp/ChangeLog:

	PR c++/98687
	* name-lookup.c (push_using_decl_bindings): New, broken out of...
	(finish_nonmember_using_decl): ...here.
	* name-lookup.h (push_using_decl_bindings): Update declaration.
	* pt.c (tsubst_expr): Update the call to push_using_decl_bindings.

gcc/testsuite/ChangeLog:

	PR c++/98687
	* g++.dg/lookup/using64.C: New test.
	* g++.dg/lookup/using65.C: New test.
---
 gcc/cp/name-lookup.c                  | 103 ++++++++++++++------------
 gcc/cp/name-lookup.h                  |   2 +-
 gcc/cp/pt.c                           |   3 +-
 gcc/testsuite/g++.dg/lookup/using64.C |  69 +++++++++++++++++
 gcc/testsuite/g++.dg/lookup/using65.C |  17 +++++
 5 files changed, 145 insertions(+), 49 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/lookup/using64.C
 create mode 100644 gcc/testsuite/g++.dg/lookup/using65.C

diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index b4b6c0b81b5..843e5f305c0 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -6279,6 +6279,61 @@ pushdecl_namespace_level (tree x, bool hiding)
   return t;
 }
 
+/* Wrapper around push_local_binding to push the bindings for
+   a non-member USING_DECL with NAME and VALUE.  LOOKUP, if non-null,
+   is the result of name lookup during template parsing.  */
+
+static void
+push_using_decl_bindings (name_lookup *lookup, tree name, tree value)
+{
+  tree type = NULL_TREE;
+
+  cxx_binding *binding = find_local_binding (current_binding_level, name);
+  if (binding)
+    {
+      value = binding->value;
+      type = binding->type;
+    }
+
+  /* DR 36 questions why using-decls at function scope may not be
+     duplicates.  Disallow it, as C++11 claimed and PR 20420
+     implemented.  */
+  if (lookup)
+    do_nonmember_using_decl (*lookup, true, true, &value, &type);
+
+  if (!value)
+    ;
+  else if (binding && value == binding->value)
+    /* Redeclaration of this USING_DECL.  */;
+  else if (binding && binding->value && TREE_CODE (value) == OVERLOAD)
+    {
+      /* We already have this binding, so replace it.  */
+      update_local_overload (IDENTIFIER_BINDING (name), value);
+      IDENTIFIER_BINDING (name)->value = value;
+    }
+  else
+    /* Install the new binding.  */
+    push_local_binding (name, value, /*using=*/true);
+
+  if (!type)
+    ;
+  else if (binding && type == binding->type)
+    ;
+  else
+    {
+      push_local_binding (name, type, /*using=*/true);
+      set_identifier_type_value (name, type);
+    }
+}
+
+/* Overload for push_using_decl_bindings that doesn't take a name_lookup.  */
+
+void
+push_using_decl_bindings (tree name, tree value)
+{
+  push_using_decl_bindings (nullptr, name, value);
+}
+
 /* Process a using declaration in non-class scope.  */
 
 void
@@ -6395,43 +6450,7 @@ finish_nonmember_using_decl (tree scope, tree name)
   else
     {
       add_decl_expr (using_decl);
-
-      cxx_binding *binding = find_local_binding (current_binding_level, name);
-      tree value = NULL;
-      tree type = NULL;
-      if (binding)
-	{
-	  value = binding->value;
-	  type = binding->type;
-	}
-
-      /* DR 36 questions why using-decls at function scope may not be
-	 duplicates.  Disallow it, as C++11 claimed and PR 20420
-	 implemented.  */
-      do_nonmember_using_decl (lookup, true, true, &value, &type);
-
-      if (!value)
-	;
-      else if (binding && value == binding->value)
-	;
-      else if (binding && binding->value && TREE_CODE (value) == OVERLOAD)
-	{
-	  update_local_overload (IDENTIFIER_BINDING (name), value);
-	  IDENTIFIER_BINDING (name)->value = value;
-	}
-      else
-	/* Install the new binding.  */
-	push_local_binding (name, value, true);
-
-      if (!type)
-	;
-      else if (binding && type == binding->type)
-	;
-      else
-	{
-	  push_local_binding (name, type, true);
-	  set_identifier_type_value (name, type);
-	}
+      push_using_decl_bindings (&lookup, name, NULL_TREE);
     }
 }
 
@@ -9279,14 +9298,4 @@ push_operator_bindings ()
 	}
 }
 
-/* Wrapper around push_local_binding to push the bindings for
-   a non-member USING_DECL DECL that was found during template parsing.  */
-
-void
-push_using_decl_bindings (tree decl)
-{
-  push_local_binding (DECL_NAME (decl), USING_DECL_DECLS (decl),
-		      /*using*/true);
-}
-
 #include "gt-cp-name-lookup.h"
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index bac3fa71fc9..75db5b38061 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -478,7 +478,7 @@ extern void push_to_top_level (void);
 extern void pop_from_top_level (void);
 extern void maybe_save_operator_binding (tree);
 extern void push_operator_bindings (void);
-extern void push_using_decl_bindings (tree);
+extern void push_using_decl_bindings (tree, tree);
 extern void discard_operator_bindings (tree);
 
 /* Lower level interface for modules. */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 957140115e4..12d084031b1 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -18136,7 +18136,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 				 == tsubst (scope, args, complain, in_decl));
 	    /* We still need to push the bindings so that we can look up
 	       this name later.  */
-	    push_using_decl_bindings (decl);
+	    push_using_decl_bindings (DECL_NAME (decl),
+				      USING_DECL_DECLS (decl));
 	  }
 	else if (is_capture_proxy (decl)
 		 && !DECL_TEMPLATE_INSTANTIATION (current_function_decl))
diff --git a/gcc/testsuite/g++.dg/lookup/using64.C b/gcc/testsuite/g++.dg/lookup/using64.C
new file mode 100644
index 00000000000..a50cd273c89
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using64.C
@@ -0,0 +1,69 @@
+// PR c++/98687
+// { dg-do compile }
+
+struct S { };
+
+namespace N {
+  template <typename T>
+  bool operator==(T, int);
+
+  template <typename T>
+  void X(T);
+}
+
+namespace M {
+  template <typename T>
+  bool operator==(T, double);
+}
+
+template<typename T>
+bool fn1 (T t)
+{
+  using N::operator==;
+  return t == 1;
+}
+
+template<typename T>
+bool fn2 (T t)
+{
+  // Redeclaration.
+  using N::operator==;
+  using N::operator==;
+  return t == 1;
+}
+
+template<typename T>
+bool fn3 (T t)
+{
+  // Need update_local_overload.
+  using N::operator==;
+  using M::operator==;
+  return t == 1;
+}
+
+template<typename T>
+void fn4 (T)
+{
+  struct X { };
+  using N::X;
+  X(1);
+}
+
+template<typename T>
+void fn5 (T)
+{
+  int S;
+  using ::S;
+  struct S s;
+}
+
+void
+g ()
+{
+  S s;
+  fn1 (s);
+  fn2 (s);
+  fn3 (s);
+  fn4 (s);
+  fn5 (s);
+}
diff --git a/gcc/testsuite/g++.dg/lookup/using65.C b/gcc/testsuite/g++.dg/lookup/using65.C
new file mode 100644
index 00000000000..bc6c086197f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using65.C
@@ -0,0 +1,17 @@
+// PR c++/98687
+// { dg-do compile }
+
+extern "C" namespace std {
+  double log1p(double);
+}
+namespace std_fallback {
+  template <typename> void log1p();
+}
+template <typename> struct log1p_impl {
+  static int run() {
+    using std::log1p;
+    using std_fallback::log1p;
+    return 0;
+  }
+};
+void log1p() { log1p_impl<int>::run(); }

base-commit: 7266ff2a243715e20882850b2fc4211ac7db4d34
Jason Merrill Jan. 19, 2021, 9:11 p.m. UTC | #3
On 1/19/21 3:47 PM, Marek Polacek wrote:
> On Mon, Jan 18, 2021 at 05:18:46PM -0500, Jason Merrill wrote:
>> On 1/15/21 12:26 AM, Marek Polacek wrote:
>>> My recent patch that introduced push_using_decl_bindings didn't
>>> handle USING_DECL redeclaration, therefore things broke.  This
>>> patch amends that.  Note that I don't know if the other parts of
>>> finish_nonmember_using_decl are needed (e.g. the binding->type
>>> setting) -- I couldn't trigger it by any of my hand-made testcases.
>>
>> I'd expect it to be exercised by something along the lines of
>>
>> struct A { };
>>
>> void f()
>> {
>>    int A;
>>    using ::A;
>>    struct A a;
>> }
> 
> Hmm, I already had a test for the struct stat hack, but I've added this one
> to using64.C, thanks.
>   
>> Let's factor the code out of finish_nonmember_using_decl rather than copy
>> it.
> 
> Done here.  A small complication was that name_lookup is local to
> name-lookup.c so I had to add an overload to handle this.
> 
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> -- >8 --
> My recent patch that introduced push_using_decl_bindings didn't
> handle USING_DECL redeclaration, therefore things broke.  This patch
> amends that by breaking out a part of finish_nonmember_using_decl
> out to a separate function, push_using_decl_bindings, and calling it.
> It needs an overload, because name_lookup is only available inside
> of name-lookup.c.
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/98687
> 	* name-lookup.c (push_using_decl_bindings): New, broken out of...
> 	(finish_nonmember_using_decl): ...here.
> 	* name-lookup.h (push_using_decl_bindings): Update declaration.
> 	* pt.c (tsubst_expr): Update the call to push_using_decl_bindings.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/98687
> 	* g++.dg/lookup/using64.C: New test.
> 	* g++.dg/lookup/using65.C: New test.
> ---
>   gcc/cp/name-lookup.c                  | 103 ++++++++++++++------------
>   gcc/cp/name-lookup.h                  |   2 +-
>   gcc/cp/pt.c                           |   3 +-
>   gcc/testsuite/g++.dg/lookup/using64.C |  69 +++++++++++++++++
>   gcc/testsuite/g++.dg/lookup/using65.C |  17 +++++
>   5 files changed, 145 insertions(+), 49 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/lookup/using64.C
>   create mode 100644 gcc/testsuite/g++.dg/lookup/using65.C
> 
> diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
> index b4b6c0b81b5..843e5f305c0 100644
> --- a/gcc/cp/name-lookup.c
> +++ b/gcc/cp/name-lookup.c
> @@ -6279,6 +6279,61 @@ pushdecl_namespace_level (tree x, bool hiding)
>     return t;
>   }
>   
> +/* Wrapper around push_local_binding to push the bindings for
> +   a non-member USING_DECL with NAME and VALUE.  LOOKUP, if non-null,
> +   is the result of name lookup during template parsing.  */
> +
> +static void
> +push_using_decl_bindings (name_lookup *lookup, tree name, tree value)
> +{
> +  tree type = NULL_TREE;
> +
> +  cxx_binding *binding = find_local_binding (current_binding_level, name);
> +  if (binding)
> +    {
> +      value = binding->value;
> +      type = binding->type;
> +    }
> +
> +  /* DR 36 questions why using-decls at function scope may not be
> +     duplicates.  Disallow it, as C++11 claimed and PR 20420
> +     implemented.  */
> +  if (lookup)
> +    do_nonmember_using_decl (*lookup, true, true, &value, &type);
> +
> +  if (!value)
> +    ;
> +  else if (binding && value == binding->value)
> +    /* Redeclaration of this USING_DECL.  */;
> +  else if (binding && binding->value && TREE_CODE (value) == OVERLOAD)
> +    {
> +      /* We already have this binding, so replace it.  */
> +      update_local_overload (IDENTIFIER_BINDING (name), value);
> +      IDENTIFIER_BINDING (name)->value = value;
> +    }
> +  else
> +    /* Install the new binding.  */
> +    push_local_binding (name, value, /*using=*/true);
> +
> +  if (!type)
> +    ;
> +  else if (binding && type == binding->type)
> +    ;
> +  else
> +    {
> +      push_local_binding (name, type, /*using=*/true);
> +      set_identifier_type_value (name, type);
> +    }
> +}
> +
> +/* Overload for push_using_decl_bindings that doesn't take a name_lookup.  */
> +
> +void
> +push_using_decl_bindings (tree name, tree value)
> +{
> +  push_using_decl_bindings (nullptr, name, value);
> +}
> +
>   /* Process a using declaration in non-class scope.  */
>   
>   void
> @@ -6395,43 +6450,7 @@ finish_nonmember_using_decl (tree scope, tree name)
>     else
>       {
>         add_decl_expr (using_decl);
> -
> -      cxx_binding *binding = find_local_binding (current_binding_level, name);
> -      tree value = NULL;
> -      tree type = NULL;
> -      if (binding)
> -	{
> -	  value = binding->value;
> -	  type = binding->type;
> -	}
> -
> -      /* DR 36 questions why using-decls at function scope may not be
> -	 duplicates.  Disallow it, as C++11 claimed and PR 20420
> -	 implemented.  */
> -      do_nonmember_using_decl (lookup, true, true, &value, &type);
> -
> -      if (!value)
> -	;
> -      else if (binding && value == binding->value)
> -	;
> -      else if (binding && binding->value && TREE_CODE (value) == OVERLOAD)
> -	{
> -	  update_local_overload (IDENTIFIER_BINDING (name), value);
> -	  IDENTIFIER_BINDING (name)->value = value;
> -	}
> -      else
> -	/* Install the new binding.  */
> -	push_local_binding (name, value, true);
> -
> -      if (!type)
> -	;
> -      else if (binding && type == binding->type)
> -	;
> -      else
> -	{
> -	  push_local_binding (name, type, true);
> -	  set_identifier_type_value (name, type);
> -	}
> +      push_using_decl_bindings (&lookup, name, NULL_TREE);
>       }
>   }
>   
> @@ -9279,14 +9298,4 @@ push_operator_bindings ()
>   	}
>   }
>   
> -/* Wrapper around push_local_binding to push the bindings for
> -   a non-member USING_DECL DECL that was found during template parsing.  */
> -
> -void
> -push_using_decl_bindings (tree decl)
> -{
> -  push_local_binding (DECL_NAME (decl), USING_DECL_DECLS (decl),
> -		      /*using*/true);
> -}
> -
>   #include "gt-cp-name-lookup.h"
> diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
> index bac3fa71fc9..75db5b38061 100644
> --- a/gcc/cp/name-lookup.h
> +++ b/gcc/cp/name-lookup.h
> @@ -478,7 +478,7 @@ extern void push_to_top_level (void);
>   extern void pop_from_top_level (void);
>   extern void maybe_save_operator_binding (tree);
>   extern void push_operator_bindings (void);
> -extern void push_using_decl_bindings (tree);
> +extern void push_using_decl_bindings (tree, tree);
>   extern void discard_operator_bindings (tree);
>   
>   /* Lower level interface for modules. */
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 957140115e4..12d084031b1 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -18136,7 +18136,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
>   				 == tsubst (scope, args, complain, in_decl));
>   	    /* We still need to push the bindings so that we can look up
>   	       this name later.  */
> -	    push_using_decl_bindings (decl);
> +	    push_using_decl_bindings (DECL_NAME (decl),
> +				      USING_DECL_DECLS (decl));

There could still be an overload of push_using_decl_bindings that takes 
a single argument.  OK either way.

>   	  }
>   	else if (is_capture_proxy (decl)
>   		 && !DECL_TEMPLATE_INSTANTIATION (current_function_decl))
> diff --git a/gcc/testsuite/g++.dg/lookup/using64.C b/gcc/testsuite/g++.dg/lookup/using64.C
> new file mode 100644
> index 00000000000..a50cd273c89
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/lookup/using64.C
> @@ -0,0 +1,69 @@
> +// PR c++/98687
> +// { dg-do compile }
> +
> +struct S { };
> +
> +namespace N {
> +  template <typename T>
> +  bool operator==(T, int);
> +
> +  template <typename T>
> +  void X(T);
> +}
> +
> +namespace M {
> +  template <typename T>
> +  bool operator==(T, double);
> +}
> +
> +template<typename T>
> +bool fn1 (T t)
> +{
> +  using N::operator==;
> +  return t == 1;
> +}
> +
> +template<typename T>
> +bool fn2 (T t)
> +{
> +  // Redeclaration.
> +  using N::operator==;
> +  using N::operator==;
> +  return t == 1;
> +}
> +
> +template<typename T>
> +bool fn3 (T t)
> +{
> +  // Need update_local_overload.
> +  using N::operator==;
> +  using M::operator==;
> +  return t == 1;
> +}
> +
> +template<typename T>
> +void fn4 (T)
> +{
> +  struct X { };
> +  using N::X;
> +  X(1);
> +}
> +
> +template<typename T>
> +void fn5 (T)
> +{
> +  int S;
> +  using ::S;
> +  struct S s;
> +}
> +
> +void
> +g ()
> +{
> +  S s;
> +  fn1 (s);
> +  fn2 (s);
> +  fn3 (s);
> +  fn4 (s);
> +  fn5 (s);
> +}
> diff --git a/gcc/testsuite/g++.dg/lookup/using65.C b/gcc/testsuite/g++.dg/lookup/using65.C
> new file mode 100644
> index 00000000000..bc6c086197f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/lookup/using65.C
> @@ -0,0 +1,17 @@
> +// PR c++/98687
> +// { dg-do compile }
> +
> +extern "C" namespace std {
> +  double log1p(double);
> +}
> +namespace std_fallback {
> +  template <typename> void log1p();
> +}
> +template <typename> struct log1p_impl {
> +  static int run() {
> +    using std::log1p;
> +    using std_fallback::log1p;
> +    return 0;
> +  }
> +};
> +void log1p() { log1p_impl<int>::run(); }
> 
> base-commit: 7266ff2a243715e20882850b2fc4211ac7db4d34
>
diff mbox series

Patch

diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index b4b6c0b81b5..857d90914ca 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -9285,8 +9285,24 @@  push_operator_bindings ()
 void
 push_using_decl_bindings (tree decl)
 {
-  push_local_binding (DECL_NAME (decl), USING_DECL_DECLS (decl),
-		      /*using*/true);
+  tree name = DECL_NAME (decl);
+  tree value = USING_DECL_DECLS (decl);
+
+  cxx_binding *binding = find_local_binding (current_binding_level, name);
+  if (binding)
+    {
+      if (value == binding->value)
+	/* Redeclaration of this USING_DECL.  */;
+      else if (binding->value && TREE_CODE (value) == OVERLOAD)
+	{
+	  /* We already have this binding, so replace it.  */
+	  update_local_overload (IDENTIFIER_BINDING (name), value);
+	  IDENTIFIER_BINDING (name)->value = value;
+	}
+    }
+  else
+    /* Install the new binding.  */
+    push_local_binding (DECL_NAME (decl), value, /*using*/true);
 }
 
 #include "gt-cp-name-lookup.h"
diff --git a/gcc/testsuite/g++.dg/lookup/using64.C b/gcc/testsuite/g++.dg/lookup/using64.C
new file mode 100644
index 00000000000..42bce331e19
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using64.C
@@ -0,0 +1,60 @@ 
+// PR c++/98687
+// { dg-do compile }
+
+struct S { };
+
+namespace N {
+  template <typename T>
+  bool operator==(T, int);
+
+  template <typename T>
+  void X(T);
+}
+
+namespace M {
+  template <typename T>
+  bool operator==(T, double);
+}
+
+template<typename T>
+bool fn1 (T t)
+{
+  using N::operator==;
+  return t == 1;
+}
+
+template<typename T>
+bool fn2 (T t)
+{
+  // Redeclaration.
+  using N::operator==;
+  using N::operator==;
+  return t == 1;
+}
+
+template<typename T>
+bool fn3 (T t)
+{
+  // Need update_local_overload.
+  using N::operator==;
+  using M::operator==;
+  return t == 1;
+}
+
+template<typename T>
+void fn4 (T t)
+{
+  struct X { };
+  using N::X;
+  X(1);
+}
+
+void
+g ()
+{
+  S s;
+  fn1 (s);
+  fn2 (s);
+  fn3 (s);
+  fn4 (s);
+}
diff --git a/gcc/testsuite/g++.dg/lookup/using65.C b/gcc/testsuite/g++.dg/lookup/using65.C
new file mode 100644
index 00000000000..bc6c086197f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using65.C
@@ -0,0 +1,17 @@ 
+// PR c++/98687
+// { dg-do compile }
+
+extern "C" namespace std {
+  double log1p(double);
+}
+namespace std_fallback {
+  template <typename> void log1p();
+}
+template <typename> struct log1p_impl {
+  static int run() {
+    using std::log1p;
+    using std_fallback::log1p;
+    return 0;
+  }
+};
+void log1p() { log1p_impl<int>::run(); }