Argument-dependent lookup for friend declarations.  Add a new decl type,
FriendFunctionDecl, and create instances as appropriate.

The design of FriendFunctionDecl is still somewhat up in the air;  you can
befriend arbitrary types of functions --- methods, constructors, etc. ---
and it's not clear that this representation captures that very well.
We'll have a better picture when we start consuming this data in access
control.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78653 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index aac79e9..ab5578b 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2353,6 +2353,7 @@
   if (D.getDeclSpec().isThreadSpecified())
     Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
 
+  bool isFriend = D.getDeclSpec().isFriendSpecified();
   bool isInline = D.getDeclSpec().isInlineSpecified();
   bool isVirtual = D.getDeclSpec().isVirtualSpecified();
   bool isExplicit = D.getDeclSpec().isExplicitSpecified();
@@ -2382,7 +2383,20 @@
   
   bool isVirtualOkay = false;
   FunctionDecl *NewFD;
-  if (D.getKind() == Declarator::DK_Constructor) {
+  if (isFriend) {
+    // DC is the namespace in which the function is being declared.
+    assert(DC->isFileContext() || PrevDecl);
+
+    // C++ [class.friend]p5
+    //   A function can be defined in a friend declaration of a
+    //   class . . . . Such a function is implicitly inline.
+    isInline |= IsFunctionDefinition;
+
+    NewFD = FriendFunctionDecl::Create(Context, DC,
+                                       D.getIdentifierLoc(), Name, R,
+                                       isInline,
+                                       D.getDeclSpec().getFriendSpecLoc());
+  } else if (D.getKind() == Declarator::DK_Constructor) {
     // This is a C++ constructor declaration.
     assert(DC->isRecord() &&
            "Constructors can only be declared in a member context");
@@ -2643,7 +2657,7 @@
   if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
     // An out-of-line member function declaration must also be a
     // definition (C++ [dcl.meaning]p1).
-    if (!IsFunctionDefinition) {
+    if (!IsFunctionDefinition && !isFriend) {
       Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
         << D.getCXXScopeSpec().getRange();
       NewFD->setInvalidDecl();
@@ -4142,7 +4156,7 @@
     //   If a friend declaration in a non-local class first declares a
     //   class or function, the friend class or function is a member of
     //   the innermost enclosing namespace.
-    while (!SearchDC->isNamespace() && !SearchDC->isTranslationUnit())
+    while (!SearchDC->isFileContext())
       SearchDC = SearchDC->getParent();
 
     // The entity of a decl scope is a DeclContext; see PushDeclContext.