In r11-4690 we removed the call to finish_nonmember_using_decl in
tsubst_expr/DECL_EXPR in the USING_DECL block. This was done not
to perform name lookup twice for a non-dependent using-decl, which
sounds sensible.
However, finish_nonmember_using_decl also pushes the decl's bindings
which we still have to do so that we can find the USING_DECL's name
later. In this case, we've got a USING_DECL N::operator<< that we are
tsubstituting. We already looked it up while parsing the template
"foo", and lookup_using_decl stashed the OVERLOAD it found into
USING_DECL_DECLS. Now we just have to update the IDENTIFIER_BINDING of
the identifier for operator<< with the overload the name is bound to.
I didn't want to export push_local_binding so I've introduced a new
wrapper.
gcc/cp/ChangeLog:
PR c++/98231
* name-lookup.c (push_using_decl_bindings): New.
* name-lookup.h (push_using_decl_bindings): Declare.
* pt.c (tsubst_expr): Call push_using_decl_bindings.
gcc/testsuite/ChangeLog:
PR c++/98231
* g++.dg/lookup/using63.C: New test.
}
}
+/* 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"
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 discard_operator_bindings (tree);
/* Lower level interface for modules. */
tree scope = USING_DECL_SCOPE (decl);
gcc_checking_assert (scope
== 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);
}
else if (is_capture_proxy (decl)
&& !DECL_TEMPLATE_INSTANTIATION (current_function_decl))
--- /dev/null
+// PR c++/98231
+// { dg-do compile }
+
+template <typename, typename = int> struct basic_ostream {};
+namespace N {
+ template <typename Char, typename CharTraits, typename T>
+ void operator<<(basic_ostream<Char, CharTraits>, T);
+}
+basic_ostream<char> os;
+
+template<typename T> void
+foo (T value)
+{
+ using N::operator<<;
+ os << value;
+}
+void bar() { foo (1); }