First pass at friend semantics.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78274 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 44ee2eb..90ba65a 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1275,6 +1275,9 @@
     if (!DS.getTypeRep()) // We probably had an error
       return DeclPtrTy();
 
+    // Note that the above type specs guarantee that the
+    // type rep is a Decl, whereas in many of the others
+    // it's a Type.
     Tag = dyn_cast<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
   }
 
@@ -3973,7 +3976,8 @@
       // If this is a use of a previous tag, or if the tag is already declared
       // in the same scope (so that the definition/declaration completes or
       // rementions the tag), reuse the decl.
-      if (TUK == TUK_Reference || isDeclInScope(PrevDecl, SearchDC, S)) {
+      if (TUK == TUK_Reference || TUK == TUK_Friend ||
+          isDeclInScope(PrevDecl, SearchDC, S)) {
         // Make sure that this wasn't declared as an enum and now used as a
         // struct or something similar.
         if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
@@ -4009,6 +4013,11 @@
           if (TUK == TUK_Reference)
             return DeclPtrTy::make(PrevDecl);
 
+          // If this is a friend, make sure we create the new
+          // declaration in the appropriate semantic context.
+          if (TUK == TUK_Friend)
+            SearchDC = PrevDecl->getDeclContext();
+
           // Diagnose attempts to redefine a tag.
           if (TUK == TUK_Definition) {
             if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) {
@@ -4039,7 +4048,8 @@
           }
         }
         // If we get here we have (another) forward declaration or we
-        // have a definition.  Just create a new decl.        
+        // have a definition.  Just create a new decl.
+
       } else {
         // If we get here, this is a definition of a new tag type in a nested
         // scope, e.g. "struct foo; void bar() { struct foo; }", just create a 
@@ -4102,6 +4112,18 @@
            (S->getEntity() && 
             ((DeclContext *)S->getEntity())->isTransparentContext()))
       S = S->getParent();
+
+  } else if (TUK == TUK_Friend && SS.isEmpty() && Name) {
+    // C++ [namespace.memdef]p3:
+    //   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())
+      SearchDC = SearchDC->getParent();
+
+    // The entity of a decl scope is a DeclContext; see PushDeclContext.
+    while (S->getEntity() != SearchDC)
+      S = S->getParent();
   }
 
 CreateNewDecl:
@@ -4195,14 +4217,14 @@
   New->setLexicalDeclContext(CurContext);
 
   // Set the access specifier.
-  if (!Invalid)
+  if (!Invalid && TUK != TUK_Friend)
     SetMemberAccessSpecifier(New, PrevDecl, AS);
 
   if (TUK == TUK_Definition)
     New->startDefinition();
   
   // If this has an identifier, add it to the scope stack.
-  if (Name) {
+  if (Name && TUK != TUK_Friend) {
     S = getNonFieldDeclScope(S);
     PushOnScopeChains(New, S);
   } else {