Fix regression in r154844. If necessary, defer computing adjusted destructor

exception specifications in C++11 until after we've parsed the exception
specifications for nested classes.

llvm-svn: 155293
This commit is contained in:
Richard Smith 2012-04-21 18:42:51 +00:00
parent 2568bf3089
commit 84973e56e3
5 changed files with 79 additions and 18 deletions

View File

@ -331,6 +331,11 @@ public:
/// cycle detection at the end of the TU.
DelegatingCtorDeclsType DelegatingCtorDecls;
/// \brief All the destructors seen during a class definition that had their
/// exception spec computation delayed because it depended on an unparsed
/// exception spec.
SmallVector<CXXDestructorDecl*, 2> DelayedDestructorExceptionSpecs;
/// \brief All the overriding destructors seen during a class definition
/// (there could be multiple due to nested classes) that had their exception
/// spec checks delayed, plus the overridden destructor.
@ -3203,7 +3208,8 @@ public:
/// C++11 says that user-defined destructors with no exception spec get one
/// that looks as if the destructor was implicitly declared.
void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
CXXDestructorDecl *Destructor);
CXXDestructorDecl *Destructor,
bool WasDelayed = false);
/// \brief Declare all inherited constructors for the given class.
///
@ -4048,6 +4054,7 @@ public:
SourceLocation LBrac,
SourceLocation RBrac,
AttributeList *AttrList);
void ActOnFinishCXXMemberDecls();
void ActOnReenterTemplateScope(Scope *S, Decl *Template);
void ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D);

View File

@ -2369,6 +2369,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
SourceLocation SavedPrevTokLocation = PrevTokLocation;
ParseLexedAttributes(getCurrentClass());
ParseLexedMethodDeclarations(getCurrentClass());
// We've finished with all pending member declarations.
Actions.ActOnFinishCXXMemberDecls();
ParseLexedMemberInitializers(getCurrentClass());
ParseLexedMethodDefs(getCurrentClass());
PrevTokLocation = SavedPrevTokLocation;

View File

@ -9784,21 +9784,6 @@ void Sema::ActOnFields(Scope* S,
if (!Completed)
Record->completeDefinition();
// Now that the record is complete, do any delayed exception spec checks
// we were missing.
while (!DelayedDestructorExceptionSpecChecks.empty()) {
const CXXDestructorDecl *Dtor =
DelayedDestructorExceptionSpecChecks.back().first;
if (Dtor->getParent() != Record)
break;
assert(!Dtor->getParent()->isDependentType() &&
"Should not ever add destructors of templates into the list.");
CheckOverridingFunctionExceptionSpec(Dtor,
DelayedDestructorExceptionSpecChecks.back().second);
DelayedDestructorExceptionSpecChecks.pop_back();
}
} else {
ObjCIvarDecl **ClsFields =
reinterpret_cast<ObjCIvarDecl**>(RecFields.data());

View File

@ -7317,15 +7317,42 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
}
}
/// \brief Perform any semantic analysis which needs to be delayed until all
/// pending class member declarations have been parsed.
void Sema::ActOnFinishCXXMemberDecls() {
// Now we have parsed all exception specifications, determine the implicit
// exception specifications for destructors.
for (unsigned i = 0, e = DelayedDestructorExceptionSpecs.size();
i != e; ++i) {
CXXDestructorDecl *Dtor = DelayedDestructorExceptionSpecs[i];
AdjustDestructorExceptionSpec(Dtor->getParent(), Dtor, true);
}
DelayedDestructorExceptionSpecs.clear();
// Perform any deferred checking of exception specifications for virtual
// destructors.
for (unsigned i = 0, e = DelayedDestructorExceptionSpecChecks.size();
i != e; ++i) {
const CXXDestructorDecl *Dtor =
DelayedDestructorExceptionSpecChecks[i].first;
assert(!Dtor->getParent()->isDependentType() &&
"Should not ever add destructors of templates into the list.");
CheckOverridingFunctionExceptionSpec(Dtor,
DelayedDestructorExceptionSpecChecks[i].second);
}
DelayedDestructorExceptionSpecChecks.clear();
}
void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl,
CXXDestructorDecl *destructor) {
CXXDestructorDecl *destructor,
bool WasDelayed) {
// C++11 [class.dtor]p3:
// A declaration of a destructor that does not have an exception-
// specification is implicitly considered to have the same exception-
// specification as an implicit declaration.
const FunctionProtoType *dtorType = destructor->getType()->
getAs<FunctionProtoType>();
if (dtorType->hasExceptionSpec())
if (!WasDelayed && dtorType->hasExceptionSpec())
return;
ImplicitExceptionSpecification exceptSpec =
@ -7342,6 +7369,14 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl,
destructor->setType(ty);
// If we can't compute the exception specification for this destructor yet
// (because it depends on an exception specification which we have not parsed
// yet), make a note that we need to try again when the class is complete.
if (epi.ExceptionSpecType == EST_Delayed) {
assert(!WasDelayed && "couldn't compute destructor exception spec");
DelayedDestructorExceptionSpecs.push_back(destructor);
}
// FIXME: If the destructor has a body that could throw, and the newly created
// spec doesn't allow exceptions, we should emit a warning, because this
// change in behavior can break conforming C++03 programs at runtime.

View File

@ -54,3 +54,33 @@ namespace DefaultArgument {
} t; // expected-note {{has no default constructor}}
};
}
namespace ImplicitDtorExceptionSpec {
struct A {
virtual ~A();
struct Inner {
~Inner() throw();
};
Inner inner;
};
struct B {
virtual ~B() {} // expected-note {{here}}
};
struct C : B {
virtual ~C() {}
A a;
};
struct D : B {
~D(); // expected-error {{more lax than base}}
struct E {
~E();
struct F {
~F() throw(A);
} f;
} e;
};
}