Index: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td @@ -69,7 +69,7 @@ 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">; Index: cfe/trunk/lib/Sema/DeclSpec.cpp =================================================================== --- cfe/trunk/lib/Sema/DeclSpec.cpp +++ cfe/trunk/lib/Sema/DeclSpec.cpp @@ -1125,14 +1125,41 @@ 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. Index: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp =================================================================== --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp @@ -14,3 +14,7 @@ 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}} +}; Index: cfe/trunk/test/CXX/drs/dr4xx.cpp =================================================================== --- cfe/trunk/test/CXX/drs/dr4xx.cpp +++ cfe/trunk/test/CXX/drs/dr4xx.cpp @@ -844,14 +844,14 @@ // 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}} Index: cfe/trunk/www/cxx_dr_status.html =================================================================== --- cfe/trunk/www/cxx_dr_status.html +++ cfe/trunk/www/cxx_dr_status.html @@ -2903,7 +2903,7 @@ 477 CD1 Can virtual appear in a friend declaration? - No + SVN 478