[cfe-commits] r78719 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/AST/DeclNodes.def lib/AST/DeclBase.cpp lib/AST/DeclCXX.cpp lib/Sema/SemaDeclCXX.cpp

John McCall rjmccall at apple.com
Tue Aug 11 14:13:22 PDT 2009


Author: rjmccall
Date: Tue Aug 11 16:13:21 2009
New Revision: 78719

URL: http://llvm.org/viewvc/llvm-project?rev=78719&view=rev
Log:
Add a FriendClassDecl type for holding declarations of friend types in 
the AST, and create such declarations.


Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/AST/DeclNodes.def
    cfe/trunk/lib/AST/DeclBase.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp

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

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Aug 11 16:13:21 2009
@@ -1273,6 +1273,42 @@
   static bool classof(const FriendFunctionDecl *D) { return true; }
 };
   
+/// FriendClassDecl - Represents the declaration of a friend class.
+class FriendClassDecl : public Decl {
+  // The friended type.  In C++0x, this can be an arbitrary type,
+  // which we simply ignore if it's not a record type.
+  const QualType FriendType;
+
+  // Location of the 'friend' specifier.
+  const SourceLocation FriendLoc;
+
+  FriendClassDecl(DeclContext *DC, SourceLocation L,
+                  QualType T, SourceLocation FriendL)
+    : Decl(FriendClass, DC, L),
+      FriendType(T),
+      FriendLoc(FriendL)
+  {}
+
+public:
+  static FriendClassDecl *Create(ASTContext &C, DeclContext *DC,
+                                 SourceLocation L, QualType T,
+                                 SourceLocation FriendL);
+
+  QualType getFriendType() const {
+    return FriendType;
+  }
+
+  SourceLocation getFriendLoc() const {
+    return FriendLoc;
+  }
+
+  // Implement isa/cast/dyncast/etc.
+  static bool classof(const Decl *D) { 
+    return D->getKind() == FriendClass;
+  }
+  static bool classof(const FriendClassDecl *D) { return true; }
+};
+  
 /// LinkageSpecDecl - This represents a linkage specification.  For example:
 ///   extern "C" void foo();
 ///

Modified: cfe/trunk/include/clang/AST/DeclNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclNodes.def?rev=78719&r1=78718&r2=78719&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclNodes.def (original)
+++ cfe/trunk/include/clang/AST/DeclNodes.def Tue Aug 11 16:13:21 2009
@@ -125,6 +125,7 @@
 DECL(ObjCForwardProtocol, Decl)
 DECL(ObjCClass, Decl)
 DECL(FileScopeAsm, Decl)
+DECL(FriendClass, Decl)
 DECL(StaticAssert, Decl)
 LAST_DECL(Block, Decl)
 

Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=78719&r1=78718&r2=78719&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Tue Aug 11 16:13:21 2009
@@ -199,6 +199,7 @@
     case ObjCCompatibleAlias:
       return IDNS_Ordinary;
 
+    case FriendClass:
     case FriendFunction:
       return IDNS_Friend;
       

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=78719&r1=78718&r2=78719&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Aug 11 16:13:21 2009
@@ -743,14 +743,20 @@
   return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter;
 }
 
