diff options
author | John McCall <rjmccall@apple.com> | 2009-08-11 21:13:21 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-08-11 21:13:21 +0000 |
commit | c48fbdfb83a5e50fed693f0bdda3396e5b67051d (patch) | |
tree | 0733e013e1f2e7eb3a4788633ada2beda5d74bbc /lib/Sema/SemaDeclCXX.cpp | |
parent | bab8a8ee632f0f62b67709a57e2b7ca165205020 (diff) |
Add a FriendClassDecl type for holding declarations of friend types in
the AST, and create such declarations.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78719 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 138 |
1 files changed, 84 insertions, 54 deletions
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. |