This patch addresses the regression caused by the first fix. For
reasons that used to make more sense, an overload set of template
members would present as just a dependent using-decl, if it contained
any such using decls. Then we'd defer repeat lookup to instantiation
time. Except in a couple of places where we'd really want the
non-dependent function set.
However, we're now better at doing lookups correctly in more places, and
this deferring gets in the way. In this particular case, we need to know if
name < whatever >
is a template-id-expr, or a less-than operator[*], and we determine this
by seeing if any members of whatever 'name' found are templates. This
breaks if we just present a dependent using decl.
So, this patch removes the frobbing in name lookup and returns the whole
binding. We'll have arranged that if there is at least one dependent
using decl, it'll be first in the overload set.
Then we need to deal with that as an overload member in a couple of
places. The finish_id_expr change is so we properly insert an implicit
'this->' before hand. That showed I'd neglected to set the using-decl's
DECL_CONTEXT, hence the change in finish_struct.
get_class_binding_direct's fn_or_type arg can now return to be a bool
'want_type', as we no longer call it with the 'want_fns's' value.
That's a cleanup for stage 1. (The only other place we asked for fns is
getting the dtor, which cannot be a dependent using decl anyway, so the
request is moot.)
Booted & tested in x86_64-linux, applying to trunk and gcc-8.
nathan
[*] there's a core or evolution paper about interpreting '<' as a
template-id-expr in more places regardless of the binding of the single
identifer on its left.
--
Nathan Sidwell
2018-12-13 Nathan Sidwell <nat...@acm.org>
PR c++/87531
* class.c (finish_struct): Set DECL_CONTEXT of template assign op.
* name-lookup.c (get_class_binding_direct): Don't strip using-decl
of overload here.
* parser.c (cp_parser_postfix_expression): Cope with using decl in
overload set.
* semantics.c (finish_id_expr): Likewise.
* g++.dg/lookup/pr87531-2.C: New.
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c (revision 267093)
+++ gcc/cp/class.c (working copy)
@@ -7158,6 +7158,7 @@ finish_struct (tree t, tree attributes)
time. */
tree ass_op = build_lang_decl (USING_DECL, assign_op_identifier,
NULL_TREE);
+ DECL_CONTEXT (ass_op) = t;
USING_DECL_SCOPE (ass_op) = t;
DECL_DEPENDENT_P (ass_op) = true;
DECL_ARTIFICIAL (ass_op) = true;
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c (revision 267093)
+++ gcc/cp/name-lookup.c (working copy)
@@ -1242,17 +1242,6 @@ get_class_binding_direct (tree klass, tr
}
else if (STAT_HACK_P (val))
val = STAT_DECL (val);
-
- if (val && TREE_CODE (val) == OVERLOAD
- && TREE_CODE (OVL_FUNCTION (val)) == USING_DECL)
- {
- /* An overload with a dependent USING_DECL. Does the caller
- want the USING_DECL or the functions? */
- if (type_or_fns < 0)
- val = OVL_CHAIN (val);
- else
- val = OVL_FUNCTION (val);
- }
}
else
{
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 267093)
+++ gcc/cp/parser.c (working copy)
@@ -7240,14 +7240,19 @@ cp_parser_postfix_expression (cp_parser
else if (!args->is_empty ()
&& is_overloaded_fn (postfix_expression))
{
+ /* We only need to look at the first function,
+ because all the fns share the attribute we're
+ concerned with (all member fns or all local
+ fns). */
tree fn = get_first_fn (postfix_expression);
fn = STRIP_TEMPLATE (fn);
/* Do not do argument dependent lookup if regular
lookup finds a member function or a block-scope
function declaration. [basic.lookup.argdep]/3 */
- if (!DECL_FUNCTION_MEMBER_P (fn)
- && !DECL_LOCAL_FUNCTION_P (fn))
+ if (!((TREE_CODE (fn) == USING_DECL && DECL_DEPENDENT_P (fn))
+ || DECL_FUNCTION_MEMBER_P (fn)
+ || DECL_LOCAL_FUNCTION_P (fn)))
{
koenig_p = true;
if (!any_type_dependent_arguments_p (args))
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c (revision 267093)
+++ gcc/cp/semantics.c (working copy)
@@ -3805,9 +3805,10 @@ finish_id_expression (tree id_expression
return error_mark_node;
if (!template_arg_p
- && TREE_CODE (first_fn) == FUNCTION_DECL
- && DECL_FUNCTION_MEMBER_P (first_fn)
- && !shared_member_p (decl))
+ && (TREE_CODE (first_fn) == USING_DECL
+ || (TREE_CODE (first_fn) == FUNCTION_DECL
+ && DECL_FUNCTION_MEMBER_P (first_fn)
+ && !shared_member_p (decl))))
{
/* A set of member functions. */
decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0);
Index: gcc/testsuite/g++.dg/lookup/pr87531-2.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/pr87531-2.C (revision 0)
+++ gcc/testsuite/g++.dg/lookup/pr87531-2.C (working copy)
@@ -0,0 +1,63 @@
+// PR 87531 part 2. dependent using decls + template decls.
+
+template<typename T>
+struct One
+{
+ One& operator=(T* p_)
+ {
+ return operator=<T>(p_); // Parse failed here
+ }
+
+ template<typename U>
+ One& operator=(U* p_);
+
+};
+
+
+template<typename T>
+struct Two : T
+{
+ using T::f;
+ template<typename U> void f ();
+
+ using T::operator T*;
+ operator T * () const;
+
+ int frob ()
+ {
+ return f<int> (1);
+ }
+
+ T *quux ()
+ {
+ return operator T * ();
+ }
+
+ T *quux () const
+ {
+ return operator T * ();
+ }
+};
+
+struct Base
+{
+ template <typename T> int f (T i)
+ {
+ return i;
+ }
+
+ operator Base *() const;
+};
+
+void foo ()
+{
+ One<int> one;
+ Two<Base> two;
+
+ one = One<int> ();
+
+ two.frob ();
+ two.quux ();
+ const_cast <const Two<Base> &> (two).quux ();
+}
+