[cfe-commits] r81801 - in /cfe/trunk: 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

John McCall rjmccall at apple.com
Mon Sep 14 14:59:20 PDT 2009


Author: rjmccall
Date: Mon Sep 14 16:59:20 2009
New Revision: 81801

URL: http://llvm.org/viewvc/llvm-project?rev=81801&view=rev
Log:
Skeletal support for friend class templates.


Added:
    cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p5.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=81801&r1=81800&r2=81801&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Mon Sep 14 16:59:20 2009
@@ -419,7 +419,8 @@
   /// 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;
 

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=81801&r1=81800&r2=81801&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Mon Sep 14 16:59:20 2009
@@ -1214,7 +1214,8 @@
 
   /// ActOnFriendTypeDecl - Parsed a friend type declaration.
   virtual DeclPtrTy ActOnFriendTypeDecl(Scope *S,
-                                        const DeclSpec &DS) {
+                                        const DeclSpec &DS,
+                                        bool IsTemplate) {
     return DeclPtrTy();
   }
 

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=81801&r1=81800&r2=81801&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Sep 14 16:59:20 2009
@@ -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);
 

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=81801&r1=81800&r2=81801&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Sep 14 16:59:20 2009
@@ -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);
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=81801&r1=81800&r2=81801&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Sep 14 16:59:20 2009
@@ -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);

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=81801&r1=81800&r2=81801&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Sep 14 16:59:20 2009
@@ -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();

Added: cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p5.cpp?rev=81801&view=auto

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p5.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p5.cpp Mon Sep 14 16:59:20 2009
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class A {
+  template <class T> friend class B;
+};
+





More information about the cfe-commits mailing list