Title
Avoid circularity in specification of scope for friend class declarations
Status
open
Section
9.2.9.4 [dcl.type.elab]
Submitter
Jim X

Created on 2022-07-04.00:00:00 last changed 2 months ago

Messages

Date: 2022-07-04.00:00:00

Consider:

auto f(struct X* ptr) {
  struct D {
    private:
      int d;
      friend class X;      // #1
  };
  return D{};
}
X* b = 0;
struct X {
  void show() {
    auto t = f(0);
    t.d = 10;              // #2 error: ::X is not a friend of f::D
  }
};

The target scope for #2 is f's block scope, making ::X not a friend of f::D. Thus the access at #2 is ill-formed. Clang disagrees.

Subclause 9.2.9.4 [dcl.type.elab] paragraph 3 specifies:

... If E contains an identifier but no nested-name-specifier and (unqualified) lookup for the identifier finds nothing, E shall not be introduced by the enum keyword and declares the identifier as a class-name. The target scope of E is the nearest enclosing namespace or block scope.

If an elaborated-type-specifier appears with the friend specifier as an entire member-declaration, the member-declaration shall have one of the following forms:

friend class-key nested-name-specifieropt identifier ;
...
Any unqualified lookup for the identifier (in the first case) does not consider scopes that contain the target scope; no name is bound.

This specification is circular in that the target scope that limits unqualified lookup is defined only if the identifier is actually declared, but the identifier is declared only if lookup finds nothing.

Possible resolution:

Change in 9.2.9.4 [dcl.type.elab] paragraph 4 as follows:

... Any unqualified lookup for the identifier (in the first case) does not consider scopes that contain the target nearest enclosing namespace or block scope; no name is bound. [ Note: ... ]
History
Date User Action Args
2022-07-04 00:00:00admincreate