Clang Sources, friend classes can't access private members?

Hi all!
I found that in clang sources, in Sema.h in particular,
it is required to add class predeclaration before friending it, like this:

  class DelayedDiagnostics; // predeclaration is required here, otherwise it won't compiled

  class DelayedDiagnosticsState {
    sema::DelayedDiagnosticPool *SavedPool;
    friend class Sema::DelayedDiagnostics;
  };
  // ...
  class DelayedDiagnostics {
  // ...
    DelayedDiagnosticsState push(sema::DelayedDiagnosticPool &pool) {
      DelayedDiagnosticsState state;
      state.SavedPool = CurPool; // Private access.
      // ...
    }
  };

And yet it contradicts standard, which states that the name of the class that is used in this friend declaration does not need to be previously declared.

Honestly I didn't try to debug it. I tried to reproduce it though, but failed. The example below compiled with no errors:

namespace clang {
class Sema {
  public:
  class A {
    int x;
    friend class B;
  };

  class B {
    A a;
    void f() {
      a.x = 1; // access private member of A, no error!
    }
  };
};
} // namespace clang

It looks like I'm missing something... Anybody knows why we should predeclare friend classes in clang::Sema?

Thanks!
Stepan Dyatkovskiy

Hi all!
I found that in clang sources, in Sema.h in particular,
it is required to add class predeclaration before friending it, like this:

class DelayedDiagnostics; // predeclaration is required here, otherwise it won’t compiled

class DelayedDiagnosticsState {
sema::DelayedDiagnosticPool *SavedPool;
friend class Sema::DelayedDiagnostics;
};
// …
class DelayedDiagnostics {
// …
DelayedDiagnosticsState push(sema::DelayedDiagnosticPool &pool) {
DelayedDiagnosticsState state;
state.SavedPool = CurPool; // Private access.
// …
}
};

And yet it contradicts standard, which states that the name of the class that is used in this friend declaration does not need to be previously declared.

Honestly I didn’t try to debug it. I tried to reproduce it though, but failed. The example below compiled with no errors:

namespace clang {
class Sema {
public:
class A {
int x;
friend class B;
};

class B {
A a;
void f() {
a.x = 1; // access private member of A, no error!
}
};
};
} // namespace clang

It looks like I’m missing something… Anybody knows why we should predeclare friend classes in clang::Sema?

I can’t reproduce your minimized test case - when I try to compile the example you gave, I get an error:

delay.cpp:12:9: error: ‘x’ is a private member of ‘clang::Sema::A’
a.x = 1; // access private member of A, no error!
^
delay.cpp:5:9: note: implicitly declared private here
int x;
^
1 error generated.

But if you make ‘B’ not a member of ‘Sema’, but instead just a member of the ‘clang’ namespace, then it compiles - which shows the difference between your example and the original. In the original code, it says “friend class Sema::B”, whereas your example is “friend class B” - in the latter case, that unqualified ‘class B’ (in the absence of a prior declaration of ‘class B’ inside class Sema) refers to/injects a declaration of ‘B’ into the clang namespace, not into the Sema class.

David, Thanks!
I have updated my toolchain, and now it also emits error. Which turned out to be a correct behavour.
I obviously missed this statement (taken from cppreference, for I don’t have a draft yet):
“When a local class declares an unqualified function or class as a friend, only functions and classes in the innermost non-class scope are looked up”.
So as you mentioned declaring unqualified friend class in Sema, means that such should be non-nested declaration of “clang” namespace.

Now everything makes sense! Thanks!
Stepan Dyatkovskiy.