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.

llvm-svn: 91771
This commit is contained in:
John McCall 2009-12-19 10:49:29 +00:00
parent 4d6d6137a0
commit 6df5fef637
8 changed files with 99 additions and 84 deletions

View 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,

View 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;
}

View 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

View 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,

View 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);
}

View 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

View 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

View 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