]> granicus.if.org Git - clang/commitdiff
Implement correct name lookup inside an initializer of a C++ class static data member.
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Wed, 17 Jun 2009 22:50:06 +0000 (22:50 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Wed, 17 Jun 2009 22:50:06 +0000 (22:50 +0000)
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

include/clang/Parse/Action.h
lib/Parse/ParseDecl.cpp
lib/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
test/CXX/basic/basic.lookup/basic.lookup.unqual/p13.cpp

index f1207e4f0f73e1c87a443f2f56ec480336ea0e99..ba480c5b7c4ac9006597aef113f83186d4da1321 100644 (file)
@@ -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".
index 9073c6dbd19306ab13d15faf103160f7229326e2..efabf3a7c6da5d50c02ec7f0c8f55b0eb1ce069f 100644 (file)
@@ -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();
index bbfab88a3fd3637051a8689663c4127d93a7ee4a..579fe37feb56757e92b62961ff1638b2d32881a2 100644 (file)
@@ -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,
index dcf11c54acf5e53c2af5d14d2d92f03dd908a9f6..bb1f50f104b7eda52a9328367d3bca6f17375e30 100644 (file)
@@ -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?");
+}
index 037d590f4ebc5b3cc5136b040b16027a9d2df394..afd66236057211d40fef9bf2495f99c6d8e2222a 100644 (file)
@@ -1,5 +1,4 @@
 // RUN: clang-cc -fsyntax-only -verify %s
-// XFAIL
 
 struct S {
   static const int f0 = 0;