diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2009-06-17 22:50:06 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2009-06-17 22:50:06 +0000 |
commit | 0ffd9ffb633ca4886c7db4dd12dc36bdad3d797c (patch) | |
tree | 5eb5663995e1352ad9eb66794b1586af3d512488 | |
parent | f5cecfbdcd20be224861f9e67c5973a9a2b61512 (diff) |
Implement correct name lookup inside an initializer of a C++ class static data member.
Fixes "test/CXX/basic/basic.lookup/basic.lookup.unqual/p13.cpp" test case.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73652 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Parse/Action.h | 13 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 11 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 55 | ||||
-rw-r--r-- | test/CXX/basic/basic.lookup/basic.lookup.unqual/p13.cpp | 1 |
5 files changed, 86 insertions, 1 deletions
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index f1207e4f0f..ba480c5b7c 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -248,6 +248,19 @@ public: virtual void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { } + /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an + /// initializer for the declaration 'Dcl'. + /// 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. + virtual void ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) { + } + + /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an + /// initializer for the declaration 'Dcl'. + virtual void ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl) { + } + /// ActOnDeclarator - This callback is invoked when a declarator is parsed and /// 'Init' specifies the initializer if any. This is for things like: /// "int X = 4" or "typedef int foo". diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 9073c6dbd1..efabf3a7c6 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -402,7 +402,14 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D) { SourceLocation DelLoc = ConsumeToken(); Actions.SetDeclDeleted(ThisDecl, DelLoc); } else { + if (getLang().CPlusPlus) + Actions.ActOnCXXEnterDeclInitializer(CurScope, ThisDecl); + OwningExprResult Init(ParseInitializer()); + + if (getLang().CPlusPlus) + Actions.ActOnCXXExitDeclInitializer(CurScope, ThisDecl); + if (Init.isInvalid()) { SkipUntil(tok::semi, true, true); return DeclPtrTy(); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index bbfab88a3f..579fe37feb 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1721,6 +1721,17 @@ public: /// defining scope. virtual void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an + /// initializer for the declaration 'Dcl'. + /// 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. + virtual void ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl); + + /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an + /// initializer for the declaration 'Dcl'. + virtual void ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl); + // ParseObjCStringLiteral - Parse Objective-C string literals. virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ExprTy **Strings, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index dcf11c54ac..bb1f50f104 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2828,3 +2828,58 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, return false; } + +/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an +/// initializer for the declaration 'Dcl'. +/// 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) { + 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. + + assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?"); + PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity()); + CurContext = D->getDeclContext(); + assert(CurContext && "No context?"); + S->setEntity(CurContext); +} + +/// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an +/// initializer for the declaration 'Dcl'. +void Sema::ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy 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; + + assert(S->getEntity() == D->getDeclContext() && "Context imbalance!"); + S->setEntity(PreDeclaratorDC); + PreDeclaratorDC = 0; + + // Reset CurContext to the nearest enclosing context. + while (!S->getEntity() && S->getParent()) + S = S->getParent(); + CurContext = static_cast<DeclContext*>(S->getEntity()); + assert(CurContext && "No context?"); +} diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p13.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p13.cpp index 037d590f4e..afd6623605 100644 --- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p13.cpp +++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p13.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -fsyntax-only -verify %s -// XFAIL struct S { static const int f0 = 0; |