]> granicus.if.org Git - clang/commitdiff
Refactor to remove more dependencies on PreDeclaratorDC. I seem to have made
authorJohn McCall <rjmccall@apple.com>
Sat, 19 Dec 2009 10:49:29 +0000 (10:49 +0000)
committerJohn McCall <rjmccall@apple.com>
Sat, 19 Dec 2009 10:49:29 +0000 (10:49 +0000)
the redeclaration problems in the [temp.explicit]p3 testcase worse, but I can
live with that;  they'll need to be fixed more holistically anyhow.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91771 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Parse/Action.h
include/clang/Parse/Parser.h
lib/Parse/ParseCXXInlineMethods.cpp
lib/Sema/Sema.h
lib/Sema/SemaCXXScopeSpec.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
test/CXX/temp/temp.spec/temp.explicit/p3.cpp

index 92044a0d39759eff07e6af25fa1fd5c239ea4fa9..6c04ea4eee41a3ae1056ef38e1a0cc070129c27a 100644 (file)
@@ -1351,6 +1351,14 @@ public:
   virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template) {
   }
 
+  /// ActOnStartDelayedMemberDeclarations - We have completed parsing
+  /// a C++ class, and we are about to start parsing any parts of
+  /// member declarations that could not be parsed earlier.  Enter
+  /// the appropriate record scope.
+  virtual void ActOnStartDelayedMemberDeclarations(Scope *S,
+                                                   DeclPtrTy Record) {
+  }
+
   /// ActOnStartDelayedCXXMethodDeclaration - We have completed
   /// parsing a top-level (non-nested) C++ class, and we are now
   /// parsing those parts of the given Method declaration that could
@@ -1381,6 +1389,14 @@ public:
                                                       DeclPtrTy Method) {
   }
 
+  /// ActOnFinishDelayedMemberDeclarations - We have finished parsing
+  /// a C++ class, and we are about to start parsing any parts of
+  /// member declarations that could not be parsed earlier.  Enter the
+  /// appropriate record scope.
+  virtual void ActOnFinishDelayedMemberDeclarations(Scope *S,
+                                                    DeclPtrTy Record) {
+  }
+
   /// ActOnStaticAssertDeclaration - Parse a C++0x static_assert declaration.
   virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
                                                  ExprArg AssertExpr,
index e47de506fd1f31e7fe7ca1d31dfbe07166d2c517..2214797b8f7b53ad166c68390f566df153639205 100644 (file)
@@ -1243,10 +1243,7 @@ private:
       CreatedScope = true;
       P.EnterScope(0); // Not a decl scope.
 
-      if (P.Actions.ActOnCXXEnterDeclaratorScope(P.CurScope, SS))
-        SS.setScopeRep(0);
-      
-      if (!SS.isInvalid())
+      if (!P.Actions.ActOnCXXEnterDeclaratorScope(P.CurScope, SS))
         EnteredScope = true;
     }
 
index b9314d242442d8e327e1eb921388c73175892c94..f1e639c2957dd3474598bd8aff57f96e5e034cbd 100644 (file)
@@ -95,9 +95,12 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
   if (HasTemplateScope)
     Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate);
 
+  // The current scope is still active if we're the top-level class.
+  // Otherwise we'll need to push and enter a new scope.
   bool HasClassScope = !Class.TopLevelClass;
-  ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
-                        HasClassScope);
+  ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope);
+  if (HasClassScope)
+    Actions.ActOnStartDelayedMemberDeclarations(CurScope, Class.TagOrTemplate);
 
   for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) {
     LateParsedMethodDeclaration &LM = Class.MethodDecls.front();
@@ -148,6 +151,9 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
 
   for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
     ParseLexedMethodDeclarations(*Class.NestedClasses[I]);
+
+  if (HasClassScope)
+    Actions.ActOnFinishDelayedMemberDeclarations(CurScope, Class.TagOrTemplate);
 }
 
 /// ParseLexedMethodDefs - We finished parsing the member specification of a top
