From 3b4abb67921126aefbf67d15bd6cdb7aa7cf47ff Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 7 Apr 2010 17:57:12 +0000 Subject: 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. llvm-svn: 100635 --- clang/lib/Sema/SemaDeclCXX.cpp | 72 ++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 35 deletions(-) (limited to 'clang/lib/Sema/SemaDeclCXX.cpp') diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 75dbb46d423..60b62202278 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/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()) { - 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()) { + 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()) { + 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()) { - 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()) { - 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 -- cgit v1.2.3