diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 36 | ||||
-rw-r--r-- | include/clang/AST/DeclNodes.def | 1 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 1 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 138 |
5 files changed, 130 insertions, 56 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 4ca9a8222e..ff498ba4a4 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -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(); /// diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def index 8d5c0681d7..0cf092ffba 100644 --- a/include/clang/AST/DeclNodes.def +++ b/include/clang/AST/DeclNodes.def @@ -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) diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 0f7c4dcc0d..8296f2931b 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -199,6 +199,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCCompatibleAlias: return IDNS_Ordinary; + case FriendClass: case FriendFunction: return IDNS_Friend; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 87a557d4df..e9ae7e77f0 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -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, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a4005bae34..0affe512b3 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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. |