index 24101c67029b78706f1e4ce97baed8fd1c7f751a..28993c7c5a6537c42ba5c4daecf9d97d9c66cc00 100644 (file)
@@ -2193,11 +2193,15 @@ public:
                                                  SourceLocation RBrac);
 
   virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template);
+  virtual void ActOnStartDelayedMemberDeclarations(Scope *S,
+                                                   DeclPtrTy Record);
   virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S,
                                                      DeclPtrTy Method);
   virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param);
   virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S,
                                                       DeclPtrTy Method);
+  virtual void ActOnFinishDelayedMemberDeclarations(Scope *S,
+                                                    DeclPtrTy Record);
 
   virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
                                                  ExprArg AssertExpr,
index 039691f122f97a32845d06de7e184857ed59555d..2488c9f38f3c4ec4249179bb1d4fa82e76c37e32 100644 (file)
@@ -605,15 +605,18 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
 /// The 'SS' should be a non-empty valid CXXScopeSpec.
 bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
   assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
-  if (DeclContext *DC = computeDeclContext(SS, true)) {
-    // Before we enter a declarator's context, we need to make sure that
-    // it is a complete declaration context.
-    if (!DC->isDependentContext() && RequireCompleteDeclContext(SS))
-      return true;
-      
-    EnterDeclaratorContext(S, DC);
-  }
-  
+
+  if (SS.isInvalid()) return true;
+
+  DeclContext *DC = computeDeclContext(SS, true);
+  if (!DC) return true;
+
+  // Before we enter a declarator's context, we need to make sure that
+  // it is a complete declaration context.
+  if (!DC->isDependentContext() && RequireCompleteDeclContext(SS))
+    return true;
+    
+  EnterDeclaratorContext(S, DC);
   return false;
 }
 
@@ -626,6 +629,7 @@ void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
   assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
   if (SS.isInvalid())
     return;
-  if (computeDeclContext(SS, true))
-    ExitDeclaratorContext(S);
+  assert(!SS.isInvalid() && computeDeclContext(SS, true) &&
+         "exiting declarator scope we never really entered");
+  ExitDeclaratorContext(S);
 }
index 4c2c658571c7478f9ff0c2f7039a21b702631d66..e408000fab591d0055d7933a6ca3188098c65d5c 100644 (file)
@@ -321,23 +321,47 @@ void Sema::PopDeclContext() {
 
 /// EnterDeclaratorContext - Used when we must lookup names in the context
 /// of a declarator's nested name specifier.
+///
 void Sema::EnterDeclaratorContext(Scope *S, DeclContext *DC) {
-  assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");
-  PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity());
+  // 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,
+  // the containing scope should have the appropriate information.
+
+  assert(!S->getEntity() && "scope already has entity");
+
+#ifndef NDEBUG
+  Scope *Ancestor = S->getParent();
+  while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent();
+  assert(Ancestor->getEntity() == CurContext && "ancestor context mismatch");
+#endif
+
   CurContext = DC;
-  assert(CurContext && "No context?");
-  S->setEntity(CurContext);
+  S->setEntity(DC);
 }
 
 void Sema::ExitDeclaratorContext(Scope *S) {
-  S->setEntity(PreDeclaratorDC);
-  PreDeclaratorDC = 0;
+  assert(S->getEntity() == CurContext && "Context imbalance!");
 
-  // 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?");
+  // Switch back to the lexical context.  The safety of this is
+  // enforced by an assert in EnterDeclaratorContext.
+  Scope *Ancestor = S->getParent();
+  while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent();
+  CurContext = (DeclContext*) Ancestor->getEntity();
+
+  // We don't need to do anything with the scope, which is going to
+  // disappear.
 }
 
 /// \brief Determine whether we allow overloading of the function
index 24534e74ee00f61b84b8287ca79d2871d1064017..674a4bd9560d38ccbb8c6450a7db0487c900cab9 100644 (file)
@@ -2266,6 +2266,18 @@ void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
   }
 }
 
