[cfe-commits] r91146 - in /cfe/trunk: include/clang/Parse/Action.h lib/Parse/ParseDecl.cpp lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp test/SemaCXX/friend.cpp
John McCall
rjmccall at apple.com
Fri Dec 11 12:04:54 PST 2009
Author: rjmccall
Date: Fri Dec 11 14:04:54 2009
New Revision: 91146
URL: http://llvm.org/viewvc/llvm-project?rev=91146&view=rev
Log:
Don't enter a new scope for a namespace-qualified declarator unless we're
in a file context. In well-formed code, only happens with friend functions.
Fixes PR 5760.
Modified:
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
cfe/trunk/test/SemaCXX/friend.cpp
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=91146&r1=91145&r2=91146&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Fri Dec 11 14:04:54 2009
@@ -365,8 +365,19 @@
return 0;
}
+ /// ShouldEnterDeclaratorScope - Called when a C++ scope specifier
+ /// is parsed as part of a declarator-id to determine whether a scope
+ /// should be entered.
+ ///
+ /// \param S the current scope
+ /// \param SS the scope being entered
+ /// \param isFriendDeclaration whether this is a friend declaration
+ virtual bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+ return false;
+ }
+
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
- /// scope or nested-name-specifier) is parsed, part of a declarator-id.
+ /// scope or nested-name-specifier) is parsed as part of a declarator-id.
/// After this method is called, according to [C++ 3.4.3p3], names should be
/// looked up in the declarator-id's scope, until the declarator is parsed and
/// ActOnCXXExitDeclaratorScope is called.
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=91146&r1=91145&r2=91146&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Dec 11 14:04:54 2009
@@ -2335,9 +2335,10 @@
ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0,
true);
if (afterCXXScope) {
- // Change the declaration context for name lookup, until this function
- // is exited (and the declarator has been parsed).
- DeclScopeObj.EnterDeclaratorScope();
+ if (Actions.ShouldEnterDeclaratorScope(CurScope, D.getCXXScopeSpec()))
+ // Change the declaration context for name lookup, until this function
+ // is exited (and the declarator has been parsed).
+ DeclScopeObj.EnterDeclaratorScope();
}
if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) ||
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=91146&r1=91145&r2=91146&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Dec 11 14:04:54 2009
@@ -2048,6 +2048,8 @@
SourceRange TypeRange,
SourceLocation CCLoc);
+ virtual bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS);
+
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
/// scope or nested-name-specifier) is parsed, part of a declarator-id.
/// After this method is called, according to [C++ 3.4.3p3], names should be
Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=91146&r1=91145&r2=91146&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Fri Dec 11 14:04:54 2009
@@ -559,6 +559,44 @@
T.getTypePtr());
}
+bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+ assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
+
+ NestedNameSpecifier *Qualifier =
+ static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+
+ // There are only two places a well-formed program may qualify a
+ // declarator: first, when defining a namespace or class member
+ // out-of-line, and second, when naming an explicitly-qualified
+ // friend function. The latter case is governed by
+ // C++03 [basic.lookup.unqual]p10:
+ // In a friend declaration naming a member function, a name used
+ // in the function declarator and not part of a template-argument
+ // in a template-id is first looked up in the scope of the member
+ // function's class. If it is not found, or if the name is part of
+ // a template-argument in a template-id, the look up is as
+ // described for unqualified names in the definition of the class
+ // granting friendship.
+ // i.e. we don't push a scope unless it's a class member.
+
+ switch (Qualifier->getKind()) {
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Namespace:
+ // These are always namespace scopes. We never want to enter a
+ // namespace scope from anything but a file context.
+ return CurContext->getLookupContext()->isFileContext();
+
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ // These are never namespace scopes.
+ return true;
+ }
+
+ // Silence bogus warning.
+ return false;
+}
+
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
/// scope or nested-name-specifier) is parsed, part of a declarator-id.
/// After this method is called, according to [C++ 3.4.3p3], names should be
Modified: cfe/trunk/test/SemaCXX/friend.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/friend.cpp?rev=91146&r1=91145&r2=91146&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/friend.cpp (original)
+++ cfe/trunk/test/SemaCXX/friend.cpp Fri Dec 11 14:04:54 2009
@@ -4,3 +4,14 @@
void f() { friend class A; } // expected-error {{'friend' used outside of class}}
class C { friend class A; };
class D { void f() { friend class A; } }; // expected-error {{'friend' used outside of class}}
+
+// PR5760
+namespace test0 {
+ namespace ns {
+ void f(int);
+ }
+
+ struct A {
+ friend void ns::f(int a);
+ };
+}
More information about the cfe-commits
mailing list