Bug 24795 - Error in dependent name-lookup
Summary: Error in dependent name-lookup
Status: RESOLVED DUPLICATE of bug 2922
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.1.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-11-11 14:27 UTC by Richard Biener
Modified: 2005-12-25 02:14 UTC (History)
8 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Richard Biener 2005-11-11 14:27:59 UTC
Consider the following testcase, where the call to foo(B&) should be resolved
at template instantiaton time of the function template g.

struct A {};
struct B {};

void foo(A&);

template <class T>
void g(T& t)
{
  foo(t);
}

void foo(B&);

void bar(B& b)
{
  g(b);
}

This works correctly.  Now add some namespace blurb (which shouldn't really
change anything here) and get

namespace X {
struct A {};
struct B {};
}

void foo(X::A&);

template <class T>
void g(T& t)
{
  foo(t);
}

void foo(X::B&);

void bar(X::B& b)
{
  g(b);
}

where 4.1 now rejects this with
t2.C: In function ‘void g(T&) [with T = X::B]’:
t2.C:18:   instantiated from here
t2.C:11: error: invalid initialization of reference of type ‘X::A&’ from expression of type ‘X::B’
t2.C:6: error: in passing argument 1 of ‘void foo(X::A&)’

even more funny, adding an unrelated overload of foo:

namespace X {
struct A {};
struct B {};
struct C {};
}

void foo(X::A&);
void foo(X::C&);

template <class T>
void g(T& t)
{
  foo(t);
}

void foo(X::B&);

void bar(X::B& b)
{
  g(b);
}

we reject it with
t3.C: In function ‘void g(T&) [with T = X::B]’:
t3.C:20:   instantiated from here
t3.C:13: error: no matching function for call to ‘foo(X::B&)’
t3.C:7: note: candidates are: void foo(X::A&)
t3.C:8: note:                 void foo(X::C&)


EDG rejects the latter two with a consistent error message (in -strict_ansi mode):
t3.C(13): error: no instance of overloaded function "foo" matches the argument list
            argument types are: (X::B)
    foo(t);
    ^
          detected during instantiation of "void g(T &) [with T=X::B]" 

compilation aborted for t3.C (code 2)


g++ accepts even the following, which may hint at the reason for the inconsistent error messages?

namespace X {
struct B {};
}

template <class T>
void g(T& t)
{
  foo(t);
}

void foo(X::B&);

void bar(X::B& b)
{
  g(b);
}


I'm really unsure who's at fault here and if this is rejects-valid or
rejects-invalid.  Digging in the standard now, but maybe someone can
point me at the relevant section.
Comment 1 Richard Biener 2005-11-11 15:06:07 UTC
It looks like we are looking up the name 'foo' from bar in X only (because
X::B is a qualified type and so special name-lookup rules apply), but search
the scope of bar (or g) only from the context of g.  So the following compiles:

namespace X {
struct A {};
struct B {};
}

void foo(X::A&);

template <class T>
void g(T& t)
{
  foo(t);
}

namespace X {
void foo(X::B&);
}

void bar(X::B& b)
{
  g(b);
}
Comment 2 Richard Biener 2005-11-11 15:44:12 UTC
From 14.6.2/1 one could argue that foo is a dependent name and thus is looked up in the context of the point of instantiation, bar, which should find foo(X::B&).

But 14.6.4/1 contradicts this in telling we search the visible decls from the point of the template definition and only those from namespaces associated with the types of the function arguments from the instantiation context and the definition context.

Which would make the last, working, example a accepts-invalid.
Comment 3 Andrew Pinski 2005-11-11 15:44:41 UTC
There are a couple of DR reports about this issue.  Basicially what you are doing is invalid (IIRC).

The error message which EDG is less helpful than the error message GCC gives because it does not list the overloaded set while GCC does.  That is the only difference.
Comment 4 Andrew Pinski 2005-11-11 15:47:06 UTC
(In reply to comment #2)
> Which would make the last, working, example a accepts-invalid.

You missed Argument dependent namelookup rules (Koenig) which is 3.4.2.
Comment 5 Andrew Pinski 2005-11-11 15:49:03 UTC
Anyways the revelevent bug reports about why the second and thrid examples are invalid code are PR 5660 and PR 2922.
Comment 6 Andrew Pinski 2005-11-11 15:57:59 UTC
This is invalid.
The last example has argument-dependent lookup working which is still required to run even after finding an overloaded set.  PR 2922 explains all this correctly (and so does the change log for the patch):
	* semantics.c (perform_koenig_lookup): For dependent calls, just
	return the set of functions we've found so far. Later, it will be
	augmented by those found through argument-dependent lookup.
	* name-lookup.c (lookup_arg_dependent): Implement DR 164 by removing
	the optimization that skips namespaces where the functions were
	originally found.
Comment 7 Richard Biener 2005-11-11 16:23:09 UTC
by 14.6.2/1 I would expect search from both instantiation and definition.

by 14.6.4/1 I would expect (as is the case for 4.1) search from the instantiation
point to be restricted to namespace X.

I do not see how Koenig lookup can make it /fail/, but only work (and that it doesn't).

We're still speaking about

namespace X {
struct A {};
struct B {};
}

void foo(X::A&);

template <class T>
void g(T& t)
{
  foo(t);
}

void foo(X::B&);

void bar(X::B& b)
{
  g(b);
}
Comment 8 Richard Biener 2005-11-11 16:25:49 UTC
Please someone else comment on this.
Comment 9 Andrew Pinski 2005-11-11 17:45:52 UTC
(In reply to comment #7)
> by 14.6.2/1 I would expect search from both instantiation and definition.
> by 14.6.4/1 I would expect (as is the case for 4.1) search from the
> instantiation
> point to be restricted to namespace X.
> I do not see how Koenig lookup can make it /fail/, but only work (and that it
> doesn't).

 Koenig lookup does not apply here as foo is not in the namespace X.
Comment 10 Andrew Pinski 2005-12-25 02:14:31 UTC
> We're still speaking about
> 
> namespace X {
> struct A {};
> struct B {};
> }
> 
> void foo(X::A&);
> 
> template <class T>
> void g(T& t)
> {
>   foo(t);
> }
> 
> void foo(X::B&);
> 
> void bar(X::B& b)
> {
>   g(b);
> }

This is invalid as Koenig look cannot and will not find the second foo as it is not in the namespace X.
The overloaded set for foo in g only contains the first foo and then when instantiating it, it reruns the Koenig rules and that says it can only find foo in the namespace X so the code is rejected.

So this is a dup of bug 2922 after all.


*** This bug has been marked as a duplicate of 2922 ***