From: Eli Friedman Date: Fri, 3 Aug 2018 22:09:44 +0000 (+0000) Subject: Diagnose invalid cv-qualifiers for friend decls. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6c542b52ff1756169b286d50ed7c35628fe2e49a;p=clang Diagnose invalid cv-qualifiers for friend decls. Differential Revision: https://reviews.llvm.org/D45712 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@338931 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 4cf3abdf57..f119a6ef04 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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. diff --git a/test/CXX/class.access/class.friend/p3-cxx0x.cpp b/test/CXX/class.access/class.friend/p3-cxx0x.cpp index 5a1ab49321..9aabdbe540 100644 --- a/test/CXX/class.access/class.friend/p3-cxx0x.cpp +++ b/test/CXX/class.access/class.friend/p3-cxx0x.cpp @@ -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 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; diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp index 16ddfefa53..117029405e 100644 --- a/test/Modules/odr_hash.cpp +++ b/test/Modules/odr_hash.cpp @@ -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)