Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

name lookup in qualified friend declaration is extremely suspicious #38230

Open
zygoloid mannequin opened this issue Sep 10, 2018 · 4 comments
Open

name lookup in qualified friend declaration is extremely suspicious #38230

zygoloid mannequin opened this issue Sep 10, 2018 · 4 comments
Labels
bugzilla Issues migrated from bugzilla c++

Comments

@zygoloid
Copy link
Mannequin

zygoloid mannequin commented Sep 10, 2018

Bugzilla Link 38882
Version 5.0
OS All
CC @DougGregor

Extended Description

Testcase:

using T = int;

namespace N {
  struct X {
    template<typename T> void f(T);
  };
  template<typename> struct Y {
    template<typename T> friend void X::f(T); // #1
    friend void X::f<>(Y); // #2
  };
}

Here, #​1 resolves T as ::T, not as the template parameter. Strangely, we fail to diagnose this, and instead silently befriend nothing in line #​1.

In #​2, Y resolves to N::Y, not to the injected-class-name of N::Y, and as a result declaration #​2 is rejected because Y is lacking its template arguments.

These results both seem extremely surprising. The standard's rules here are highly unclear, but this cannot be the right behavior...

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
@jwakely
Copy link
Contributor

jwakely commented Jan 6, 2022

Is this another case of the same problem?

namespace ns
{
  struct S { };

  void func(S) { }
}

struct X
{
  friend void ns::func(S);
};

Other compilers accept this, but clang wants the friend decl to use ns::S:

<source>:10:24: error: unknown type name 'S'; did you mean 'ns::S'?
  friend void ns::func(S);
                       ^
                       ns::S
<source>:3:10: note: 'ns::S' declared here
  struct S { };
         ^

@stbergmann
Copy link
Collaborator

Other compilers accept this, but clang wants the friend decl to use ns::S:

...or is the Clang behavior in line with [basic.scope.namespace]/1, since C++23 P1787R6: Declarations and where to find them explicitly stating "non-friend": "For each non-friend redeclaration or specialization whose target scope is or is contained by the scope, the portion after the declarator-id, class-head-name, or enum-head-name is also included in the scope."

@stbergmann
Copy link
Collaborator

stbergmann commented Jan 6, 2022

(which would be CWG2370 friend declarations of namespace-scope functions (which states "There is implementation divergence on these points."), reportedly "resolved by performing a search in (only) the immediate scope of any friend", P1787R6: Declarations and where to find them)

@zygoloid
Copy link
Collaborator

zygoloid commented Jan 6, 2022

I think the relevant rule is:

In a friend declaration declarator whose declarator-id is a qualified-id whose lookup context is ([basic.lookup.qual]) a class or namespace S, lookup for an unqualified name that appears after the declarator-id performs a search in the scope associated with S. If that lookup finds nothing, it undergoes unqualified name lookup.

So in the new example, we should first look for S in namespace ns (but not in its enclosing scopes), then look in class X and its enclosing scopes as usual if that first lookup fails.

In the original example, we should look for T and Y as member names of N::X only (which finds nothing) and then fall back to normal unqualified lookup, so T should name the template parameter of the friend declaration and Y should name the injected-class-name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla c++
Projects
None yet
Development

No branches or pull requests

3 participants