]> granicus.if.org Git - clang/commitdiff
Add a FriendClassDecl type for holding declarations of friend types in
authorJohn McCall <rjmccall@apple.com>
Tue, 11 Aug 2009 21:13:21 +0000 (21:13 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 11 Aug 2009 21:13:21 +0000 (21:13 +0000)
the AST, and create such declarations.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78719 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclCXX.h
include/clang/AST/DeclNodes.def
lib/AST/DeclBase.cpp
lib/AST/DeclCXX.cpp
lib/Sema/SemaDeclCXX.cpp

index 4ca9a8222e657e2be705eff4df6de21d80faac81..ff498ba4a404dd226427af9f57072ea6463f8d1f 100644 (file)
@@ -1273,6 +1273,42 @@ public:
   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();
 ///
index 8d5c0681d78c08e00ee61cc19c32955319fb63fe..0cf092ffbabb4b4e940265007a896c71d69c9193 100644 (file)
@@ -125,6 +125,7 @@ DECL(ObjCPropertyImpl, Decl)
 DECL(ObjCForwardProtocol, Decl)
 DECL(ObjCClass, Decl)
 DECL(FileScopeAsm, Decl)
+DECL(FriendClass, Decl)
 DECL(StaticAssert, Decl)
 LAST_DECL(Block, Decl)
 
index 0f7c4dcc0d69d31433c10174193e1513f069b4e7..8296f2931b8a766b16c3cbd848bf8af24c758286 100644 (file)
@@ -199,6 +199,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
     case ObjCCompatibleAlias:
       return IDNS_Ordinary;
 
+    case FriendClass:
     case FriendFunction:
       return IDNS_Friend;
       
index 87a557d4df1467c9907bc1bc509c0642ffd013c0..e9ae7e77f04dc9d9082f75670dda10eb51bc7a56 100644 (file)
@@ -743,14 +743,20 @@ bool OverloadIterator::Equals(const OverloadIterator &Other) const {
   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, 
index a4005bae3438e9f056d493d27310aad25a35f905..0affe512b3e365db6ad3ff0d747d22d97f0c5686 100644 (file)
@@ -3320,68 +3320,98 @@ Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
   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;
+    QualType T;
+    DeclContext *DC;
 
-    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);
+    // 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.