]> granicus.if.org Git - clang/commitdiff
Diagnose invalid cv-qualifiers for friend decls.
authorEli Friedman <efriedma@codeaurora.org>
Fri, 3 Aug 2018 22:09:44 +0000 (22:09 +0000)
committerEli Friedman <efriedma@codeaurora.org>
Fri, 3 Aug 2018 22:09:44 +0000 (22:09 +0000)
Differential Revision: https://reviews.llvm.org/D45712

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@338931 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaDeclCXX.cpp
test/CXX/class.access/class.friend/p3-cxx0x.cpp
test/Modules/odr_hash.cpp

index 4cf3abdf5745f0b13355ed394e4c306df5d63346..f119a6ef0423233d994c5ed815e181fe71a9cc75 100644 (file)
@@ -14017,6 +14017,29 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
   assert(DS.isFriendSpecified());
   assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
 
+  // C++ [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 ;
+  //
+  // Any declaration with a type qualifier does not have that form. (It's
+  // legal to specify a qualified type as a friend, you just can't write the
+  // keywords.)
+  if (DS.getTypeQualifiers()) {
+    if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+      Diag(DS.getConstSpecLoc(), diag::err_friend_decl_spec) << "const";
+    if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
+      Diag(DS.getVolatileSpecLoc(), diag::err_friend_decl_spec) << "volatile";
+    if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
+      Diag(DS.getRestrictSpecLoc(), diag::err_friend_decl_spec) << "restrict";
+    if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+      Diag(DS.getAtomicSpecLoc(), diag::err_friend_decl_spec) << "_Atomic";
+    if (DS.getTypeQualifiers() & DeclSpec::TQ_unaligned)
+      Diag(DS.getUnalignedSpecLoc(), diag::err_friend_decl_spec) << "__unaligned";
+  }
+
   // Try to convert the decl specifier to a type.  This works for
   // friend templates because ActOnTag never produces a ClassTemplateDecl
   // for a TUK_Friend.
index 5a1ab49321d099a65a9b04617d522e131fd9f785..9aabdbe540a661df2de6774a518d7f194fe76b01 100644 (file)
@@ -52,14 +52,25 @@ 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}}
+  const volatile friend int; // expected-error {{'friend' must appear first in a non-function declaration}} \
+                             // expected-error {{'const' is invalid in friend declarations}} \
+                             // expected-error {{'volatile' is invalid in friend declarations}}
   int
           friend; // expected-error {{'friend' must appear first in a non-function declaration}}
+  friend const int; // expected-error {{'const' is invalid in friend declarations}}
+  friend volatile int; // expected-error {{'volatile' is invalid in friend declarations}}
+  template <typename T> friend const class X; // expected-error {{'const' is invalid in friend declarations}}
+  // C++ doesn't have restrict and _Atomic, but they're both the same sort
+  // of qualifier.
+  typedef int *PtrToInt;
+  friend __restrict PtrToInt; // expected-error {{'restrict' is invalid in friend declarations}} \
+                              // expected-error {{restrict requires a pointer or reference}}
+  friend _Atomic int; // expected-error {{'_Atomic' is invalid in friend declarations}}
 
   // OK
   int friend foo(void);
+  const int friend foo2(void);
   friend int;
-  friend const volatile int;
       friend
 
   float;
index 16ddfefa53c795bf790d855d85f36857ddfac86d..117029405ea03fbd3845381a009cf2fb6d779269 100644 (file)
@@ -2243,22 +2243,6 @@ S2 s2;
 // expected-note@first.h:* {{but in 'FirstModule' found friend 'class T2'}}
 #endif
 
-#if defined(FIRST)
-struct T3 {};
-struct S3 {
-  friend const T3;
-};
-#elif defined(SECOND)
-struct T3 {};
-struct S3 {
-  friend T3;
-};
-#else
-S3 s3;
-// expected-error@second.h:* {{'Friend::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend 'Friend::T3'}}
-// expected-note@first.h:* {{but in 'FirstModule' found friend 'const Friend::T3'}}
-#endif
-
 #if defined(FIRST)
 struct T4 {};
 struct S4 {
@@ -2292,14 +2276,12 @@ S5 s5;
   friend class FriendA;  \
   friend struct FriendB; \
   friend FriendC;        \
-  friend const FriendD;  \
   friend void Function();
 
 #if defined(FIRST) || defined(SECOND)
 class FriendA {};
 class FriendB {};
 class FriendC {};
-class FriendD {};
 #endif
 
 #if defined(FIRST) || defined(SECOND)