[PATCH] D45712: Diagnose invalid cv-qualifiers for friend decls.
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.
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.
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.
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.
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.
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.
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