[PATCH] D45712: Diagnose invalid cv-qualifiers for friend decls.

2018-08-03 Thread Eli Friedman via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL338931: Diagnose invalid cv-qualifiers for friend decls. 
(authored by efriedma, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D45712?vs=154707&id=159103#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D45712

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

Index: cfe/trunk/test/Modules/odr_hash.cpp
===
--- cfe/trunk/test/Modules/odr_hash.cpp
+++ cfe/trunk/test/Modules/odr_hash.cpp
@@ -2244,22 +2244,6 @@
 #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 {
   friend T4;
@@ -2292,14 +2276,12 @@
   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)
Index: cfe/trunk/test/CXX/class.access/class.friend/p3-cxx0x.cpp
===
--- cfe/trunk/test/CXX/class.access/class.friend/p3-cxx0x.cpp
+++ cfe/trunk/test/CXX/class.access/class.friend/p3-cxx0x.cpp
@@ -52,14 +52,25 @@
   // 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  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: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
===
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp
@@ -14017,6 +14017,29 @@
   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
   // 

[PATCH] D45712: Diagnose invalid cv-qualifiers for friend decls.

2018-07-06 Thread Eli Friedman via Phabricator via cfe-commits
efriedma updated this revision to Diff 154471.
efriedma retitled this revision from "[WIP] Diagnose invalid cv-qualifiers for 
friend decls." to "Diagnose invalid cv-qualifiers for friend decls.".
efriedma edited the summary of this revision.
efriedma added a comment.

Updated to handle the template case.


Repository:
  rC Clang

https://reviews.llvm.org/D45712

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

Index: test/Modules/odr_hash.cpp
===
--- test/Modules/odr_hash.cpp
+++ test/Modules/odr_hash.cpp
@@ -2048,22 +2048,6 @@
 #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 {
   friend T4;
@@ -2096,14 +2080,12 @@
   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)
Index: test/CXX/class.access/class.friend/p3-cxx0x.cpp
===
--- test/CXX/class.access/class.friend/p3-cxx0x.cpp
+++ test/CXX/class.access/class.friend/p3-cxx0x.cpp
@@ -52,14 +52,25 @@
   // 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  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: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -14067,6 +14067,29 @@
 return nullptr;
   }
 
+  // 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";
+  }
+
   // 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
Index: lib/Parse/ParseDeclCXX.cpp
===
--- lib/Parse/ParseDeclCXX.c

[PATCH] D45712: Diagnose invalid cv-qualifiers for friend decls.

2018-07-07 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added a comment.

Can we avoid the duplication by putting this check in 
`Sema::ParsedFreeStandingDeclSpec` instead?


Repository:
  rC Clang

https://reviews.llvm.org/D45712



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45712: Diagnose invalid cv-qualifiers for friend decls.

2018-07-09 Thread Eli Friedman via Phabricator via cfe-commits
efriedma added a comment.

I thought the template case wasn't using the same codepath, but apparently I 
was just confusing myself.  The exact form "template  friend class 
Y;" triggers an early out in Sema::ActOnFriendTypeDecl, so my code wasn't 
getting hit. I'll revise accordingly.


Repository:
  rC Clang

https://reviews.llvm.org/D45712



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45712: Diagnose invalid cv-qualifiers for friend decls.

2018-07-09 Thread Eli Friedman via Phabricator via cfe-commits
efriedma updated this revision to Diff 154707.
efriedma edited the summary of this revision.
efriedma added a comment.

Move declspec checks before call to GetTypeForDeclarator, since it can fail for 
class templates.


Repository:
  rC Clang

https://reviews.llvm.org/D45712

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

Index: test/Modules/odr_hash.cpp
===
--- test/Modules/odr_hash.cpp
+++ test/Modules/odr_hash.cpp
@@ -2048,22 +2048,6 @@
 #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 {
   friend T4;
@@ -2096,14 +2080,12 @@
   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)
Index: test/CXX/class.access/class.friend/p3-cxx0x.cpp
===
--- test/CXX/class.access/class.friend/p3-cxx0x.cpp
+++ test/CXX/class.access/class.friend/p3-cxx0x.cpp
@@ -52,14 +52,25 @@
   // 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  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: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -14035,6 +14035,29 @@
   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.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45712: Diagnose invalid cv-qualifiers for friend decls.

2018-07-17 Thread Eli Friedman via Phabricator via cfe-commits
efriedma added a comment.

Ping


Repository:
  rC Clang

https://reviews.llvm.org/D45712



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45712: Diagnose invalid cv-qualifiers for friend decls.

2018-07-25 Thread Eli Friedman via Phabricator via cfe-commits
efriedma added a comment.
Herald added a subscriber: jfb.

Ping


Repository:
  rC Clang

https://reviews.llvm.org/D45712



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits