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:
parent
2568bf3089
commit
84973e56e3
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue