[cfe-commits] r99708 - in /cfe/trunk: include/clang/AST/DeclBase.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/temp/temp.decls/temp.friend/p1.cpp
John McCall
rjmccall at apple.com
Fri Mar 26 22:57:59 PDT 2010
Author: rjmccall
Date: Sat Mar 27 00:57:59 2010
New Revision: 99708
URL: http://llvm.org/viewvc/llvm-project?rev=99708&view=rev
Log:
Implement method friends in class templates and fix a few related problems.
Modified:
cfe/trunk/include/clang/AST/DeclBase.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=99708&r1=99707&r2=99708&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Sat Mar 27 00:57:59 2010
@@ -452,15 +452,23 @@
/// same entity may not (and probably don't) share this property.
void setObjectOfFriendDecl(bool PreviouslyDeclared) {
unsigned OldNS = IdentifierNamespace;
- assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary ||
- OldNS == (IDNS_Tag | IDNS_Ordinary))
- && "unsupported namespace for undeclared friend");
- if (!PreviouslyDeclared) IdentifierNamespace = 0;
+ assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
+ IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
+ "namespace includes neither ordinary nor tag");
+ assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary |
+ IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
+ "namespace includes other than ordinary or tag");
- if (OldNS == IDNS_Tag)
+ IdentifierNamespace = 0;
+ if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
IdentifierNamespace |= IDNS_TagFriend;
- else
+ if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag;
+ }
+
+ if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) {
IdentifierNamespace |= IDNS_OrdinaryFriend;
+ if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary;
+ }
}
enum FriendObjectKind {
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=99708&r1=99707&r2=99708&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Mar 27 00:57:59 2010
@@ -2998,13 +2998,13 @@
"previously-undeclared friend function being created "
"in a non-namespace context");
+ // For now, claim that the objects have no previous declaration.
if (FunctionTemplate) {
- FunctionTemplate->setObjectOfFriendDecl(
- /* PreviouslyDeclared= */ !Previous.empty());
+ FunctionTemplate->setObjectOfFriendDecl(false);
FunctionTemplate->setAccess(AS_public);
+ } else {
+ NewFD->setObjectOfFriendDecl(false);
}
- else
- NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ !Previous.empty());
NewFD->setAccess(AS_public);
}
@@ -3154,6 +3154,17 @@
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
+ if (isFriend && Redeclaration) {
+ AccessSpecifier Access = NewFD->getPreviousDeclaration()->getAccess();
+ if (FunctionTemplate) {
+ FunctionTemplate->setObjectOfFriendDecl(true);
+ FunctionTemplate->setAccess(Access);
+ } else {
+ NewFD->setObjectOfFriendDecl(true);
+ }
+ NewFD->setAccess(Access);
+ }
+
// If we have a function template, check the template parameter
// list. This will check and merge default template arguments.
if (FunctionTemplate) {
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=99708&r1=99707&r2=99708&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Sat Mar 27 00:57:59 2010
@@ -503,13 +503,7 @@
Decl *NewND;
// Hack to make this work almost well pending a rewrite.
- if (ND->getDeclContext()->isRecord()) {
- // 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()) {
+ if (D->wasSpecialization()) {
// Totally egregious hack to work around PR5866
return 0;
} else {
@@ -906,15 +900,8 @@
// 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 (!isFriend && FunctionTemplate && !TemplateParams) {
+ if (FunctionTemplate && !TemplateParams) {
llvm::FoldingSetNodeID ID;
FunctionTemplateSpecializationInfo::Profile(ID,
TemplateArgs.getInnermost().getFlatArgumentList(),
@@ -930,6 +917,12 @@
return Info->Function;
}
+ bool isFriend;
+ if (FunctionTemplate)
+ isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None);
+ else
+ isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
+
bool MergeWithParentScope = (TemplateParams != 0) ||
!(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
@@ -1098,6 +1091,12 @@
return Info->Function;
}
+ bool isFriend;
+ if (FunctionTemplate)
+ isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None);
+ else
+ isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
+
bool MergeWithParentScope = (TemplateParams != 0) ||
!(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
@@ -1110,8 +1109,31 @@
return 0;
QualType T = TInfo->getType();
+ NestedNameSpecifier *Qualifier = D->getQualifier();
+ if (Qualifier) {
+ Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
+ D->getQualifierRange(),
+ TemplateArgs);
+ if (!Qualifier) return 0;
+ }
+
+ DeclContext *DC = Owner;
+ if (isFriend) {
+ if (Qualifier) {
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ SS.setRange(D->getQualifierRange());
+ DC = SemaRef.computeDeclContext(SS);
+ } else {
+ DC = SemaRef.FindInstantiatedContext(D->getLocation(),
+ D->getDeclContext(),
+ TemplateArgs);
+ }
+ if (!DC) return 0;
+ }
+
// Build the instantiated method declaration.
- CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXMethodDecl *Method = 0;
DeclarationName Name = D->getDeclName();
@@ -1148,9 +1170,8 @@
D->isStatic(), D->isInlineSpecified());
}
- // Substitute the nested name specifier, if any.
- if (SubstQualifier(D, Method))
- return 0;
+ if (Qualifier)
+ Method->setQualifierInfo(Qualifier, D->getQualifierRange());
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
@@ -1170,7 +1191,10 @@
Method->getLocation(),
Method->getDeclName(),
TemplateParams, Method);
- if (D->isOutOfLine())
+ if (isFriend) {
+ FunctionTemplate->setLexicalDeclContext(Owner);
+ FunctionTemplate->setObjectOfFriendDecl(true);
+ } else if (D->isOutOfLine())
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate);
} else if (FunctionTemplate) {
@@ -1178,7 +1202,7 @@
Method->setFunctionTemplateSpecialization(FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
- } else {
+ } else if (!isFriend) {
// Record that this is an instantiation of a member function.
Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
@@ -1186,7 +1210,10 @@
// If we are instantiating a member function defined
// out-of-line, the instantiation will have the same lexical
// context (which will be a namespace scope) as the template.
- if (D->isOutOfLine())
+ if (isFriend) {
+ Method->setLexicalDeclContext(Owner);
+ Method->setObjectOfFriendDecl(true);
+ } else if (D->isOutOfLine())
Method->setLexicalDeclContext(D->getLexicalDeclContext());
// Attach the parameters
@@ -1200,8 +1227,8 @@
LookupResult Previous(SemaRef, Name, SourceLocation(),
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
- if (!FunctionTemplate || TemplateParams) {
- SemaRef.LookupQualifiedName(Previous, Owner);
+ if (!FunctionTemplate || TemplateParams || isFriend) {
+ SemaRef.LookupQualifiedName(Previous, Record);
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
@@ -1221,9 +1248,19 @@
Method->setAccess(D->getAccess());
- if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) &&
- !Method->getFriendObjectKind())
- Owner->addDecl(Method);
+ if (FunctionTemplate) {
+ // If there's a function template, let our caller handle it.
+ } else if (Method->isInvalidDecl() && !Previous.empty()) {
+ // Don't hide a (potentially) valid declaration with an invalid one.
+ } else {
+ NamedDecl *DeclToAdd = (TemplateParams
+ ? cast<NamedDecl>(FunctionTemplate)
+ : Method);
+ if (isFriend)
+ Record->makeDeclVisibleInContext(DeclToAdd);
+ else
+ Owner->addDecl(DeclToAdd);
+ }
return Method;
}
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=99708&r1=99707&r2=99708&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 Sat Mar 27 00:57:59 2010
@@ -191,3 +191,28 @@
}
template void foo<int>();
}
+
+namespace test9 {
+ template <class T> class A {
+ class B; class C;
+
+ int foo(B *b) {
+ return b->x;
+ }
+
+ int foo(C *c) {
+ return c->x; // expected-error {{'x' is a private member}}
+ }
+
+ class B {
+ int x;
+ friend int A::foo(B*);
+ };
+
+ class C {
+ int x; // expected-note {{declared private here}}
+ };
+ };
+
+ template class A<int>; // expected-note {{in instantiation}}
+}
More information about the cfe-commits
mailing list