diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-04-22 02:13:50 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-04-22 02:13:50 +0000 |
commit | e85e1766005ef4510d388f99e5084259b327c594 (patch) | |
tree | d6b2054462681d218d3e7f8c465e28e15753cefb /clang | |
parent | 4304101fb2991826b13cfd68a5d9798595906d04 (diff) | |
download | bcm5719-llvm-e85e1766005ef4510d388f99e5084259b327c594.tar.gz bcm5719-llvm-e85e1766005ef4510d388f99e5084259b327c594.zip |
PR12585: When processing a friend template inside a class template, don't
pretend there was no previous declaration -- that can lead us to injecting
a class template (with no access specifier) into a class scope. Instead,
just avoid the problematic checks.
llvm-svn: 155303
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 27 | ||||
-rw-r--r-- | clang/test/PCH/cxx-friends.cpp | 8 | ||||
-rw-r--r-- | clang/test/PCH/cxx-friends.h | 12 | ||||
-rw-r--r-- | clang/test/SemaTemplate/friend-template.cpp | 35 |
5 files changed, 69 insertions, 15 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 007869c4374..113a8fc3e54 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3658,6 +3658,8 @@ def err_member_def_undefined_record : Error< "out-of-line definition of %0 from class %1 without definition">; def err_member_def_does_not_match : Error< "out-of-line definition of %0 does not match any declaration in %1">; +def err_friend_decl_does_not_match : Error< + "friend declaration of %0 does not match any declaration in %1">; def err_member_def_does_not_match_suggest : Error< "out-of-line definition of %0 does not match any declaration in %1; " "did you mean %2?">; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f1581e0c349..d4b09753d30 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -969,20 +969,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, PrevDecl = (*Previous.begin())->getUnderlyingDecl(); } } - - if (CurContext->isDependentContext() && PrevClassTemplate) { - // If this is a dependent context, we don't want to link the friend - // class template to the template in scope, because that would perform - // checking of the template parameter lists that can't be performed - // until the outer context is instantiated. - PrevDecl = PrevClassTemplate = 0; - } } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S)) PrevDecl = PrevClassTemplate = 0; if (PrevClassTemplate) { - // Ensure that the template parameter lists are compatible. - if (!TemplateParameterListsAreEqual(TemplateParams, + // Ensure that the template parameter lists are compatible. Skip this check + // for a friend in a dependent context: the template parameter list itself + // could be dependent. + if (!(TUK == TUK_Friend && CurContext->isDependentContext()) && + !TemplateParameterListsAreEqual(TemplateParams, PrevClassTemplate->getTemplateParameters(), /*Complain=*/true, TPL_TemplateMatch)) @@ -1031,8 +1026,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // Check the template parameter list of this declaration, possibly // merging in the template parameter list from the previous class - // template declaration. - if (CheckTemplateParameterList(TemplateParams, + // template declaration. Skip this check for a friend in a dependent + // context, because the template parameter list might be dependent. + if (!(TUK == TUK_Friend && CurContext->isDependentContext()) && + CheckTemplateParameterList(TemplateParams, PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0, (SS.isSet() && SemanticContext && SemanticContext->isRecord() && @@ -1044,9 +1041,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (SS.isSet()) { // If the name of the template was qualified, we must be defining the // template out-of-line. - if (!SS.isInvalid() && !Invalid && !PrevClassTemplate && - !(TUK == TUK_Friend && CurContext->isDependentContext())) { - Diag(NameLoc, diag::err_member_def_does_not_match) + if (!SS.isInvalid() && !Invalid && !PrevClassTemplate) { + Diag(NameLoc, TUK == TUK_Friend ? diag::err_friend_decl_does_not_match + : diag::err_member_def_does_not_match) << Name << SemanticContext << SS.getRange(); Invalid = true; } diff --git a/clang/test/PCH/cxx-friends.cpp b/clang/test/PCH/cxx-friends.cpp index a8d75586e43..bdba42bbcb5 100644 --- a/clang/test/PCH/cxx-friends.cpp +++ b/clang/test/PCH/cxx-friends.cpp @@ -11,3 +11,11 @@ class F { a->x = 0; } }; + +template<typename T> class PR12585::future_base::setter { +public: + int f() { + return promise<T*>().k; + } +}; +int k = PR12585::future_base::setter<int>().f(); diff --git a/clang/test/PCH/cxx-friends.h b/clang/test/PCH/cxx-friends.h index 2a33f15a532..05dcc960663 100644 --- a/clang/test/PCH/cxx-friends.h +++ b/clang/test/PCH/cxx-friends.h @@ -4,3 +4,15 @@ class A { int x; friend class F; }; + +namespace PR12585 { + struct future_base { + template<typename> class setter; + }; + template<typename> class promise { + // We used to inject this into future_base with no access specifier, + // then crash during AST writing. + template<typename> friend class future_base::setter; + int k; + }; +} diff --git a/clang/test/SemaTemplate/friend-template.cpp b/clang/test/SemaTemplate/friend-template.cpp index 2b05527cf17..9acbfdcea29 100644 --- a/clang/test/SemaTemplate/friend-template.cpp +++ b/clang/test/SemaTemplate/friend-template.cpp @@ -267,3 +267,38 @@ namespace PR12557 { Bar<int> b; } + +namespace PR12585 { + struct A { }; + template<typename> struct B { + template<typename> friend class A::does_not_exist; // \ + // expected-error {{friend declaration of 'does_not_exist' does not match any declaration in 'PR12585::A'}} + }; + + struct C { + template<typename> struct D; + }; + template<typename> class E { + int n; + template<typename> friend struct C::D; + }; + template<typename T> struct C::D { + int f() { + return E<int>().n; + } + }; + int n = C::D<void*>().f(); + + struct F { + template<int> struct G; + }; + template<typename T> struct H { + // FIXME: As with cases above, the note here is on an unhelpful declaration, + // and should point to the declaration of G within F. + template<T> friend struct F::G; // \ + // expected-error {{different type 'char' in template redeclaration}} \ + // expected-note {{previous}} + }; + H<int> h1; // ok + H<char> h2; // expected-note {{instantiation}} +} |