From: Douglas Gregor Date: Thu, 20 Oct 2011 15:58:54 +0000 (+0000) Subject: When we parse something that looks like a templated friend tag but X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ba4ee9a9b6e4cffc12bb6b395a58b89c189bb07e;p=clang When we parse something that looks like a templated friend tag but actually just has an extraneous 'template<>' header, strip off the 'template<>' header and treat it as a normal friend tag. Fixes PR10660 / . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142587 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 951ea9ccfd..bb867ed33e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -9746,8 +9746,6 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, if (Invalid) return 0; - assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?"); - bool isAllExplicitSpecializations = true; for (unsigned I = TempParamLists.size(); I-- > 0; ) { if (TempParamLists.get()[I]->size()) { @@ -9762,6 +9760,18 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, // about the template header and build an appropriate non-templated // friend. TODO: for source fidelity, remember the headers. if (isAllExplicitSpecializations) { + if (SS.isEmpty()) { + bool Owned = false; + bool IsDependent = false; + return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, + Attr, AS_public, + /*ModulePrivateLoc=*/SourceLocation(), + MultiTemplateParamsArg(), Owned, IsDependent, + /*ScopedEnum=*/false, + /*ScopedEnumUsesClassTag=*/false, + /*UnderlyingType=*/TypeResult()); + } + NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); ElaboratedTypeKeyword Keyword = TypeWithKeyword::getKeywordForTagTypeKind(Kind); @@ -9789,6 +9799,10 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, CurContext->addDecl(Friend); return Friend; } + + assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?"); + + // Handle the case of a templated-scope friend class. e.g. // template class A::B; diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp index d1284de35f..152df37d3d 100644 --- a/test/SemaTemplate/friend-template.cpp +++ b/test/SemaTemplate/friend-template.cpp @@ -224,3 +224,9 @@ namespace friend_type_template_no_tag { }; template struct S; } + +namespace PR10660 { + struct A { + template <> friend class B; // expected-error{{extraneous 'template<>' in declaration of class 'B'}} + }; +}