-FriendFunctionDecl *FriendFunctionDecl::Create(ASTContext &C,DeclContext *DC,
+FriendFunctionDecl *FriendFunctionDecl::Create(ASTContext &C,
+                                               DeclContext *DC,
                                                SourceLocation L,
                                                DeclarationName N, QualType T,
                                                bool isInline,
                                                SourceLocation FriendL) {
   return new (C) FriendFunctionDecl(DC, L, N, T, isInline, FriendL);
 }
-                                               
+
+FriendClassDecl *FriendClassDecl::Create(ASTContext &C, DeclContext *DC,
+                                         SourceLocation L, QualType T,
+                                         SourceLocation FriendL) {
+  return new (C) FriendClassDecl(DC, L, T, FriendL);
+}                                               
 
 LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
                                          DeclContext *DC, 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Aug 11 16:13:21 2009
@@ -3320,68 +3320,98 @@
   assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
 
   // If there's no declarator, then this can only be a friend class
-  // declaration (or else it's just invalid).
+  // declaration (or else it's just syntactically invalid).
   if (!D) {
+    SourceLocation Loc = DS.getSourceRange().getBegin();
 
-    // C++ [class.friend]p2:
-    //   An elaborated-type-specifier shall be used in a friend declaration
-    //   for a class.*
-    //   * The class-key of the elaborated-type-specifier is required.
-    CXXRecordDecl *RD = 0;
-
-    switch (DS.getTypeSpecType()) {
-    case DeclSpec::TST_class:
-    case DeclSpec::TST_struct:
-    case DeclSpec::TST_union:
-      RD = dyn_cast_or_null<CXXRecordDecl>(static_cast<Decl*>(DS.getTypeRep()));
-      if (!RD) return DeclPtrTy();
-      break;
-
-    case DeclSpec::TST_typename:
-      if (const RecordType *RT = 
-          ((const Type*) DS.getTypeRep())->getAs<RecordType>())
-        RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
-      // fallthrough
-    default:
-      if (RD) {
-        Diag(DS.getFriendSpecLoc(), diag::err_unelaborated_friend_type)
-          << (RD->isUnion())
-          << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
-                                      RD->isUnion() ? " union" : " class");
-        return DeclPtrTy::make(RD);
+    QualType T;
+    DeclContext *DC;
+
+    // In C++0x, we just accept any old type.
+    if (getLangOptions().CPlusPlus0x) {
+      bool invalid = false;
+      QualType T = ConvertDeclSpecToType(DS, Loc, invalid);
+      if (invalid)
+        return DeclPtrTy();
+
+      // The semantic context in which to create the decl.  If it's not
+      // a record decl (or we don't yet know if it is), create it in the
+      // current context.
+      DC = CurContext;
+      if (const RecordType *RT = T->getAs<RecordType>())
+        DC = RT->getDecl()->getDeclContext();
+
+    // The C++98 rules are somewhat more complex.
+    } else {
+      // C++ [class.friend]p2:
+      //   An elaborated-type-specifier shall be used in a friend declaration
+      //   for a class.*
+      //   * The class-key of the elaborated-type-specifier is required.
+      CXXRecordDecl *RD = 0;
+    
+      switch (DS.getTypeSpecType()) {
+      case DeclSpec::TST_class:
+      case DeclSpec::TST_struct:
+      case DeclSpec::TST_union:
+        RD = dyn_cast_or_null<CXXRecordDecl>((Decl*) DS.getTypeRep());
+        if (!RD) return DeclPtrTy();
+        break;
+        
+      case DeclSpec::TST_typename:
+        if (const RecordType *RT = 
+            ((const Type*) DS.getTypeRep())->getAs<RecordType>())
+          RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+        // fallthrough
+      default:
+        if (RD) {
+          Diag(DS.getFriendSpecLoc(), diag::err_unelaborated_friend_type)
+            << (RD->isUnion())
+            << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
+                                         RD->isUnion() ? " union" : " class");
+          return DeclPtrTy::make(RD);
+        }
+
+        Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
+          << DS.getSourceRange();
+        return DeclPtrTy();
       }
 
-      Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
-        << DS.getSourceRange();
-      return DeclPtrTy();
+      // The record declaration we get from friend declarations is not
+      // canonicalized; see ActOnTag.
+      assert(RD);
+
+      // C++ [class.friend]p2: A class shall not be defined inside
+      //   a friend declaration.
+      if (RD->isDefinition())
+        Diag(DS.getFriendSpecLoc(), diag::err_friend_decl_defines_class)
+          << RD->getSourceRange();
+
+      // C++98 [class.friend]p1: A friend of a class is a function
+      //   or class that is not a member of the class . . .
+      // But that's a silly restriction which nobody implements for
+      // inner classes, and C++0x removes it anyway, so we only report
+      // this (as a warning) if we're being pedantic.
+      // 
+      // Also, definitions currently get treated in a way that causes
+      // this error, so only report it if we didn't see a definition.
+      else if (RD->getDeclContext() == CurContext &&
+               !getLangOptions().CPlusPlus0x)
+        Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class);
+      
+      T = QualType(RD->getTypeForDecl(), 0);
+      DC = RD->getDeclContext();
     }
 
-    // The record declaration we get from friend declarations is not
-    // canonicalized; see ActOnTag.
-    assert(RD);
-
-    // C++ [class.friend]p2: A class shall not be defined inside
-    //   a friend declaration.
-    if (RD->isDefinition())
-      Diag(DS.getFriendSpecLoc(), diag::err_friend_decl_defines_class)
-        << RD->getSourceRange();
-
-    // C++98 [class.friend]p1: A friend of a class is a function
-    //   or class that is not a member of the class . . .
-    // But that's a silly restriction which nobody implements for
-    // inner classes, and C++0x removes it anyway, so we only report
-    // this 
-    // But no-one implements it that way, and C++0x removes this
-    // restriction, so we only report it (as a warning) if we're being
-    // pedantic.  Ideally this would real -pedantic mode 
-    // 
-    // Also, definitions currently get treated in a way that causes
-    // this error, so only report it if we didn't see a definition.
-    else if (RD->getDeclContext() == CurContext &&
-             !getLangOptions().CPlusPlus0x)
-      Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class);
+    FriendClassDecl *FCD = FriendClassDecl::Create(Context, DC, Loc, T,
+                                                   DS.getFriendSpecLoc());
+    FCD->setLexicalDeclContext(CurContext);
+
+    if (CurContext->isDependentContext())
+      CurContext->addHiddenDecl(FCD);
+    else
+      CurContext->addDecl(FCD);
 
-    return DeclPtrTy::make(RD);
+    return DeclPtrTy::make(FCD);
   }
 
   // We have a declarator.





More information about the cfe-commits mailing list