[PATCH] c++: Function found via ADL when it should not [PR95074]

Marek Polacek polacek@redhat.com
Tue May 12 20:18:15 GMT 2020


I noticed that we don't implement [basic.lookup.argdep]/3: quite correctly;
it says "If X (the lookup set produced by unqualified lookup) contains
-- a block-scope function declaration that is not a using-declaration
[...]
then Y (the lookup set produced by ADL) is empty."
but we were still performing ADL in fn1 in the attached test.  The
problem was that we were only looking at the first function in the
overload set which in this case happened to be a using-declaration, and
those don't suppress ADL.  We have to look through the whole set to find
out if unqualified lookup found a block-scope function declaration, or
a member function declaration.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

	PR c++/95074
	* parser.c (cp_parser_postfix_expression) <case CPP_OPEN_PAREN>: When
	looking for a block-scope function declaration, look through the whole
	set, not just the first function in the overload set.

	* g++.dg/lookup/koenig15.C: New test.
---
 gcc/cp/parser.c                        | 26 +++++++++------
 gcc/testsuite/g++.dg/lookup/koenig15.C | 45 ++++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/lookup/koenig15.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 10627cb1c92..f1ddef220fe 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -7385,19 +7385,25 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 		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 (!((TREE_CODE (fn) == USING_DECL && DECL_DEPENDENT_P (fn))
-			  || DECL_FUNCTION_MEMBER_P (fn)
-			  || DECL_LOCAL_FUNCTION_P (fn)))
+		    bool do_adl_p = true;
+		    tree fns = get_fns (postfix_expression);
+		    for (lkp_iterator iter (fns); iter; ++iter)
+		      {
+			tree fn = STRIP_TEMPLATE (*iter);
+			if ((TREE_CODE (fn) == USING_DECL
+			     && DECL_DEPENDENT_P (fn))
+			    || DECL_FUNCTION_MEMBER_P (fn)
+			    || DECL_LOCAL_FUNCTION_P (fn))
+			  {
+			    do_adl_p = false;
+			    break;
+			  }
+		      }
+
+		    if (do_adl_p)
 		      {
 			koenig_p = true;
 			if (!any_type_dependent_arguments_p (args))
diff --git a/gcc/testsuite/g++.dg/lookup/koenig15.C b/gcc/testsuite/g++.dg/lookup/koenig15.C
new file mode 100644
index 00000000000..f317c010dde
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/koenig15.C
@@ -0,0 +1,45 @@
+// PR c++/95074 - Function found via ADL when it should not.
+// { dg-do compile }
+
+namespace N {
+  struct S { };
+  void f(S);
+}
+
+namespace M {
+  void f(int);
+}
+
+void
+fn0 ()
+{
+  N::S s;
+  using M::f;
+  f (s);
+}
+
+void
+fn1 ()
+{
+  N::S s;
+  extern void f(char);
+  using M::f;
+  f (s); // { dg-error "no matching function" }
+}
+
+void
+fn2 ()
+{
+  N::S s;
+  using M::f;
+  extern void f(char);
+  f (s); // { dg-error "no matching function" }
+}
+
+void
+fn3 ()
+{
+  N::S s;
+  extern void (*f)(char);
+  f (s); // { dg-error "cannot convert" }
+}

base-commit: f0de5d83eecd4902e4a0447bfa4863014b6b2eaf
-- 
Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA



More information about the Gcc-patches mailing list