mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-05 12:51:16 +00:00
Delay checking overrides for exception specifications if the overridden
specification has not yet been parsed. llvm-svn: 222603
This commit is contained in:
parent
54166af611
commit
88f45490a0
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
15
clang/test/CXX/except/except.spec/p5-delayed.cpp
Normal file
15
clang/test/CXX/except/except.spec/p5-delayed.cpp
Normal 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}}
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue
Block a user