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 // for a TUK_Friend. 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/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)