Skip to content

Commit

Permalink
Diagnose invalid cv-qualifiers for friend decls.
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D45712

llvm-svn: 338931
  • Loading branch information
Eli Friedman committed Aug 3, 2018
1 parent 3c869cb commit 7499610
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 20 deletions.
23 changes: 23 additions & 0 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
15 changes: 13 additions & 2 deletions clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 0 additions & 18 deletions clang/test/Modules/odr_hash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 7499610

Please sign in to comment.