diff options
author | John McCall <rjmccall@apple.com> | 2009-12-19 09:28:58 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-12-19 09:28:58 +0000 |
commit | 1f4ee7bd2f4105a04811a06294e4654c6e4058c4 (patch) | |
tree | 1fef3d651a963463bac8e563ef1dcb8a7e9eeddc | |
parent | 4f469974b27e0da7768b1eb30078658f1f382a72 (diff) | |
download | bcm5719-llvm-1f4ee7bd2f4105a04811a06294e4654c6e4058c4.tar.gz bcm5719-llvm-1f4ee7bd2f4105a04811a06294e4654c6e4058c4.zip |
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.
llvm-svn: 91769
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 76 | ||||
-rw-r--r-- | clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp | 7 | ||||
-rw-r--r-- | clang/test/SemaCXX/nested-name-spec.cpp | 13 | ||||
-rw-r--r-- | clang/test/SemaCXX/qual-id-test.cpp | 2 |
5 files changed, 69 insertions, 37 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 5dd78f7b547..43c92456d29 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/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/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 565fce8b5f5..24534e74ee0 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/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/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp index d6fc8870050..846d385e1e5 100644 --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp +++ b/clang/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/clang/test/SemaCXX/nested-name-spec.cpp b/clang/test/SemaCXX/nested-name-spec.cpp index 454af5ef196..4e65b41e666 100644 --- a/clang/test/SemaCXX/nested-name-spec.cpp +++ b/clang/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/clang/test/SemaCXX/qual-id-test.cpp b/clang/test/SemaCXX/qual-id-test.cpp index 856e42bd434..00dc662d067 100644 --- a/clang/test/SemaCXX/qual-id-test.cpp +++ b/clang/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'}} |