forked from OSchip/llvm-project
Revert 99477 since it appears to be breaking the clang-x86_64-darwin10-fnt
buildbot. The tramp3d test fails. --- Reverse-merging r99477 into '.': U test/SemaTemplate/friend-template.cpp U test/CXX/temp/temp.decls/temp.friend/p1.cpp U lib/Sema/SemaTemplateInstantiateDecl.cpp U lib/Sema/SemaAccess.cpp llvm-svn: 99481
This commit is contained in:
parent
4d745dd5cb
commit
63d45e51fb
|
@ -240,13 +240,13 @@ static Sema::AccessResult MatchesFriend(Sema &S,
|
||||||
ClassTemplateDecl *Friend) {
|
ClassTemplateDecl *Friend) {
|
||||||
Sema::AccessResult OnFailure = Sema::AR_inaccessible;
|
Sema::AccessResult OnFailure = Sema::AR_inaccessible;
|
||||||
|
|
||||||
// Check whether the friend is the template of a class in the
|
|
||||||
// context chain.
|
|
||||||
for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
|
for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
|
||||||
I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
|
I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
|
||||||
CXXRecordDecl *Record = *I;
|
CXXRecordDecl *Record = *I;
|
||||||
|
|
||||||
// Figure out whether the current class has a template:
|
// Check whether the friend is the template of a class in the
|
||||||
|
// context chain. To do that, we need to figure out whether the
|
||||||
|
// current class has a template:
|
||||||
ClassTemplateDecl *CTD;
|
ClassTemplateDecl *CTD;
|
||||||
|
|
||||||
// A specialization of the template...
|
// A specialization of the template...
|
||||||
|
@ -264,10 +264,6 @@ static Sema::AccessResult MatchesFriend(Sema &S,
|
||||||
if (Friend == CTD->getCanonicalDecl())
|
if (Friend == CTD->getCanonicalDecl())
|
||||||
return Sema::AR_accessible;
|
return Sema::AR_accessible;
|
||||||
|
|
||||||
// If the context isn't dependent, it can't be a dependent match.
|
|
||||||
if (!EC.isDependent())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// If the template names don't match, it can't be a dependent
|
// If the template names don't match, it can't be a dependent
|
||||||
// match. This isn't true in C++0x because of template aliases.
|
// match. This isn't true in C++0x because of template aliases.
|
||||||
if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName())
|
if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName())
|
||||||
|
|
|
@ -500,17 +500,21 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
|
||||||
|
|
||||||
// Hack to make this work almost well pending a rewrite.
|
// Hack to make this work almost well pending a rewrite.
|
||||||
if (ND->getDeclContext()->isRecord()) {
|
if (ND->getDeclContext()->isRecord()) {
|
||||||
// FIXME: Hack to avoid crashing when incorrectly trying to instantiate
|
if (!ND->getDeclContext()->isDependentContext()) {
|
||||||
// templated friend declarations. This doesn't produce a correct AST;
|
NewND = SemaRef.FindInstantiatedDecl(D->getLocation(), ND,
|
||||||
// however this is sufficient for some AST analysis. The real solution
|
TemplateArgs);
|
||||||
// must be put in place during the pending rewrite. See PR5848.
|
} else {
|
||||||
return 0;
|
// FIXME: Hack to avoid crashing when incorrectly trying to instantiate
|
||||||
|
// templated friend declarations. This doesn't produce a correct AST;
|
||||||
|
// however this is sufficient for some AST analysis. The real solution
|
||||||
|
// must be put in place during the pending rewrite. See PR5848.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
} else if (D->wasSpecialization()) {
|
} else if (D->wasSpecialization()) {
|
||||||
// Totally egregious hack to work around PR5866
|
// Totally egregious hack to work around PR5866
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else
|
||||||
NewND = Visit(ND);
|
NewND = Visit(ND);
|
||||||
}
|
|
||||||
if (!NewND) return 0;
|
if (!NewND) return 0;
|
||||||
|
|
||||||
FU = cast<NamedDecl>(NewND);
|
FU = cast<NamedDecl>(NewND);
|
||||||
|
@ -637,8 +641,6 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
||||||
bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
|
|
||||||
|
|
||||||
// Create a local instantiation scope for this class template, which
|
// Create a local instantiation scope for this class template, which
|
||||||
// will contain the instantiations of the template parameters.
|
// will contain the instantiations of the template parameters.
|
||||||
Sema::LocalInstantiationScope Scope(SemaRef);
|
Sema::LocalInstantiationScope Scope(SemaRef);
|
||||||
|
@ -648,95 +650,32 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
CXXRecordDecl *Pattern = D->getTemplatedDecl();
|
CXXRecordDecl *Pattern = D->getTemplatedDecl();
|
||||||
|
|
||||||
// Instantiate the qualifier. We have to do this first in case
|
|
||||||
// we're a friend declaration, because if we are then we need to put
|
|
||||||
// the new declaration in the appropriate context.
|
|
||||||
NestedNameSpecifier *Qualifier = Pattern->getQualifier();
|
|
||||||
if (Qualifier) {
|
|
||||||
Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
|
|
||||||
Pattern->getQualifierRange(),
|
|
||||||
TemplateArgs);
|
|
||||||
if (!Qualifier) return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CXXRecordDecl *PrevDecl = 0;
|
|
||||||
ClassTemplateDecl *PrevClassTemplate = 0;
|
|
||||||
|
|
||||||
// If this isn't a friend, then it's a member template, in which
|
|
||||||
// case we just want to build the instantiation in the
|
|
||||||
// specialization. If it is a friend, we want to build it in
|
|
||||||
// the appropriate context.
|
|
||||||
DeclContext *DC = Owner;
|
|
||||||
if (isFriend) {
|
|
||||||
if (Qualifier) {
|
|
||||||
CXXScopeSpec SS;
|
|
||||||
SS.setScopeRep(Qualifier);
|
|
||||||
SS.setRange(Pattern->getQualifierRange());
|
|
||||||
DC = SemaRef.computeDeclContext(SS);
|
|
||||||
if (!DC) return 0;
|
|
||||||
} else {
|
|
||||||
DC = SemaRef.FindInstantiatedContext(Pattern->getLocation(),
|
|
||||||
Pattern->getDeclContext(),
|
|
||||||
TemplateArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for a previous declaration of the template in the owning
|
|
||||||
// context.
|
|
||||||
LookupResult R(SemaRef, Pattern->getDeclName(), Pattern->getLocation(),
|
|
||||||
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
|
|
||||||
SemaRef.LookupQualifiedName(R, DC);
|
|
||||||
|
|
||||||
if (R.isSingleResult()) {
|
|
||||||
PrevClassTemplate = R.getAsSingle<ClassTemplateDecl>();
|
|
||||||
if (PrevClassTemplate)
|
|
||||||
PrevDecl = PrevClassTemplate->getTemplatedDecl();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PrevClassTemplate && Qualifier) {
|
|
||||||
SemaRef.Diag(Pattern->getLocation(), diag::err_not_tag_in_scope)
|
|
||||||
<< Pattern->getDeclName() << Pattern->getQualifierRange();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PrevClassTemplate &&
|
|
||||||
!SemaRef.TemplateParameterListsAreEqual(InstParams,
|
|
||||||
PrevClassTemplate->getTemplateParameters(),
|
|
||||||
/*Complain=*/true,
|
|
||||||
Sema::TPL_TemplateMatch))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CXXRecordDecl *RecordInst
|
CXXRecordDecl *RecordInst
|
||||||
= CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), DC,
|
= CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), Owner,
|
||||||
Pattern->getLocation(), Pattern->getIdentifier(),
|
Pattern->getLocation(), Pattern->getIdentifier(),
|
||||||
Pattern->getTagKeywordLoc(), PrevDecl,
|
Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL,
|
||||||
/*DelayTypeCreation=*/true);
|
/*DelayTypeCreation=*/true);
|
||||||
|
|
||||||
if (Qualifier)
|
// Substitute the nested name specifier, if any.
|
||||||
RecordInst->setQualifierInfo(Qualifier, Pattern->getQualifierRange());
|
if (SubstQualifier(Pattern, RecordInst))
|
||||||
|
return 0;
|
||||||
|
|
||||||
ClassTemplateDecl *Inst
|
ClassTemplateDecl *Inst
|
||||||
= ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(),
|
= ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
|
||||||
D->getIdentifier(), InstParams, RecordInst,
|
D->getIdentifier(), InstParams, RecordInst, 0);
|
||||||
PrevClassTemplate);
|
|
||||||
RecordInst->setDescribedClassTemplate(Inst);
|
RecordInst->setDescribedClassTemplate(Inst);
|
||||||
if (isFriend) {
|
if (D->getFriendObjectKind())
|
||||||
Inst->setObjectOfFriendDecl(PrevClassTemplate != 0);
|
Inst->setObjectOfFriendDecl(true);
|
||||||
// TODO: do we want to track the instantiation progeny of this
|
else
|
||||||
// friend target decl?
|
|
||||||
} else {
|
|
||||||
Inst->setAccess(D->getAccess());
|
Inst->setAccess(D->getAccess());
|
||||||
Inst->setInstantiatedFromMemberTemplate(D);
|
Inst->setInstantiatedFromMemberTemplate(D);
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger creation of the type for the instantiation.
|
// Trigger creation of the type for the instantiation.
|
||||||
SemaRef.Context.getInjectedClassNameType(RecordInst,
|
SemaRef.Context.getInjectedClassNameType(RecordInst,
|
||||||
Inst->getInjectedClassNameSpecialization(SemaRef.Context));
|
Inst->getInjectedClassNameSpecialization(SemaRef.Context));
|
||||||
|
|
||||||
// Finish handling of friends.
|
// Finish handling of friends.
|
||||||
if (isFriend) {
|
if (Inst->getFriendObjectKind()) {
|
||||||
DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false);
|
|
||||||
return Inst;
|
return Inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,21 +114,7 @@ namespace test3 {
|
||||||
|
|
||||||
template class User<bool>;
|
template class User<bool>;
|
||||||
template class User<int>; // expected-note {{requested here}}
|
template class User<int>; // expected-note {{requested here}}
|
||||||
}
|
|
||||||
|
|
||||||
namespace test4 {
|
|
||||||
template <class T> class A {
|
|
||||||
template <class T0> friend class B;
|
|
||||||
bool foo(const A<T> *) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T> class B {
|
|
||||||
bool bar(const A<T> *a, const A<T> *b) {
|
|
||||||
return a->foo(b);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template class B<int>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Dependent {
|
namespace Dependent {
|
||||||
|
|
|
@ -74,16 +74,12 @@ namespace test3 {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class X3 {
|
class X3 {
|
||||||
template<typename U, U Value> friend struct X2a;
|
template<typename U, U Value> friend struct X2a;
|
||||||
|
template<typename U, T Value> friend struct X2b;
|
||||||
// FIXME: the redeclaration note ends up here because redeclaration
|
|
||||||
// lookup ends up finding the friend target from X3<int>.
|
|
||||||
template<typename U, T Value> friend struct X2b; // expected-error {{template non-type parameter has a different type 'long' in template redeclaration}} \
|
|
||||||
// expected-note {{previous non-type template parameter with type 'int' is here}}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
X3<int> x3i; // okay
|
X3<int> x3i; // okay
|
||||||
|
|
||||||
X3<long> x3l; // expected-note {{in instantiation}}
|
X3<long> x3l; // FIXME: should cause an instantiation-time failure
|
||||||
}
|
}
|
||||||
|
|
||||||
// PR5716
|
// PR5716
|
||||||
|
|
Loading…
Reference in New Issue