diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-04-07 17:57:12 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-04-07 17:57:12 +0000 |
commit | 06245bfb3ae40bb24a8bfb17eafeb266a4daf5ca (patch) | |
tree | b54ded0e960a2b8df3e3c66a2b2dfabdddb2baa8 /lib/Sema | |
parent | 1d8693580133d6c783b9a56808e61f98005e0be1 (diff) |
Improve handling of friend types in several ways:
- When instantiating a friend type template, perform semantic
analysis on the resulting type.
- Downgrade the errors concerning friend type declarations that do
not refer to classes to ExtWarns in C++98/03. C++0x allows
practically any type to be befriended, and ignores the friend
declaration if the type is not a class.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100635 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 72 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 55 |
2 files changed, 63 insertions, 64 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 75dbb46d42..60b6220227 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5328,39 +5328,48 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc, QualType T = TSInfo->getType(); SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange(); - // C++03 [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. - if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) { - // If we evaluated the type to a record type, suggest putting - // a tag in front. - if (const RecordType *RT = T->getAs<RecordType>()) { - RecordDecl *RD = RT->getDecl(); - - std::string InsertionText = std::string(" ") + RD->getKindName(); - - Diag(FriendLoc, diag::err_unelaborated_friend_type) - << (unsigned) RD->getTagKind() + if (!getLangOptions().CPlusPlus0x) { + // C++03 [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. + if (!ActiveTemplateInstantiations.empty()) { + // Do not complain about the form of friend template types during + // template instantiation; we will already have complained when the + // template was declared. + } else if (!T->isElaboratedTypeSpecifier()) { + // If we evaluated the type to a record type, suggest putting + // a tag in front. + if (const RecordType *RT = T->getAs<RecordType>()) { + RecordDecl *RD = RT->getDecl(); + + std::string InsertionText = std::string(" ") + RD->getKindName(); + + Diag(TypeRange.getBegin(), diag::ext_unelaborated_friend_type) + << (unsigned) RD->getTagKind() + << T + << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc), + InsertionText); + } else { + Diag(FriendLoc, diag::ext_nonclass_type_friend) + << T + << SourceRange(FriendLoc, TypeRange.getEnd()); + } + } else if (T->getAs<EnumType>()) { + Diag(FriendLoc, diag::ext_enum_friend) << T - << SourceRange(FriendLoc) - << FixItHint::CreateInsertion(TypeRange.getBegin(), - InsertionText); - return 0; - } else { - Diag(FriendLoc, diag::err_unexpected_friend) << SourceRange(FriendLoc, TypeRange.getEnd()); - return 0; } } - // Enum types cannot be friends. - if (T->getAs<EnumType>()) { - Diag(FriendLoc, diag::err_enum_friend) - << SourceRange(FriendLoc, TypeRange.getEnd()); - return 0; - } + // C++0x [class.friend]p3: + // If the type specifier in a friend declaration designates a (possibly + // cv-qualified) class type, that class is declared as a friend; otherwise, + // the friend declaration is ignored. + + // FIXME: C++0x has some syntactic restrictions on friend type declarations + // in [class.friend]p3 that we do not implement. return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, FriendLoc); } @@ -5421,13 +5430,6 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, return DeclPtrTy(); } - // Enum templates cannot be friends. - if (TempParams.size() && T->getAs<EnumType>()) { - Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend) - << SourceRange(DS.getFriendSpecLoc()); - return DeclPtrTy(); - } - // C++98 [class.friend]p1: A friend of a class is a function // or class that is not a member of the class . . . // This is fixed in DR77, which just barely didn't make the C++03 diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 3375ccc0eb..69f183c706 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -476,47 +476,44 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { } Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { - FriendDecl::FriendUnion FU; - // Handle friend type expressions by simply substituting template - // parameters into the pattern type. + // parameters into the pattern type and checking the result. if (TypeSourceInfo *Ty = D->getFriendType()) { TypeSourceInfo *InstTy = SemaRef.SubstType(Ty, TemplateArgs, D->getLocation(), DeclarationName()); - if (!InstTy) return 0; + if (!InstTy) + return 0; - // This assertion is valid because the source type was necessarily - // an elaborated-type-specifier with a record tag. - assert(getLangOptions().CPlusPlus0x || InstTy->getType()->isRecordType()); + FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy); + if (!FD) + return 0; + + FD->setAccess(AS_public); + Owner->addDecl(FD); + return FD; + } + + NamedDecl *ND = D->getFriendDecl(); + assert(ND && "friend decl must be a decl or a type!"); - FU = InstTy; + // FIXME: We have a problem here, because the nested call to Visit(ND) + // will inject the thing that the friend references into the current + // owner, which is wrong. + Decl *NewND; - // Handle everything else by appropriate substitution. + // Hack to make this work almost well pending a rewrite. + if (D->wasSpecialization()) { + // Totally egregious hack to work around PR5866 + return 0; } else { - NamedDecl *ND = D->getFriendDecl(); - assert(ND && "friend decl must be a decl or a type!"); - - // FIXME: We have a problem here, because the nested call to Visit(ND) - // will inject the thing that the friend references into the current - // owner, which is wrong. - Decl *NewND; - - // Hack to make this work almost well pending a rewrite. - if (D->wasSpecialization()) { - // Totally egregious hack to work around PR5866 - return 0; - } else { - NewND = Visit(ND); - } - if (!NewND) return 0; - - FU = cast<NamedDecl>(NewND); + NewND = Visit(ND); } + if (!NewND) return 0; FriendDecl *FD = - FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU, - D->getFriendLoc()); + FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), + cast<NamedDecl>(NewND), D->getFriendLoc()); FD->setAccess(AS_public); Owner->addDecl(FD); return FD; |