[cfe-commits] r99610 - in /cfe/trunk: lib/Sema/SemaAccess.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/class.access/class.friend/p1.cpp test/CXX/temp/temp.decls/temp.friend/p1.cpp
John McCall
rjmccall at apple.com
Thu Mar 25 21:53:08 PDT 2010
Author: rjmccall
Date: Thu Mar 25 23:53:08 2010
New Revision: 99610
URL: http://llvm.org/viewvc/llvm-project?rev=99610&view=rev
Log:
Reapply r99596 with a fix: link an instantiated friend function to its
pattern if it has a body.
Modified:
cfe/trunk/lib/Sema/SemaAccess.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/test/CXX/class.access/class.friend/p1.cpp
cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=99610&r1=99609&r2=99610&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Thu Mar 25 23:53:08 2010
@@ -319,7 +319,7 @@
if (Friend == FTD->getCanonicalDecl())
return Sema::AR_accessible;
- if (MightInstantiateTo(S, FTD, Friend))
+ if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
return Sema::AR_dependent;
return Sema::AR_inaccessible;
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=99610&r1=99609&r2=99610&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Mar 25 23:53:08 2010
@@ -904,8 +904,15 @@
// Check whether there is already a function template specialization for
// this declaration.
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
+
+ bool isFriend;
+ if (FunctionTemplate)
+ isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None);
+ else
+ isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
+
void *InsertPos = 0;
- if (FunctionTemplate && !TemplateParams) {
+ if (!isFriend && FunctionTemplate && !TemplateParams) {
llvm::FoldingSetNodeID ID;
FunctionTemplateSpecializationInfo::Profile(ID,
TemplateArgs.getInnermost().getFlatArgumentList(),
@@ -933,14 +940,29 @@
return 0;
QualType T = TInfo->getType();
+ NestedNameSpecifier *Qualifier = D->getQualifier();
+ if (Qualifier) {
+ Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
+ D->getQualifierRange(),
+ TemplateArgs);
+ if (!Qualifier) return 0;
+ }
+
// If we're instantiating a local function declaration, put the result
// in the owner; otherwise we need to find the instantiated context.
DeclContext *DC;
if (D->getDeclContext()->isFunctionOrMethod())
DC = Owner;
- else
+ else if (isFriend && Qualifier) {
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ SS.setRange(D->getQualifierRange());
+ DC = SemaRef.computeDeclContext(SS);
+ if (!DC) return 0;
+ } else {
DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(),
TemplateArgs);
+ }
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
@@ -948,9 +970,8 @@
D->getStorageClass(),
D->isInlineSpecified(), D->hasWrittenPrototype());
- // Substitute the nested name specifier, if any.
- if (SubstQualifier(D, Function))
- return 0;
+ if (Qualifier)
+ Function->setQualifierInfo(Qualifier, D->getQualifierRange());
Function->setLexicalDeclContext(Owner);
@@ -974,17 +995,28 @@
// which means substituting int for T, but leaving "f" as a friend function
// template.
// Build the function template itself.
- FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Owner,
+ FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, DC,
Function->getLocation(),
Function->getDeclName(),
TemplateParams, Function);
Function->setDescribedFunctionTemplate(FunctionTemplate);
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+
+ if (isFriend && D->isThisDeclarationADefinition()) {
+ // TODO: should we remember this connection regardless of whether
+ // the friend declaration provided a body?
+ FunctionTemplate->setInstantiatedFromMemberTemplate(
+ D->getDescribedFunctionTemplate());
+ }
} else if (FunctionTemplate) {
// Record this function template specialization.
Function->setFunctionTemplateSpecialization(FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
+ } else if (isFriend && D->isThisDeclarationADefinition()) {
+ // TODO: should we remember this connection regardless of whether
+ // the friend declaration provided a body?
+ Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
if (InitFunctionInstantiation(Function, D))
@@ -1016,9 +1048,7 @@
// If the original function was part of a friend declaration,
// inherit its namespace state and add it to the owner.
- NamedDecl *FromFriendD
- = TemplateParams? cast<NamedDecl>(D->getDescribedFunctionTemplate()) : D;
- if (FromFriendD->getFriendObjectKind()) {
+ if (isFriend) {
NamedDecl *ToFriendD = 0;
NamedDecl *PrevDecl;
if (TemplateParams) {
@@ -1029,11 +1059,7 @@
PrevDecl = Function->getPreviousDeclaration();
}
ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL);
- if (!Owner->isDependentContext() && !PrevDecl)
- DC->makeDeclVisibleInContext(ToFriendD, /* Recoverable = */ false);
-
- if (!TemplateParams)
- Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+ DC->makeDeclVisibleInContext(ToFriendD, /*Recoverable=*/ false);
}
return Function;
Modified: cfe/trunk/test/CXX/class.access/class.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/class.friend/p1.cpp?rev=99610&r1=99609&r2=99610&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/class.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/class.access/class.friend/p1.cpp Thu Mar 25 23:53:08 2010
@@ -165,3 +165,18 @@
return p->x; // expected-error {{'x' is a protected member of 'test3::A'}}
}
}
+
+namespace test4 {
+ template <class T> class Holder {
+ T object;
+ friend bool operator==(Holder &a, Holder &b) {
+ return a.object == b.object; // expected-error {{invalid operands to binary expression}}
+ }
+ };
+
+ struct Inequal {};
+ bool test() {
+ Holder<Inequal> a, b;
+ return a == b; // expected-note {{requested here}}
+ }
+}
Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp?rev=99610&r1=99609&r2=99610&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp Thu Mar 25 23:53:08 2010
@@ -178,3 +178,16 @@
};
template class D<int>;
}
+
+namespace test8 {
+ template <class N> class A {
+ static int x;
+ template <class T> friend void foo();
+ };
+ template class A<int>;
+
+ template <class T> void foo() {
+ A<int>::x = 0;
+ }
+ template void foo<int>();
+}
More information about the cfe-commits
mailing list