Skeletal support for friend class templates.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81801 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index b9a0d61..e1228cf 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1015,11 +1015,8 @@
     ConsumeToken();
 
     if (DS.isFriendSpecified()) {
-      // FIXME: Friend templates are ignored for now.
-      if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate)
-        return;
-      
-      Actions.ActOnFriendTypeDecl(CurScope, DS);
+      bool IsTemplate = TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate;
+      Actions.ActOnFriendTypeDecl(CurScope, DS, IsTemplate);
     } else
       Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
 
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index c0719d4..1811f29 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2246,7 +2246,7 @@
                                                  ExprArg AssertExpr,
                                                  ExprArg AssertMessageExpr);
 
-  DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS);
+  DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, bool IsTemplate);
   DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
                                     MultiTemplateParamsArg TemplateParams);
 
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 0adf3e8..9e49778 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -4009,12 +4009,35 @@
 }
 
 Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S,
-                                          const DeclSpec &DS) {
+                                          const DeclSpec &DS,
+                                          bool IsTemplate) {
   SourceLocation Loc = DS.getSourceRange().getBegin();
 
   assert(DS.isFriendSpecified());
   assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
 
+  // Handle friend templates specially.
+  if (IsTemplate) {
+    Decl *D;
+    switch (DS.getTypeSpecType()) {
+    default:
+      // FIXME: implement this
+      assert(false && "unelaborated type templates are currently unimplemented!");
+    case DeclSpec::TST_class:
+    case DeclSpec::TST_union:
+    case DeclSpec::TST_struct:
+      D = (Decl*) DS.getTypeRep();
+    }
+
+    ClassTemplateDecl *Temp = cast<ClassTemplateDecl>(D);
+    FriendDecl *FD = FriendDecl::Create(Context, CurContext, Loc, Temp,
+                                        DS.getFriendSpecLoc());
+    FD->setAccess(AS_public);
+    CurContext->addDecl(FD);
+
+    return DeclPtrTy::make(FD);
+  }
+
   // Try to convert the decl specifier to a type.
   bool invalid = false;
   QualType T = ConvertDeclSpecToType(DS, Loc, invalid);
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index ab791a4..ad9328f 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -556,13 +556,8 @@
   if (CheckTemplateDeclScope(S, TemplateParams))
     return true;
 
-  TagDecl::TagKind Kind;
-  switch (TagSpec) {
-  default: assert(0 && "Unknown tag type!");
-  case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
-  case DeclSpec::TST_union:  Kind = TagDecl::TK_union; break;
-  case DeclSpec::TST_class:  Kind = TagDecl::TK_class; break;
-  }
+  TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
+  assert(Kind != TagDecl::TK_enum && "can't build template of enumerated type");
 
   // There is no such thing as an unnamed class template.
   if (!Name) {
@@ -657,6 +652,13 @@
   // FIXME: If we had a scope specifier, we better have a previous template
   // declaration!
 
+  // If this is a friend declaration of an undeclared template,
+  // create the template in the innermost namespace scope.
+  if (TUK == TUK_Friend && !PrevClassTemplate) {
+    while (!SemanticContext->isFileContext())
+      SemanticContext = SemanticContext->getParent();
+  }
+
   CXXRecordDecl *NewClass =
     CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc,
                           PrevClassTemplate?
@@ -678,7 +680,11 @@
   (void)T;
 
   // Set the access specifier.
-  SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
+  if (TUK == TUK_Friend)
+    NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */
+                                       PrevClassTemplate != NULL);
+  else 
+    SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
 
   // Set the lexical context of these templates
   NewClass->setLexicalDeclContext(CurContext);
@@ -690,7 +696,23 @@
   if (Attr)
     ProcessDeclAttributeList(S, NewClass, Attr);
 
-  PushOnScopeChains(NewTemplate, S);
+  if (TUK != TUK_Friend)
+    PushOnScopeChains(NewTemplate, S);
+  else {
+    // We might be replacing an existing declaration in the lookup tables;
+    // if so, borrow its access specifier.
+    if (PrevClassTemplate)
+      NewTemplate->setAccess(PrevClassTemplate->getAccess());
+
+    // Friend templates are visible in fairly strange ways.
+    if (!CurContext->isDependentContext()) {
+      DeclContext *DC = SemanticContext->getLookupContext();
+      DC->makeDeclVisibleInContext(NewTemplate, /* Recoverable = */ false);
+      if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
+        PushOnScopeChains(NewTemplate, EnclosingScope,
+                          /* AddToContext = */ false);      
+    }
+  }
 
   if (Invalid) {
     NewTemplate->setInvalidDecl();