diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 67097a5774ea..be9ea674d0da 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -333,6 +333,7 @@ def UnknownAttributes : DiagGroup<"attributes">; def IgnoredAttributes : DiagGroup<"ignored-attributes">; def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args", [CXX98CompatUnnamedTypeTemplateArgs]>; +def UnsupportedFriend : DiagGroup<"unsupported-friend">; def UnusedArgument : DiagGroup<"unused-argument">; def UnusedSanitizeArgument : DiagGroup<"unused-sanitize-argument">; def UnusedCommandLineArgument : DiagGroup<"unused-command-line-argument", diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5f26a0013d64..dba3ca165274 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -914,6 +914,14 @@ def err_friend_not_first_in_declaration : Error< "'friend' must appear first in a non-function declaration">; def err_using_decl_friend : Error< "cannot befriend target of using declaration">; +def warn_template_qualified_friend_unsupported : Warning< + "dependent nested name specifier '%0' for friend class declaration is " + "not supported; turning off access control for %1">, + InGroup; +def warn_template_qualified_friend_ignored : Warning< + "dependent nested name specifier '%0' for friend template declaration is " + "not supported; ignoring this friend declaration">, + InGroup; def err_invalid_member_in_interface : Error< "%select{data member |non-public member function |static member function |" diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 8b04f8dfcf52..660641eec6ca 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11410,6 +11410,8 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, // Handle the case of a templated-scope friend class. e.g. // template class A::B; // FIXME: we don't support these right now. + Diag(NameLoc, diag::warn_template_qualified_friend_unsupported) + << SS.getScopeRep() << SS.getRange() << cast(CurContext); ElaboratedTypeKeyword ETK = TypeWithKeyword::getKeywordForTagTypeKind(Kind); QualType T = Context.getDependentNameType(ETK, SS.getScopeRep(), Name); TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 795774657c70..6d40e00b21a7 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -877,10 +877,11 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // FIXME: Horrible, horrible hack! We can't currently represent this // in the AST, and historically we have just ignored such friend // class templates, so don't complain here. - if (TUK != TUK_Friend) - Diag(NameLoc, diag::err_template_qualified_declarator_no_match) + Diag(NameLoc, TUK == TUK_Friend + ? diag::warn_template_qualified_friend_ignored + : diag::err_template_qualified_declarator_no_match) << SS.getScopeRep() << SS.getRange(); - return true; + return TUK != TUK_Friend; } if (RequireCompleteDeclContext(SS, SemanticContext)) diff --git a/clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp b/clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp index ea9d2ce697c5..5a1ab49321d0 100644 --- a/clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp +++ b/clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp @@ -36,10 +36,17 @@ class A { public: class foo {}; static int y; - template friend class B::ty; + template friend class B::ty; // expected-warning {{dependent nested name specifier 'B::' for friend class declaration is not supported}} }; -template class B { typedef int ty; }; +template class B { typedef int ty; }; + +template<> class B { + class ty { + static int f(A &a) { return a.y; } // ok, befriended + }; +}; +int f(A &a) { return a.y; } // FIXME: should be an error struct { // Ill-formed @@ -56,7 +63,7 @@ struct { friend float; - template friend class A::foo; + template friend class A::foo; // expected-warning {{not supported}} } a; void testA() { (void)sizeof(A); } diff --git a/clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp b/clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp index 77f071d52e67..b26abb64f838 100644 --- a/clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics namespace test0 { template class A { @@ -7,7 +6,8 @@ namespace test0 { }; class B { - template friend class A::Member; + template friend class A::Member; // expected-warning {{not supported}} + int n; }; A a; @@ -68,7 +68,7 @@ namespace test3 { template class C { int i; - template friend struct A::Inner; + template friend struct A::Inner; // expected-warning {{not supported}} }; template int A::Inner::foo() { diff --git a/clang/test/SemaTemplate/friend-template.cpp b/clang/test/SemaTemplate/friend-template.cpp index 8a478777eb7e..e9b2b9b8e64e 100644 --- a/clang/test/SemaTemplate/friend-template.cpp +++ b/clang/test/SemaTemplate/friend-template.cpp @@ -232,16 +232,23 @@ namespace PR10660 { } namespace rdar11147355 { - template + template struct A { template class B; - template template friend class A::B; + template template friend class A::B; // expected-warning {{dependent nested name specifier 'A::' for friend template declaration is not supported; ignoring this friend declaration}} + private: + int n; // expected-note {{here}} }; - + template template class A::B { - }; - + public: + // FIXME: This should be permitted. + int f(A a) { return a.n; } // expected-error {{private}} + }; + A::B ab; + A a; + int k = ab.f(a); // expected-note {{instantiation of}} } namespace RedeclUnrelated {