]> granicus.if.org Git - clang/commitdiff
Skeletal support for friend class templates.
authorJohn McCall <rjmccall@apple.com>
Mon, 14 Sep 2009 21:59:20 +0000 (21:59 +0000)
committerJohn McCall <rjmccall@apple.com>
Mon, 14 Sep 2009 21:59:20 +0000 (21:59 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81801 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclBase.h
include/clang/Parse/Action.h
lib/Parse/ParseDeclCXX.cpp
lib/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.decls/temp.friend/p5.cpp [new file with mode: 0644]

index 7e188c26f9c2fe775fa7ff4146ebabb61965896f..f60d36fc3d937a2804cd5ba2952e5a7dcdad0e5d 100644 (file)
@@ -419,7 +419,8 @@ public:
   /// same entity may not (and probably don't) share this property.
   void setObjectOfFriendDecl(bool PreviouslyDeclared) {
     unsigned OldNS = IdentifierNamespace;
-    assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary)
+    assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary ||
+            OldNS == (IDNS_Tag | IDNS_Ordinary))
            && "unsupported namespace for undeclared friend");
     if (!PreviouslyDeclared) IdentifierNamespace = 0;
 
index 83fc0ae263057fe9e2f344961d0577a6e9611a2c..f15398465b99c6e475667d0678bb15f982795a3f 100644 (file)
@@ -1214,7 +1214,8 @@ public:
 
   /// ActOnFriendTypeDecl - Parsed a friend type declaration.
   virtual DeclPtrTy ActOnFriendTypeDecl(Scope *S,
-                                        const DeclSpec &DS) {
+                                        const DeclSpec &DS,
+                                        bool IsTemplate) {
     return DeclPtrTy();
   }
 
index b9a0d6165e7e8c1e8f5a37571ac2c58396ffa1e0..e1228cf1fdf241447f74d751926629e0b6ed6a16 100644 (file)
@@ -1015,11 +1015,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
     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);
 
index c0719d4577a71b5aea811508e4950588ff02db5d..1811f29a3ceec4047af4f7adff8097e21a367d78 100644 (file)
@@ -2246,7 +2246,7 @@ public:
                                                  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);
 
index 0adf3e834e99e0b8c5e6357fb21e693b14326a79..9e497782507828c6230fc5bfae9453c9742a014b 100644 (file)
@@ -4009,12 +4009,35 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
 }
 
 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);
index ab791a468cf0c014265a860c769715203a32870f..ad9328f2cac63dd327479ab95ed69550a07ef7dc 100644 (file)
@@ -556,13 +556,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
   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 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
   // 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 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
   (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 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
   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();
diff --git a/test/CXX/temp/temp.decls/temp.friend/p5.cpp b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
new file mode 100644 (file)
index 0000000..2c4a7c9
--- /dev/null
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class A {
+  template <class T> friend class B;
+};
+