+void Sema::ActOnStartDelayedMemberDeclarations(Scope *S, DeclPtrTy RecordD) {
+  if (!RecordD) return;
+  AdjustDeclIfTemplate(RecordD);
+  CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordD.getAs<Decl>());
+  PushDeclContext(S, Record);
+}
+
+void Sema::ActOnFinishDelayedMemberDeclarations(Scope *S, DeclPtrTy RecordD) {
+  if (!RecordD) return;
+  PopDeclContext();
+}
+
 /// ActOnStartDelayedCXXMethodDeclaration - We have completed
 /// parsing a top-level (non-nested) C++ class, and we are now
 /// parsing those parts of the given Method declaration that could
@@ -2275,18 +2287,6 @@ void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
 /// name. However, it should not bring the parameters into scope;
 /// that will be performed by ActOnDelayedCXXMethodParameter.
 void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
-  if (!MethodD)
-    return;
-
-  AdjustDeclIfTemplate(MethodD);
-
-  CXXScopeSpec SS;
-  FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>());
-  QualType ClassTy
-    = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
-  SS.setScopeRep(
-    NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
-  ActOnCXXEnterDeclaratorScope(S, SS);
 }
 
 /// ActOnDelayedCXXMethodParameter - We've already started a delayed
@@ -2323,12 +2323,6 @@ void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
   AdjustDeclIfTemplate(MethodD);
 
   FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>());
-  CXXScopeSpec SS;
-  QualType ClassTy
-    = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
-  SS.setScopeRep(
-    NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
-  ActOnCXXExitDeclaratorScope(S, SS);
 
   // Now that we have our default arguments, check the constructor
   // again. It could produce additional diagnostics or affect whether
@@ -5544,31 +5538,7 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) {
   // 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);
+  EnterDeclaratorContext(S, D->getDeclContext());
 }
 
 /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an
@@ -5579,11 +5549,7 @@ void Sema::ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl) {
   if (D == 0) return;
 
   assert(D->isOutOfLine());
-  assert(S->getEntity() == D->getDeclContext() && "Context imbalance!");
-  
-  Scope *Ancestor = S->getParent();
-  while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent();
-  CurContext = (DeclContext*) Ancestor->getEntity();
+  ExitDeclaratorContext(S);
 }
 
 /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
index 3abbe2625d19fddc1b63afe4410557874ebbaa04..e30f046c2bd1a4470c4fb4f029da8aa4ee295080 100644 (file)
@@ -8,14 +8,12 @@ template void f0(int); // okay
 // A definition of the class or class template containing a member function 
 // template shall be in scope at the point of the explicit instantiation of 
 // the member function template.
-struct X0; // expected-note 2{{forward declaration}}
-template<typename> struct X1; // expected-note 5{{declared here}}
+struct X0; // expected-note 3{{forward declaration}}
+template<typename> struct X1; // expected-note 8{{declared here}}
 
 // FIXME: Repeated diagnostics here!
-template void X0::f0<int>(int); // expected-error 2{{incomplete type}} \
-  // expected-error{{does not refer}}
-template void X1<int>::f0<int>(int); // expected-error 2{{implicit instantiation of undefined template}} \
-  // expected-error{{does not refer}}
+template void X0::f0<int>(int); // expected-error 3{{incomplete type}} // expected-error{{invalid token after top level declarator}}
+template void X1<int>::f0<int>(int); // expected-error 3{{implicit instantiation of undefined template}} // expected-error{{invalid token after top level declarator}}
 
 // A definition of a class template or class member template shall be in scope 
 // at the point of the explicit instantiation of the class template or class 
@@ -35,10 +33,10 @@ template struct X2<int>::Inner<float>; // expected-error{{explicit instantiation
 // A definition of a class template shall be in scope at the point of an 
 // explicit instantiation of a member function or a static data member of the
 // class template.
-template void X1<int>::f1(int); // expected-error{{undefined template}} \
+template void X1<int>::f1(int); // expected-error 2{{undefined template}} \
                                 // expected-error{{does not refer}}
 
-template int X1<int>::member; // expected-error{{undefined template}} \
+template int X1<int>::member; // expected-error 2{{undefined template}} \
                               // expected-error{{does not refer}}
 
 // A definition of a member class of a class template shall be in scope at the