diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticParseKinds.td | 2 | ||||
-rw-r--r-- | clang/lib/Sema/DeclSpec.cpp | 31 | ||||
-rw-r--r-- | clang/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp | 4 | ||||
-rw-r--r-- | clang/test/CXX/drs/dr4xx.cpp | 6 | ||||
-rw-r--r-- | clang/www/cxx_dr_status.html | 2 |
5 files changed, 38 insertions, 7 deletions
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 6cb7a55db43..335b6abf134 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -69,7 +69,7 @@ def err_invalid_short_spec : Error<"'short %0' is invalid">; def err_invalid_long_spec : Error<"'long %0' is invalid">; def err_invalid_longlong_spec : Error<"'long long %0' is invalid">; def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">; -def err_friend_storage_spec : Error<"'%0' is invalid in friend declarations">; +def err_friend_decl_spec : Error<"'%0' is invalid in friend declarations">; def ext_ident_list_in_param : Extension< "type-less parameter names in function declaration">; diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 5c2006f6e93..69415ce34df 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -1125,14 +1125,41 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP, const PrintingPoli ThreadHint = FixItHint::CreateRemoval(SCLoc); } - Diag(D, SCLoc, diag::err_friend_storage_spec) + Diag(D, SCLoc, diag::err_friend_decl_spec) << SpecName << StorageHint << ThreadHint; ClearStorageClassSpecs(); } + // C++11 [dcl.fct.spec]p5: + // The virtual specifier shall be used only in the initial + // declaration of a non-static class member function; + // C++11 [dcl.fct.spec]p6: + // The explicit specifier shall be used only in the declaration of + // a constructor or conversion function within its class + // definition; + if (isFriendSpecified() && (isVirtualSpecified() || isExplicitSpecified())) { + StringRef Keyword; + SourceLocation SCLoc; + + if (isVirtualSpecified()) { + Keyword = "virtual"; + SCLoc = getVirtualSpecLoc(); + } else { + Keyword = "explicit"; + SCLoc = getExplicitSpecLoc(); + } + + FixItHint Hint = FixItHint::CreateRemoval(SCLoc); + Diag(D, SCLoc, diag::err_friend_decl_spec) + << Keyword << Hint; + + FS_virtual_specified = FS_explicit_specified = false; + FS_virtualLoc = FS_explicitLoc = SourceLocation(); + } + assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType)); - + // Okay, now we can infer the real type. // TODO: return "auto function" and other bad things based on the real type. diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp index ee870d96016..5d1e6fb85ce 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp @@ -14,3 +14,7 @@ public: explicit A::A() { } // expected-error {{'explicit' can only be specified inside the class definition}} explicit A::operator bool() { return false; } // expected-warning {{explicit conversion functions are a C++11 extension}}\ // expected-error {{'explicit' can only be specified inside the class definition}} + +class B { + friend explicit A::A(); // expected-error {{'explicit' is invalid in friend declarations}} +}; diff --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp index de85aea1c9d..726c67e2da0 100644 --- a/clang/test/CXX/drs/dr4xx.cpp +++ b/clang/test/CXX/drs/dr4xx.cpp @@ -844,14 +844,14 @@ namespace dr474 { // dr474: yes // dr475 FIXME write a codegen test -namespace dr477 { // dr477: no +namespace dr477 { // dr477: 3.5 struct A { explicit A(); virtual void f(); }; struct B { - friend explicit A::A(); // FIXME: reject this - friend virtual void A::f(); // FIXME: reject this + friend explicit A::A(); // expected-error {{'explicit' is invalid in friend declarations}} + friend virtual void A::f(); // expected-error {{'virtual' is invalid in friend declarations}} }; explicit A::A() {} // expected-error {{can only be specified inside the class definition}} virtual void A::f() {} // expected-error {{can only be specified inside the class definition}} diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 1ada70c7022..dc6339982c8 100644 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -2903,7 +2903,7 @@ of class templates</td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#477">477</a></td> <td>CD1</td> <td>Can <TT>virtual</TT> appear in a <TT>friend</TT> declaration?</td> - <td class="none" align="center">No</td> + <td class="svn" align="center">SVN</td> </tr> <tr id="478"> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#478">478</a></td> |