Redirect templated friend class decls to a new Sema callback and
construct an unsupported friend when there's a friend with a templated scope specifier. Fixes a consistency crash, rdar://problem/8540527 llvm-svn: 116786
This commit is contained in:
parent
898fbd82a5
commit
ace48cd872
|
@ -799,6 +799,13 @@ public:
|
|||
bool &OwnedDecl, bool &IsDependent, bool ScopedEnum,
|
||||
TypeResult UnderlyingType);
|
||||
|
||||
Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
|
||||
unsigned TagSpec, SourceLocation TagLoc,
|
||||
CXXScopeSpec &SS,
|
||||
IdentifierInfo *Name, SourceLocation NameLoc,
|
||||
AttributeList *Attr,
|
||||
MultiTemplateParamsArg TempParamLists);
|
||||
|
||||
TypeResult ActOnDependentTag(Scope *S,
|
||||
unsigned TagSpec,
|
||||
TagUseKind TUK,
|
||||
|
|
|
@ -947,6 +947,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
TemplateInfo.TemplateLoc,
|
||||
TagType, StartLoc, SS, Name,
|
||||
NameLoc, AttrList);
|
||||
} else if (TUK == Sema::TUK_Friend &&
|
||||
TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) {
|
||||
TagOrTempResult =
|
||||
Actions.ActOnTemplatedFriendTag(getCurScope(), DS.getFriendSpecLoc(),
|
||||
TagType, StartLoc, SS,
|
||||
Name, NameLoc, AttrList,
|
||||
MultiTemplateParamsArg(Actions,
|
||||
TemplateParams? &(*TemplateParams)[0] : 0,
|
||||
TemplateParams? TemplateParams->size() : 0));
|
||||
} else {
|
||||
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
|
||||
TUK == Sema::TUK_Definition) {
|
||||
|
@ -956,8 +965,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
bool IsDependent = false;
|
||||
|
||||
// Declaration or definition of a class type
|
||||
TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, SS,
|
||||
Name, NameLoc, AttrList, AS,
|
||||
TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc,
|
||||
SS, Name, NameLoc, AttrList, AS,
|
||||
MultiTemplateParamsArg(Actions,
|
||||
TemplateParams? &(*TemplateParams)[0] : 0,
|
||||
TemplateParams? TemplateParams->size() : 0),
|
||||
|
@ -966,9 +975,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
|
||||
// If ActOnTag said the type was dependent, try again with the
|
||||
// less common call.
|
||||
if (IsDependent)
|
||||
if (IsDependent) {
|
||||
assert(TUK == Sema::TUK_Reference || TUK == Sema::TUK_Friend);
|
||||
TypeResult = Actions.ActOnDependentTag(getCurScope(), TagType, TUK,
|
||||
SS, Name, StartLoc, NameLoc);
|
||||
}
|
||||
}
|
||||
|
||||
// If there is a body, parse it and inform the actions module.
|
||||
|
|
|
@ -1623,9 +1623,9 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
|
|||
}
|
||||
|
||||
if (DS.isFriendSpecified()) {
|
||||
// If we're dealing with a class template decl, assume that the
|
||||
// template routines are handling it.
|
||||
if (TagD && isa<ClassTemplateDecl>(TagD))
|
||||
// If we're dealing with a decl but not a TagDecl, assume that
|
||||
// whatever routines created it handled the friendship aspect.
|
||||
if (TagD && !Tag)
|
||||
return 0;
|
||||
return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0));
|
||||
}
|
||||
|
@ -2797,8 +2797,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
= MatchTemplateParametersToScopeSpecifier(
|
||||
D.getDeclSpec().getSourceRange().getBegin(),
|
||||
D.getCXXScopeSpec(),
|
||||
(TemplateParameterList**)TemplateParamLists.get(),
|
||||
TemplateParamLists.size(),
|
||||
TemplateParamLists.get(),
|
||||
TemplateParamLists.size(),
|
||||
/*never a friend*/ false,
|
||||
isExplicitSpecialization,
|
||||
Invalid)) {
|
||||
|
@ -2836,7 +2836,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) {
|
||||
NewVD->setTemplateParameterListsInfo(Context,
|
||||
NumMatchedTemplateParamLists,
|
||||
(TemplateParameterList**)TemplateParamLists.release());
|
||||
TemplateParamLists.release());
|
||||
}
|
||||
|
||||
if (D.getDeclSpec().isThreadSpecified()) {
|
||||
|
@ -5483,6 +5483,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
// If this is not a definition, it must have a name.
|
||||
assert((Name != 0 || TUK == TUK_Definition) &&
|
||||
"Nameless record must be a definition!");
|
||||
assert(TemplateParameterLists.size() == 0 || TUK != TUK_Reference);
|
||||
|
||||
OwnedDecl = false;
|
||||
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
|
||||
|
@ -5491,7 +5492,12 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
bool isExplicitSpecialization = false;
|
||||
unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size();
|
||||
bool Invalid = false;
|
||||
if (TUK != TUK_Reference) {
|
||||
|
||||
// We only need to do this matching if we have template parameters
|
||||
// or a scope specifier, which also conveniently avoids this work
|
||||
// for non-C++ cases.
|
||||
if (NumMatchedTemplateParamLists ||
|
||||
(SS.isNotEmpty() && TUK != TUK_Reference)) {
|
||||
if (TemplateParameterList *TemplateParams
|
||||
= MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
|
||||
TemplateParameterLists.get(),
|
||||
|
@ -5606,7 +5612,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
// and that current instantiation has any dependent base
|
||||
// classes, we might find something at instantiation time: treat
|
||||
// this as a dependent elaborated-type-specifier.
|
||||
if (Previous.wasNotFoundInCurrentInstantiation()) {
|
||||
// But this only makes any sense for reference-like lookups.
|
||||
if (Previous.wasNotFoundInCurrentInstantiation() &&
|
||||
(TUK == TUK_Reference || TUK == TUK_Friend)) {
|
||||
IsDependent = true;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6244,6 +6244,110 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc,
|
|||
return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, FriendLoc);
|
||||
}
|
||||
|
||||
/// Handle a friend tag declaration where the scope specifier was
|
||||
/// templated.
|
||||
Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
|
||||
unsigned TagSpec, SourceLocation TagLoc,
|
||||
CXXScopeSpec &SS,
|
||||
IdentifierInfo *Name, SourceLocation NameLoc,
|
||||
AttributeList *Attr,
|
||||
MultiTemplateParamsArg TempParamLists) {
|
||||
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
|
||||
|
||||
bool isExplicitSpecialization = false;
|
||||
unsigned NumMatchedTemplateParamLists = TempParamLists.size();
|
||||
bool Invalid = false;
|
||||
|
||||
if (TemplateParameterList *TemplateParams
|
||||
= MatchTemplateParametersToScopeSpecifier(TagLoc, SS,
|
||||
TempParamLists.get(),
|
||||
TempParamLists.size(),
|
||||
/*friend*/ true,
|
||||
isExplicitSpecialization,
|
||||
Invalid)) {
|
||||
--NumMatchedTemplateParamLists;
|
||||
|
||||
if (TemplateParams->size() > 0) {
|
||||
// This is a declaration of a class template.
|
||||
if (Invalid)
|
||||
return 0;
|
||||
|
||||
return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc,
|
||||
SS, Name, NameLoc, Attr,
|
||||
TemplateParams, AS_public).take();
|
||||
} else {
|
||||
// The "template<>" header is extraneous.
|
||||
Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
|
||||
<< TypeWithKeyword::getTagTypeKindName(Kind) << Name;
|
||||
isExplicitSpecialization = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Invalid) return 0;
|
||||
|
||||
assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?");
|
||||
|
||||
bool isAllExplicitSpecializations = true;
|
||||
for (unsigned I = 0; I != NumMatchedTemplateParamLists; ++I) {
|
||||
if (TempParamLists.get()[I]->size()) {
|
||||
isAllExplicitSpecializations = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: don't ignore attributes.
|
||||
|
||||
// If it's explicit specializations all the way down, just forget
|
||||
// about the template header and build an appropriate non-templated
|
||||
// friend. TODO: for source fidelity, remember the headers.
|
||||
if (isAllExplicitSpecializations) {
|
||||
ElaboratedTypeKeyword Keyword
|
||||
= TypeWithKeyword::getKeywordForTagTypeKind(Kind);
|
||||
QualType T = CheckTypenameType(Keyword, SS.getScopeRep(), *Name,
|
||||
TagLoc, SS.getRange(), NameLoc);
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
|
||||
if (isa<DependentNameType>(T)) {
|
||||
DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
|
||||
TL.setKeywordLoc(TagLoc);
|
||||
TL.setQualifierRange(SS.getRange());
|
||||
TL.setNameLoc(NameLoc);
|
||||
} else {
|
||||
ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
|
||||
TL.setKeywordLoc(TagLoc);
|
||||
TL.setQualifierRange(SS.getRange());
|
||||
cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(NameLoc);
|
||||
}
|
||||
|
||||
FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc,
|
||||
TSI, FriendLoc);
|
||||
Friend->setAccess(AS_public);
|
||||
CurContext->addDecl(Friend);
|
||||
return Friend;
|
||||
}
|
||||
|
||||
// Handle the case of a templated-scope friend class. e.g.
|
||||
// template <class T> class A<T>::B;
|
||||
// FIXME: we don't support these right now.
|
||||
ElaboratedTypeKeyword ETK = TypeWithKeyword::getKeywordForTagTypeKind(Kind);
|
||||
QualType T = Context.getDependentNameType(ETK, SS.getScopeRep(), Name);
|
||||
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
|
||||
DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
|
||||
TL.setKeywordLoc(TagLoc);
|
||||
TL.setQualifierRange(SS.getRange());
|
||||
TL.setNameLoc(NameLoc);
|
||||
|
||||
FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc,
|
||||
TSI, FriendLoc);
|
||||
Friend->setAccess(AS_public);
|
||||
Friend->setUnsupportedFriend(true);
|
||||
CurContext->addDecl(Friend);
|
||||
return Friend;
|
||||
}
|
||||
|
||||
|
||||
/// Handle a friend type declaration. This works in tandem with
|
||||
/// ActOnTag.
|
||||
///
|
||||
|
|
|
@ -550,6 +550,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
|
|||
return 0;
|
||||
|
||||
FD->setAccess(AS_public);
|
||||
FD->setUnsupportedFriend(D->isUnsupportedFriend());
|
||||
Owner->addDecl(FD);
|
||||
return FD;
|
||||
}
|
||||
|
@ -568,6 +569,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
|
|||
FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
|
||||
cast<NamedDecl>(NewND), D->getFriendLoc());
|
||||
FD->setAccess(AS_public);
|
||||
FD->setUnsupportedFriend(D->isUnsupportedFriend());
|
||||
Owner->addDecl(FD);
|
||||
return FD;
|
||||
}
|
||||
|
|
|
@ -56,3 +56,25 @@ namespace test2 {
|
|||
void f() { C::foo(); }
|
||||
};
|
||||
}
|
||||
|
||||
// rdar://problem/8540527
|
||||
namespace test3 {
|
||||
template <class T> struct A {
|
||||
struct Inner {
|
||||
static int foo();
|
||||
};
|
||||
};
|
||||
|
||||
template <class U> class C {
|
||||
int i;
|
||||
template <class T> friend struct A<T>::Inner;
|
||||
};
|
||||
|
||||
template <class T> int A<T>::Inner::foo() {
|
||||
C<int> c;
|
||||
c.i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test = A<int>::Inner::foo();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue