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


Reply via email to