aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2009-12-19 09:28:58 +0000
committerJohn McCall <rjmccall@apple.com>2009-12-19 09:28:58 +0000
commit731ad843b7bf1862f6547ac79539f0f5b4c539bd (patch)
tree97e3dae789dab6e85566c174aaa08aa02b818c44
parentcfdc81a83467973b14e4ea5e9e9af1690f135415 (diff)
Just push a new scope when parsing an out-of-line variable definition.
Magically fixes all the terrible lookup problems associated with not pushing a new scope. Resolves an ancient xfail and an LLVM misparse. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91769 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Parse/ParseDecl.cpp8
-rw-r--r--lib/Sema/SemaDeclCXX.cpp76
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp7
-rw-r--r--test/SemaCXX/nested-name-spec.cpp13
-rw-r--r--test/SemaCXX/qual-id-test.cpp2
5 files changed, 69 insertions, 37 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 5dd78f7b54..43c92456d2 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -550,13 +550,17 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
SourceLocation DelLoc = ConsumeToken();
Actions.SetDeclDeleted(ThisDecl, DelLoc);
} else {
- if (getLang().CPlusPlus)
+ if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
+ EnterScope(0);
Actions.ActOnCXXEnterDeclInitializer(CurScope, ThisDecl);
+ }
OwningExprResult Init(ParseInitializer());
- if (getLang().CPlusPlus)
+ if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
Actions.ActOnCXXExitDeclInitializer(CurScope, ThisDecl);
+ ExitScope();
+ }
if (Init.isInvalid()) {
SkipUntil(tok::semi, true, true);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 565fce8b5f..24534e74ee 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -5529,51 +5529,61 @@ bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) {
return true;
}
-/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an
-/// initializer for the declaration 'Dcl'.
+/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse
+/// an initializer for the out-of-line declaration 'Dcl'. The scope
+/// is a fresh scope pushed for just this purpose.
+///
/// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a
/// static data member of class X, names should be looked up in the scope of
/// class X.
void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) {
- AdjustDeclIfTemplate(Dcl);
-
- Decl *D = Dcl.getAs<Decl>();
// If there is no declaration, there was an error parsing it.
- if (D == 0)
- return;
-
- // Check whether it is a declaration with a nested name specifier like
- // int foo::bar;
- if (!D->isOutOfLine())
- return;
-
- // C++ [basic.lookup.unqual]p13
- //
- // A name used in the definition of a static data member of class X
- // (after the qualified-id of the static member) is looked up as if the name
- // was used in a member function of X.
-
- // Change current context into the context of the initializing declaration.
- EnterDeclaratorContext(S, D->getDeclContext());
+ Decl *D = Dcl.getAs<Decl>();
+ if (D == 0) return;
+
+ // We should only get called for declarations with scope specifiers, like:
+ // int foo::bar;
+ assert(D->isOutOfLine());
+
+ // C++0x [basic.lookup.unqual]p13:
+ // A name used in the definition of a static data member of class
+ // X (after the qualified-id of the static member) is looked up as
+ // if the name was used in a member function of X.
+ // C++0x [basic.lookup.unqual]p14:
+ // If a variable member of a namespace is defined outside of the
+ // scope of its namespace then any name used in the definition of
+ // the variable member (after the declarator-id) is looked up as
+ // if the definition of the variable member occurred in its
+ // namespace.
+ // Both of these imply that we should push a scope whose context
+ // is the semantic context of the declaration. We can't use
+ // PushDeclContext here because that context is not necessarily
+ // lexically contained in the current context. Fortunately,
+ // scopes should work.
+
+#ifndef NDEBUG
+ Scope *Ancestor = S->getParent();
+ while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent();
+ assert(Ancestor->getEntity() == CurContext && "ancestor context mismatch");
+#endif
+
+ CurContext = D->getDeclContext();
+ S->setEntity(CurContext);
}
/// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an
-/// initializer for the declaration 'Dcl'.
+/// initializer for the out-of-line declaration 'Dcl'.
void Sema::ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl) {
- AdjustDeclIfTemplate(Dcl);
-
- Decl *D = Dcl.getAs<Decl>();
// If there is no declaration, there was an error parsing it.
- if (D == 0)
- return;
-
- // Check whether it is a declaration with a nested name specifier like
- // int foo::bar;
- if (!D->isOutOfLine())
- return;
+ Decl *D = Dcl.getAs<Decl>();
+ if (D == 0) return;
+ assert(D->isOutOfLine());
assert(S->getEntity() == D->getDeclContext() && "Context imbalance!");
- ExitDeclaratorContext(S);
+
+ Scope *Ancestor = S->getParent();
+ while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent();
+ CurContext = (DeclContext*) Ancestor->getEntity();
}
/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp
index d6fc887005..846d385e1e 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp
@@ -1,5 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// XFAIL: *
+
+// C++0x [basic.lookup.unqual]p14:
+// If a variable member of a namespace is defined outside of the
+// scope of its namespace then any name used in the definition of
+// the variable member (after the declarator-id) is looked up as if
+// the definition of the variable member occurred in its namespace.
namespace N {
struct S {};
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 454af5ef19..4e65b41e66 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -207,3 +207,16 @@ namespace test1 {
}
};
}
+
+// We still need to do lookup in the lexical scope, even if we push a
+// non-lexical scope.
+namespace test2 {
+ namespace ns {
+ int *count_ptr;
+ }
+ namespace {
+ int count = 0;
+ }
+
+ int *ns::count_ptr = &count;
+}
diff --git a/test/SemaCXX/qual-id-test.cpp b/test/SemaCXX/qual-id-test.cpp
index 856e42bd43..00dc662d06 100644
--- a/test/SemaCXX/qual-id-test.cpp
+++ b/test/SemaCXX/qual-id-test.cpp
@@ -137,4 +137,4 @@ struct a {
a a;
-int a::sa = a.a;
+int a::sa = a.a; // expected-error {{invalid use of nonstatic data member 'a'}}