From: Richard Smith Date: Thu, 20 Sep 2012 01:31:00 +0000 (+0000) Subject: Per C++11 [class.friend]p3, the 'friend' keyword must appear first in a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d6f80daa84164ceeb8900da07f43b6a150edf713;p=clang Per C++11 [class.friend]p3, the 'friend' keyword must appear first in a non-function friend declaration. Patch by Josh Magee! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164273 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h index 9a64f08dee..a5f736739b 100644 --- a/include/clang/AST/DeclFriend.h +++ b/include/clang/AST/DeclFriend.h @@ -104,7 +104,8 @@ public: /// Retrieves the source range for the friend declaration. SourceRange getSourceRange() const LLVM_READONLY { - /* FIXME: consider the case of templates wrt start of range. */ + // FIXME: If this is a friend function declaration, the 'friend' keyword + // might not be the first token of the declaration. if (NamedDecl *ND = getFriendDecl()) return SourceRange(getFriendLoc(), ND->getLocEnd()); else if (TypeSourceInfo *TInfo = getFriendType()) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 07a278e5fe..735221b7fc 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -807,6 +807,8 @@ def err_qualified_friend_def : Error< "friend function definition cannot be qualified with '%0'">; def err_friend_def_in_local_class : Error< "friend function cannot be defined in a local class">; +def err_friend_not_first_in_declaration : Error< + "'friend' must appear first in a non-function declaration">; def err_abstract_type_in_decl : Error< "%select{return|parameter|variable|field|ivar}0 type %1 is an abstract class">; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 8c10af9b13..4798b032df 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4336,7 +4336,7 @@ public: SourceLocation RParenLoc, bool Failed); - FriendDecl *CheckFriendTypeDecl(SourceLocation Loc, + FriendDecl *CheckFriendTypeDecl(SourceLocation LocStart, SourceLocation FriendLoc, TypeSourceInfo *TSInfo); Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a92f2d2340..e0c655f879 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -9850,7 +9850,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, /// \brief Perform semantic analysis of the given friend type declaration. /// /// \returns A friend declaration that. -FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc, +FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart, SourceLocation FriendLoc, TypeSourceInfo *TSInfo) { assert(TSInfo && "NULL TypeSourceInfo for friend type declaration"); @@ -9889,7 +9889,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc, diag::warn_cxx98_compat_nonclass_type_friend : diag::ext_nonclass_type_friend) << T - << SourceRange(FriendLoc, TypeRange.getEnd()); + << TypeRange; } } else if (T->getAs()) { Diag(FriendLoc, @@ -9897,18 +9897,22 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc, diag::warn_cxx98_compat_enum_friend : diag::ext_enum_friend) << T - << SourceRange(FriendLoc, TypeRange.getEnd()); + << TypeRange; } - // C++0x [class.friend]p3: + // C++11 [class.friend]p3: + // A friend declaration that does not declare a function shall have one + // of the following forms: + // friend elaborated-type-specifier ; + // friend simple-type-specifier ; + // friend typename-specifier ; + if (getLangOpts().CPlusPlus0x && LocStart != FriendLoc) + Diag(FriendLoc, diag::err_friend_not_first_in_declaration) << T; + // If the type specifier in a friend declaration designates a (possibly - // cv-qualified) class type, that class is declared as a friend; otherwise, + // 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, Loc, TSInfo, FriendLoc); + return FriendDecl::Create(Context, CurContext, LocStart, TSInfo, FriendLoc); } /// Handle a friend tag declaration where the scope specifier was diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 21ddd47363..8c1722fded 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -510,7 +510,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { if (!InstTy) return 0; - FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getLocation(), + FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getLocStart(), D->getFriendLoc(), InstTy); if (!FD) return 0; diff --git a/test/CXX/class.access/class.friend/p3-cxx0x.cpp b/test/CXX/class.access/class.friend/p3-cxx0x.cpp index 00fc0a33be..e4d5fd55b0 100644 --- a/test/CXX/class.access/class.friend/p3-cxx0x.cpp +++ b/test/CXX/class.access/class.friend/p3-cxx0x.cpp @@ -27,3 +27,29 @@ struct Y3 { X1 x1a; X1 x1b; X1 x1c; // expected-note{{in instantiation of template class 'X1' requested here}} + +template +class A { + T x; +public: + class foo {}; + static int y; +}; + +struct { + // Ill-formed + int friend; // expected-error {{'friend' must appear first in a non-function declaration}} + unsigned friend int; // expected-error {{'friend' must appear first in a non-function declaration}} + const volatile friend int; // expected-error {{'friend' must appear first in a non-function declaration}} + int + friend; // expected-error {{'friend' must appear first in a non-function declaration}} + + // OK + int friend foo(void); + friend int; + friend const volatile int; + friend + + float; + template friend class A::foo; +} a;