diff options
author | John McCall <rjmccall@apple.com> | 2009-12-19 10:49:29 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-12-19 10:49:29 +0000 |
commit | 7a1dc562d4ad59237ed9fe7e8cef56f9eaa7a26c (patch) | |
tree | f79a62b9cccc358dfa2866cbca2f1656b2a0d157 | |
parent | 0dd7ceb72cc369195d698ccc26c70ac0e56ab945 (diff) |
Refactor to remove more dependencies on PreDeclaratorDC. I seem to have made
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
-rw-r--r-- | include/clang/Parse/Action.h | 16 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 5 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 26 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 46 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 62 | ||||
-rw-r--r-- | test/CXX/temp/temp.spec/temp.explicit/p3.cpp | 14 |
8 files changed, 99 insertions, 84 deletions
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 92044a0d39..6c04ea4eee 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -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, diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index e47de506fd..2214797b8f 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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; } diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index b9314d2424..f1e639c295 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -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 diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 24101c6702..28993c7c5a 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 039691f122..2488c9f38f 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -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); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 4c2c658571..e408000fab 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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 diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 24534e74ee..674a4bd956 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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 diff --git a/test/CXX/temp/temp.spec/temp.explicit/p3.cpp b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp index 3abbe2625d..e30f046c2b 100644 --- a/test/CXX/temp/temp.spec/temp.explicit/p3.cpp +++ b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp @@ -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 |