зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
0dd7ceb72c
Коммит
7a1dc562d4
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче