This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for c++/34691 (mismatched default args to extern "C" function)
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Tue, 07 Apr 2009 23:50:06 -0400
- Subject: C++ PATCH for c++/34691 (mismatched default args to extern "C" function)
This patch fixes the first testcase in this PR by retaining multiple
extern "C" functions in the overload set until the point of overload
resolution, at which point we can complain if we use an ambiguous
default argument. In cases where we don't use the default argument, we
combine the functions at that point.
Tested x86_64-pc-linux-gnu, applied to trunk and 4.4.
2009-04-07 Jason Merrill <jason@redhat.com>
PR c++/34691
* name-lookup.c (merge_functions): Keep multiple extern "C" functions.
* call.c (joust): Complain about mismatched default arguments
in extern "C" functions.
* class.c (resolve_address_of_overloaded_function): Handle multiple
extern "C" functions.
* pt.c (resolve_overloaded_unification): Likewise.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 745c31f..c942712 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -6787,11 +6787,53 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn)
}
}
- /* If the two functions are the same (this can happen with declarations
- in multiple scopes and arg-dependent lookup), arbitrarily choose one. */
+ /* If the two function declarations represent the same function (this can
+ happen with declarations in multiple scopes and arg-dependent lookup),
+ arbitrarily choose one. But first make sure the default args we're
+ using match. */
if (DECL_P (cand1->fn) && DECL_P (cand2->fn)
&& equal_functions (cand1->fn, cand2->fn))
- return 1;
+ {
+ tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (cand1->fn));
+ tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (cand2->fn));
+
+ gcc_assert (!DECL_CONSTRUCTOR_P (cand1->fn));
+
+ for (i = 0; i < len; ++i)
+ {
+ parms1 = TREE_CHAIN (parms1);
+ parms2 = TREE_CHAIN (parms2);
+ }
+
+ if (off1)
+ parms1 = TREE_CHAIN (parms1);
+ else if (off2)
+ parms2 = TREE_CHAIN (parms2);
+
+ for (; parms1; ++i)
+ {
+ if (!cp_tree_equal (TREE_PURPOSE (parms1),
+ TREE_PURPOSE (parms2)))
+ {
+ if (warn)
+ {
+ permerror (input_location, "default argument mismatch in "
+ "overload resolution");
+ inform (input_location,
+ " candidate 1: %q+#F", cand1->fn);
+ inform (input_location,
+ " candidate 2: %q+#F", cand2->fn);
+ }
+ else
+ add_warning (cand1, cand2);
+ break;
+ }
+ parms1 = TREE_CHAIN (parms1);
+ parms2 = TREE_CHAIN (parms2);
+ }
+
+ return 1;
+ }
tweak:
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index c1885be..1a96384 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6164,25 +6164,33 @@ resolve_address_of_overloaded_function (tree target_type,
}
else if (TREE_CHAIN (matches))
{
- /* There were too many matches. */
+ /* There were too many matches. First check if they're all
+ the same function. */
+ tree match;
- if (flags & tf_error)
+ fn = TREE_PURPOSE (matches);
+ for (match = TREE_CHAIN (matches); match; match = TREE_CHAIN (match))
+ if (!decls_match (fn, TREE_PURPOSE (matches)))
+ break;
+
+ if (match)
{
- tree match;
+ if (flags & tf_error)
+ {
+ error ("converting overloaded function %qD to type %q#T is ambiguous",
+ DECL_NAME (OVL_FUNCTION (overload)),
+ target_type);
- error ("converting overloaded function %qD to type %q#T is ambiguous",
- DECL_NAME (OVL_FUNCTION (overload)),
- target_type);
+ /* Since print_candidates expects the functions in the
+ TREE_VALUE slot, we flip them here. */
+ for (match = matches; match; match = TREE_CHAIN (match))
+ TREE_VALUE (match) = TREE_PURPOSE (match);
- /* Since print_candidates expects the functions in the
- TREE_VALUE slot, we flip them here. */
- for (match = matches; match; match = TREE_CHAIN (match))
- TREE_VALUE (match) = TREE_PURPOSE (match);
+ print_candidates (matches);
+ }
- print_candidates (matches);
+ return error_mark_node;
}
-
- return error_mark_node;
}
/* Good, exactly one match. Now, convert it to the correct type. */
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index f02605f..2eebb79 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -3607,10 +3607,9 @@ merge_functions (tree s1, tree s2)
/* If the function from S2 is already in S1, there is no
need to add it again. For `extern "C"' functions, we
might have two FUNCTION_DECLs for the same function, in
- different namespaces; again, we only need one of them. */
- if (fn1 == fn2
- || (DECL_EXTERN_C_P (fn1) && DECL_EXTERN_C_P (fn2)
- && DECL_NAME (fn1) == DECL_NAME (fn2)))
+ different namespaces, but let's leave them in in case
+ they have different default arguments. */
+ if (fn1 == fn2)
break;
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 92815c0..8dd3579 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12679,6 +12679,7 @@ resolve_overloaded_unification (tree tparms,
{
tree tempargs = copy_node (targs);
int good = 0;
+ tree goodfn = NULL_TREE;
bool addr_p;
if (TREE_CODE (arg) == ADDR_EXPR)
@@ -12724,8 +12725,13 @@ resolve_overloaded_unification (tree tparms,
if (subargs)
{
elem = tsubst (TREE_TYPE (fn), subargs, tf_none, NULL_TREE);
- good += try_one_overload (tparms, targs, tempargs, parm,
- elem, strict, sub_strict, addr_p);
+ if (try_one_overload (tparms, targs, tempargs, parm,
+ elem, strict, sub_strict, addr_p)
+ && (!goodfn || !decls_match (goodfn, elem)))
+ {
+ goodfn = elem;
+ ++good;
+ }
}
--processing_template_decl;
}
@@ -12738,9 +12744,14 @@ resolve_overloaded_unification (tree tparms,
return false;
else
for (; arg; arg = OVL_NEXT (arg))
- good += try_one_overload (tparms, targs, tempargs, parm,
- TREE_TYPE (OVL_CURRENT (arg)),
- strict, sub_strict, addr_p);
+ if (try_one_overload (tparms, targs, tempargs, parm,
+ TREE_TYPE (OVL_CURRENT (arg)),
+ strict, sub_strict, addr_p)
+ && (!goodfn || !decls_match (goodfn, OVL_CURRENT (arg))))
+ {
+ goodfn = OVL_CURRENT (arg);
+ ++good;
+ }
/* [temp.deduct.type] A template-argument can be deduced from a pointer
to function or pointer to member function argument if the set of
diff --git a/gcc/testsuite/g++.dg/overload/extern-C-1.C b/gcc/testsuite/g++.dg/overload/extern-C-1.C
new file mode 100644
index 0000000..839a0b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/extern-C-1.C
@@ -0,0 +1,17 @@
+// PR c++/34691
+
+namespace A {
+ extern "C" void f(int = 5); // { dg-message "= 5" }
+}
+namespace B {
+ extern "C" void f(int = 4); // { dg-message "= 4" }
+}
+
+using A::f;
+using B::f;
+int main() {
+ void (*fp)(int) = f; // OK
+ f(3); // OK
+ f(); // { dg-error "default argument mismatch" }
+}
+