aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-10-13 05:45:15 +0000
committerJohn McCall <rjmccall@apple.com>2010-10-13 05:45:15 +0000
commit29ae6e5fb001deddd831e66faf143ecd9e50f67c (patch)
treeeef97e606a9b4f6326e5797691f196409321564c /lib/Sema/SemaDeclCXX.cpp
parent3bd5b6c3c2ad1d5a6f88cf21f627e8d4f03c4df4 (diff)
Support friend function declarations in local classes correctly.
Fixes a crash and diagnoses the error condition of an unqualified friend which doesn't resolve to something. I'm still not certain how this is useful. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116393 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r--lib/Sema/SemaDeclCXX.cpp28
1 files changed, 22 insertions, 6 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index eb62b6a9db..62ac3bb455 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -6344,12 +6344,26 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
// There are four cases here.
// - There's no scope specifier, in which case we just go to the
- // appropriate namespace and create a function or function template
+ // appropriate scope and look for a function or function template
// there as appropriate.
// Recover from invalid scope qualifiers as if they just weren't there.
if (SS.isInvalid() || !SS.isSet()) {
- // Walk out to the nearest namespace scope looking for matches.
-
+ // C++0x [namespace.memdef]p3:
+ // If the name in a friend declaration is neither qualified nor
+ // a template-id and the declaration is a function or an
+ // elaborated-type-specifier, the lookup to determine whether
+ // the entity has been previously declared shall not consider
+ // any scopes outside the innermost enclosing namespace.
+ // C++0x [class.friend]p11:
+ // If a friend declaration appears in a local class and the name
+ // specified is an unqualified name, a prior declaration is
+ // looked up without considering scopes that are outside the
+ // innermost enclosing non-class scope. For a friend function
+ // declaration, if there is no prior declaration, the program is
+ // ill-formed.
+ bool isLocal = cast<CXXRecordDecl>(CurContext)->isLocalClass();
+
+ // Find the appropriate context according to the above.
DC = CurContext;
while (true) {
// Skip class contexts. If someone can cite chapter and verse
@@ -6365,9 +6379,9 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
LookupQualifiedName(Previous, DC);
// TODO: decide what we think about using declarations.
- if (!Previous.empty())
+ if (isLocal || !Previous.empty())
break;
-
+
if (DC->isFileContext()) break;
DC = DC->getParent();
}
@@ -6381,6 +6395,8 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
&& !getLangOptions().CPlusPlus0x)
Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
+ S = getScopeForDeclContext(S, DC);
+
// - There's a non-dependent scope specifier, in which case we
// compute it and do a previous lookup there for a function
// or function template.
@@ -6425,7 +6441,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?");
}
- if (DC->isFileContext()) {
+ if (!DC->isRecord()) {
// This implies that it has to be an operator or function.
if (D.getName().getKind() == UnqualifiedId::IK_ConstructorName ||
D.getName().getKind() == UnqualifiedId::IK_DestructorName ||