]> granicus.if.org Git - clang/commitdiff
Per C++11 [class.friend]p3, the 'friend' keyword must appear first in a
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 20 Sep 2012 01:31:00 +0000 (01:31 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 20 Sep 2012 01:31:00 +0000 (01:31 +0000)
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

include/clang/AST/DeclFriend.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/class.access/class.friend/p3-cxx0x.cpp

index 9a64f08dee5038f362c69b6ddd8adc5c5090cda2..a5f736739b17b8f4b8414de1abb01a6274e7b89d 100644 (file)
@@ -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())
index 07a278e5fe7ba5ebab7c0feb7c13146ff73d86b6..735221b7fc9e38b0956a5c5eef22dd1eb21ac212 100644 (file)
@@ -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">;
index 8c10af9b1348f520b893e81bf3998db3d65fbe36..4798b032df44e85e38bfb0a5749ca49e15745c60 100644 (file)
@@ -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,
index a92f2d2340c2a37c0764eff650204ba33365492a..e0c655f879f386b62cddaaca191af92bb4441dad 100644 (file)
@@ -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<EnumType>()) {
     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
index 21ddd473636bc2d4a2be14c8582b8a859837ca85..8c1722fdedbc468fb623f2fe49ec6541fedd7cd5 100644 (file)
@@ -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;
index 00fc0a33bef28c8512dbc72a2ecc058e6a951704..e4d5fd55b0b64f95da4e09500a9042823089c69c 100644 (file)
@@ -27,3 +27,29 @@ struct Y3 {
 X1<Y2> x1a;
 X1<Y3> x1b;
 X1<Y1> x1c; // expected-note{{in instantiation of template class 'X1<Y1>' requested here}}
+
+template<typename T>
+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<typename T> friend class A<T>::foo;
+} a;