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,
|
bool &OwnedDecl, bool &IsDependent, bool ScopedEnum,
|
||||||
TypeResult UnderlyingType);
|
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,
|
TypeResult ActOnDependentTag(Scope *S,
|
||||||
unsigned TagSpec,
|
unsigned TagSpec,
|
||||||
TagUseKind TUK,
|
TagUseKind TUK,
|
||||||
|
|
|
@ -947,6 +947,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
||||||
TemplateInfo.TemplateLoc,
|
TemplateInfo.TemplateLoc,
|
||||||
TagType, StartLoc, SS, Name,
|
TagType, StartLoc, SS, Name,
|
||||||
NameLoc, AttrList);
|
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 {
|
} else {
|
||||||
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
|
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
|
||||||
TUK == Sema::TUK_Definition) {
|
TUK == Sema::TUK_Definition) {
|
||||||
|
@ -956,8 +965,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
||||||
bool IsDependent = false;
|
bool IsDependent = false;
|
||||||
|
|
||||||
// Declaration or definition of a class type
|
// Declaration or definition of a class type
|
||||||
TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, SS,
|
TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc,
|
||||||
Name, NameLoc, AttrList, AS,
|
SS, Name, NameLoc, AttrList, AS,
|
||||||
MultiTemplateParamsArg(Actions,
|
MultiTemplateParamsArg(Actions,
|
||||||
TemplateParams? &(*TemplateParams)[0] : 0,
|
TemplateParams? &(*TemplateParams)[0] : 0,
|
||||||
TemplateParams? TemplateParams->size() : 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
|
// If ActOnTag said the type was dependent, try again with the
|
||||||
// less common call.
|
// less common call.
|
||||||
if (IsDependent)
|
if (IsDependent) {
|
||||||
|
assert(TUK == Sema::TUK_Reference || TUK == Sema::TUK_Friend);
|
||||||
TypeResult = Actions.ActOnDependentTag(getCurScope(), TagType, TUK,
|
TypeResult = Actions.ActOnDependentTag(getCurScope(), TagType, TUK,
|
||||||
SS, Name, StartLoc, NameLoc);
|
SS, Name, StartLoc, NameLoc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is a body, parse it and inform the actions module.
|
// 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 (DS.isFriendSpecified()) {
|
||||||
// If we're dealing with a class template decl, assume that the
|
// If we're dealing with a decl but not a TagDecl, assume that
|
||||||
// template routines are handling it.
|
// whatever routines created it handled the friendship aspect.
|
||||||
if (TagD && isa<ClassTemplateDecl>(TagD))
|
if (TagD && !Tag)
|
||||||
return 0;
|
return 0;
|
||||||
return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0));
|
return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0));
|
||||||
}
|
}
|
||||||
|
@ -2797,8 +2797,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
= MatchTemplateParametersToScopeSpecifier(
|
= MatchTemplateParametersToScopeSpecifier(
|
||||||
D.getDeclSpec().getSourceRange().getBegin(),
|
D.getDeclSpec().getSourceRange().getBegin(),
|
||||||
D.getCXXScopeSpec(),
|
D.getCXXScopeSpec(),
|
||||||
(TemplateParameterList**)TemplateParamLists.get(),
|
TemplateParamLists.get(),
|
||||||
TemplateParamLists.size(),
|
TemplateParamLists.size(),
|
||||||
/*never a friend*/ false,
|
/*never a friend*/ false,
|
||||||
isExplicitSpecialization,
|
isExplicitSpecialization,
|
||||||
Invalid)) {
|
Invalid)) {
|
||||||
|
@ -2836,7 +2836,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) {
|
if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) {
|
||||||
NewVD->setTemplateParameterListsInfo(Context,
|
NewVD->setTemplateParameterListsInfo(Context,
|
||||||
NumMatchedTemplateParamLists,
|
NumMatchedTemplateParamLists,
|
||||||
(TemplateParameterList**)TemplateParamLists.release());
|
TemplateParamLists.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (D.getDeclSpec().isThreadSpecified()) {
|
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.
|
// If this is not a definition, it must have a name.
|
||||||
assert((Name != 0 || TUK == TUK_Definition) &&
|
assert((Name != 0 || TUK == TUK_Definition) &&
|
||||||
"Nameless record must be a definition!");
|
"Nameless record must be a definition!");
|
||||||
|
assert(TemplateParameterLists.size() == 0 || TUK != TUK_Reference);
|
||||||
|
|
||||||
OwnedDecl = false;
|
OwnedDecl = false;
|
||||||
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
|
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
|
||||||
|
@ -5491,7 +5492,12 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
||||||
bool isExplicitSpecialization = false;
|
bool isExplicitSpecialization = false;
|
||||||
unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size();
|
unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size();
|
||||||
bool Invalid = false;
|
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
|
if (TemplateParameterList *TemplateParams
|
||||||
= MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
|
= MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
|
||||||
TemplateParameterLists.get(),
|
TemplateParameterLists.get(),
|
||||||
|
@ -5606,7 +5612,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
||||||
// and that current instantiation has any dependent base
|
// and that current instantiation has any dependent base
|
||||||
// classes, we might find something at instantiation time: treat
|
// classes, we might find something at instantiation time: treat
|
||||||
// this as a dependent elaborated-type-specifier.
|
// 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;
|
IsDependent = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6244,6 +6244,110 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc,
|
||||||
return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, 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
|
/// Handle a friend type declaration. This works in tandem with
|
||||||
/// ActOnTag.
|
/// ActOnTag.
|
||||||
///
|
///
|
||||||
|
|
|
@ -550,6 +550,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
FD->setAccess(AS_public);
|
FD->setAccess(AS_public);
|
||||||
|
FD->setUnsupportedFriend(D->isUnsupportedFriend());
|
||||||
Owner->addDecl(FD);
|
Owner->addDecl(FD);
|
||||||
return FD;
|
return FD;
|
||||||
}
|
}
|
||||||
|
@ -568,6 +569,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
|
||||||
FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
|
FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
|
||||||
cast<NamedDecl>(NewND), D->getFriendLoc());
|
cast<NamedDecl>(NewND), D->getFriendLoc());
|
||||||
FD->setAccess(AS_public);
|
FD->setAccess(AS_public);
|
||||||
|
FD->setUnsupportedFriend(D->isUnsupportedFriend());
|
||||||
Owner->addDecl(FD);
|
Owner->addDecl(FD);
|
||||||
return FD;
|
return FD;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,3 +56,25 @@ namespace test2 {
|
||||||
void f() { C::foo(); }
|
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