The problem in this case was that a few places in the compiler were
assuming that when we have an OVERLOAD, all the functions within it come
from the same context. But that isn't the case when we have
using-declarations involved, so we need to take them into account.
Tested x86_64-pc-linux-gnu, applied to trunk.
commit 08e12669e38d0ef41ebe051b31383906958d24c7
Author: Jason Merrill <ja...@redhat.com>
Date: Sun Jan 22 16:32:53 2012 -0500
PR c++/51925
* class.c (add_method): Set OVL_USED for using-decls.
* tree.c (ovl_scope): New.
* cp-tree.h: Declare it.
* parser.c (cp_parser_template_name): Use it.
* semantics.c (baselink_for_fns): Likewise.
* name-lookup.c (set_inherited_value_binding_p): Likewise.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index e6f33fe..d654b76 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1118,6 +1118,8 @@ add_method (tree type, tree method, tree using_decl)
/* Add the new binding. */
overload = build_overload (method, current_fns);
+ if (using_decl && TREE_CODE (overload) == OVERLOAD)
+ OVL_USED (overload) = true;
if (conv_p)
TYPE_HAS_CONVERSION (type) = 1;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ccad644..f27755e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -75,6 +75,7 @@ c-common.h, not after.
IMPLICIT_CONV_EXPR_DIRECT_INIT (in IMPLICIT_CONV_EXPR)
TRANSACTION_EXPR_IS_STMT (in TRANSACTION_EXPR)
CONVERT_EXPR_VBASE_PATH (in CONVERT_EXPR)
+ OVL_ARG_DEPENDENT (in OVERLOAD)
1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
@@ -5679,6 +5680,7 @@ extern tree get_fns (tree);
extern tree get_first_fn (tree);
extern tree ovl_cons (tree, tree);
extern tree build_overload (tree, tree);
+extern tree ovl_scope (tree);
extern bool non_static_member_function_p (tree);
extern const char *cxx_printable_name (tree, int);
extern const char *cxx_printable_name_translate (tree, int);
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 5734055..2351342 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -2853,7 +2853,7 @@ set_inherited_value_binding_p (cxx_binding *binding, tree decl,
tree context;
if (TREE_CODE (decl) == OVERLOAD)
- context = CP_DECL_CONTEXT (OVL_CURRENT (decl));
+ context = ovl_scope (decl);
else
{
gcc_assert (DECL_P (decl));
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c4c3ef4..491f48e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -12722,7 +12722,7 @@ cp_parser_template_name (cp_parser* parser,
its name; we will look it up again during template instantiation. */
if (DECL_FUNCTION_TEMPLATE_P (decl) || !DECL_P (decl))
{
- tree scope = CP_DECL_CONTEXT (get_first_fn (decl));
+ tree scope = ovl_scope (decl);
if (TYPE_P (scope) && dependent_type_p (scope))
return identifier;
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index a5a10d0..9019962 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2807,23 +2807,20 @@ finish_base_specifier (tree base, tree access, bool virtual_p)
tree
baselink_for_fns (tree fns)
{
- tree fn;
+ tree scope;
tree cl;
if (BASELINK_P (fns)
|| error_operand_p (fns))
return fns;
-
- fn = fns;
- if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
- fn = TREE_OPERAND (fn, 0);
- fn = get_first_fn (fn);
- if (!DECL_FUNCTION_MEMBER_P (fn))
+
+ scope = ovl_scope (fns);
+ if (!CLASS_TYPE_P (scope))
return fns;
- cl = currently_open_derived_class (DECL_CONTEXT (fn));
+ cl = currently_open_derived_class (scope);
if (!cl)
- cl = DECL_CONTEXT (fn);
+ cl = scope;
cl = TYPE_BINFO (cl);
return build_baselink (cl, cl, fns, /*optype=*/NULL_TREE);
}
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index bf8bc05..cf39800 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1525,6 +1525,24 @@ build_overload (tree decl, tree chain)
return ovl_cons (decl, chain);
}
+/* Return the scope where the overloaded functions OVL were found. */
+
+tree
+ovl_scope (tree ovl)
+{
+ if (TREE_CODE (ovl) == OFFSET_REF
+ || TREE_CODE (ovl) == COMPONENT_REF)
+ ovl = TREE_OPERAND (ovl, 1);
+ if (TREE_CODE (ovl) == BASELINK)
+ return BINFO_TYPE (BASELINK_BINFO (ovl));
+ if (TREE_CODE (ovl) == TEMPLATE_ID_EXPR)
+ ovl = TREE_OPERAND (ovl, 0);
+ /* Skip using-declarations. */
+ while (TREE_CODE (ovl) == OVERLOAD && OVL_USED (ovl) && OVL_CHAIN (ovl))
+ ovl = OVL_CHAIN (ovl);
+ return CP_DECL_CONTEXT (OVL_CURRENT (ovl));
+}
+
/* Return TRUE if FN is a non-static member function, FALSE otherwise.
This function looks into BASELINK and OVERLOAD nodes. */
diff --git a/gcc/testsuite/g++.dg/template/template-id-2.C b/gcc/testsuite/g++.dg/template/template-id-2.C
index 333e33d..d214716 100644
--- a/gcc/testsuite/g++.dg/template/template-id-2.C
+++ b/gcc/testsuite/g++.dg/template/template-id-2.C
@@ -11,7 +11,7 @@ template<> struct A<void>
template<typename T> void foo()
{
A<T> a;
- a.template foo<int>(); // { dg-error "no member" }
+ a.template foo<int>(); // { dg-error "member" }
}
};
diff --git a/gcc/testsuite/g++.dg/template/using20.C b/gcc/testsuite/g++.dg/template/using20.C
new file mode 100644
index 0000000..1df9549
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/using20.C
@@ -0,0 +1,18 @@
+// PR c++/51925
+
+struct E
+{
+ int e ();
+};
+template <typename T1>
+struct G : public E
+{
+ using E::e;
+ template <int> void e ();
+ void f () { e <0> (); }
+};
+int f(void)
+{
+ G<int> a;
+ a.f();
+}