Delay checking overrides for exception specifications if the overridden

specification has not yet been parsed.

llvm-svn: 222603
This commit is contained in:
Richard Smith 2014-11-22 03:09:05 +00:00
parent 54166af611
commit 88f45490a0
5 changed files with 42 additions and 27 deletions

View File

@ -458,12 +458,11 @@ public:
/// cycle detection at the end of the TU.
DelegatingCtorDeclsType DelegatingCtorDecls;
/// \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.
SmallVector<std::pair<const CXXDestructorDecl*,
const CXXDestructorDecl*>, 2>
DelayedDestructorExceptionSpecChecks;
/// \brief All the overriding functions seen during a class definition
/// that had their exception spec checks delayed, plus the overridden
/// function.
SmallVector<std::pair<const CXXMethodDecl*, const CXXMethodDecl*>, 2>
DelayedExceptionSpecChecks;
/// \brief All the members seen during a class definition which were both
/// explicitly defaulted and had explicitly-specified exception

View File

@ -680,7 +680,7 @@ void Sema::ActOnEndOfTranslationUnit() {
// All delayed member exception specs should be checked or we end up accepting
// incompatible declarations.
assert(DelayedDefaultedMemberExceptionSpecs.empty());
assert(DelayedDestructorExceptionSpecChecks.empty());
assert(DelayedExceptionSpecChecks.empty());
// Remove file scoped decls that turned out to be used.
UnusedFileScopedDecls.erase(

View File

@ -5340,27 +5340,21 @@ void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
}
void Sema::CheckDelayedMemberExceptionSpecs() {
SmallVector<std::pair<const CXXDestructorDecl *, const CXXDestructorDecl *>,
2> Checks;
SmallVector<std::pair<CXXMethodDecl *, const FunctionProtoType *>, 2> Specs;
decltype(DelayedExceptionSpecChecks) Checks;
decltype(DelayedDefaultedMemberExceptionSpecs) Specs;
std::swap(Checks, DelayedDestructorExceptionSpecChecks);
std::swap(Checks, DelayedExceptionSpecChecks);
std::swap(Specs, DelayedDefaultedMemberExceptionSpecs);
// Perform any deferred checking of exception specifications for virtual
// destructors.
for (unsigned i = 0, e = Checks.size(); i != e; ++i) {
const CXXDestructorDecl *Dtor = Checks[i].first;
assert(!Dtor->getParent()->isDependentType() &&
"Should not ever add destructors of templates into the list.");
CheckOverridingFunctionExceptionSpec(Dtor, Checks[i].second);
}
for (auto &Check : Checks)
CheckOverridingFunctionExceptionSpec(Check.first, Check.second);
// Check that any explicitly-defaulted methods have exception specifications
// compatible with their implicit exception specifications.
for (unsigned I = 0, N = Specs.size(); I != N; ++I)
CheckExplicitlyDefaultedMemberExceptionSpec(Specs[I].first,
Specs[I].second);
for (auto &Spec : Specs)
CheckExplicitlyDefaultedMemberExceptionSpec(Spec.first, Spec.second);
}
namespace {
@ -9298,7 +9292,7 @@ void Sema::ActOnFinishCXXMemberDecls() {
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(CurContext)) {
if (Record->isInvalidDecl()) {
DelayedDefaultedMemberExceptionSpecs.clear();
DelayedDestructorExceptionSpecChecks.clear();
DelayedExceptionSpecChecks.clear();
return;
}
}

View File

@ -801,6 +801,11 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
// If the new exception specification hasn't been parsed yet, skip the check.
// We'll get called again once it's been parsed.
if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
EST_Unparsed)
return false;
if (getLangOpts().CPlusPlus11 && isa<CXXDestructorDecl>(New)) {
// Don't check uninstantiated template destructors at all. We can only
// synthesize correct specs after the template is instantiated.
@ -809,16 +814,18 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
if (New->getParent()->isBeingDefined()) {
// The destructor might be updated once the definition is finished. So
// remember it and check later.
DelayedDestructorExceptionSpecChecks.push_back(std::make_pair(
cast<CXXDestructorDecl>(New), cast<CXXDestructorDecl>(Old)));
DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old));
return false;
}
}
// If the exception specification hasn't been parsed yet, skip the check.
// We'll get called again once it's been parsed.
if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
EST_Unparsed)
// If the old exception specification hasn't been parsed yet, remember that
// we need to perform this check when we get to the end of the outermost
// lexically-surrounding class.
if (Old->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
EST_Unparsed) {
DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old));
return false;
}
unsigned DiagID = diag::err_override_exception_spec;
if (getLangOpts().MicrosoftExt)
DiagID = diag::ext_override_exception_spec;

View File

@ -0,0 +1,15 @@
// RUN: %clang_cc1 -std=c++11 -verify %s -fexceptions -fcxx-exceptions
struct A { struct X { virtual ~X() throw(Y); }; struct Y : X {}; };
struct B { struct X { virtual void f() throw(Y); }; struct Y : X { void f() throw(Y); }; };
struct C { struct X { virtual void f() throw(Y); }; struct Y : X { void f() throw(); }; };
struct D { struct X { virtual void f() throw(Y); }; struct Y : X { void f() noexcept; }; };
struct E { struct Y; struct X { virtual Y &operator=(const Y&) throw(Y); }; struct Y : X {}; };
struct F {
struct X {
virtual void f() throw(Y); // expected-note {{here}}
};
struct Y : X {
void f() throw(int); // expected-error {{more lax}}
};
};