title: What is the point of the complicated scoping rules for friend declarations?
body: <p>I recently discovered that friend declarations scoping follows <a href="https://stackoverflow.com/q/8207633/214671">extremely peculiar rules</a> - if you have a <code>friend</code> declaration (definition) for a function or a class that is not already declared, it is automatically declared (defined) in the immediately enclosing namespace, <em>but</em> it is invisible to non-qualified and qualified lookup; however, friend <em>function</em> declarations remain visible through argument-dependent lookup.</p>
  
  <pre><code>struct M {
      friend void foo();
      friend void bar(M);
  };
  
  void baz() {
      foo();    // error, unqualified lookup cannot find it
      ::foo();  // error, qualified lookup cannot find it
      bar(M()); // ok, thanks to ADL magic
  }
  </code></pre>
  
  <p>If you look at the standard (see <a href="https://stackoverflow.com/q/8207633/214671">linked answer</a>), they went to significant lengths to enable this eccentric behavior, adding a specific exception in qualified/non qualified lookup with complex rules. The end result looks to me extremely confusing<sup>1</sup>, with yet-another-corner case to add to implementations. As either</p>
  
  <ul>
  <li>requiring <code>friend</code> declarations to refer to existing names, period; or</li>
  <li>allowing them to declare stuff as it is now, but without altering the ordinary names lookup (so, such names become visible as if declared "normally" in the enclosing namespace)</li>
  </ul>
  
  <p>seem simpler to implement, to specify and, most importantly, to understand, I wonder: why did they bother with this mess? What use cases were they trying to cover? What breaks under any of those simpler rules (in particular the second one, which is the most similar to the existing behavior)?</p>
  
  <hr>
  
  <ol>
  <li><p>For example, in this particular case</p>
  
  <pre><code>struct M {
     friend class N;
  };
  N *foo;
  typedef int N;
  </code></pre>
  
  <p>you get <a href="https://gcc.godbolt.org/z/4Cuwkj" rel="nofollow noreferrer">comically schizophrenic error messages</a></p>
  
  <pre><code>&lt;source&gt;:4:1: error: 'N' does not name a type
   N *foo;
   ^
  &lt;source&gt;:5:13: error: conflicting declaration 'typedef int N'
   typedef int N;
               ^
  &lt;source&gt;:2:17: note: previous declaration as 'class N'
      friend class N;
                   ^
  </code></pre>
  
  <p>where the compiler first claims that there's no such a thing as <code>N</code>, but immediately stops playing dumb when you try to provide a conflicting declaration. </p></li>
  </ol>