[ASTImporter] Fix inequivalence of unresolved exception spec

Summary:
Structural equivalence of methods can falsely report false when the
exception specifier is unresolved (i.e unevaluated or not instantiated).

(This caused one assertion during bitcoin ctu-analysis.)

Reviewers: a_sidorin, shafik, a.sidorin

Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D61424

llvm-svn: 360261
This commit is contained in:
Gabor Marton 2019-05-08 15:23:48 +00:00
parent 9fd02a71a3
commit ce6b78128f
2 changed files with 36 additions and 17 deletions

View File

@ -3130,6 +3130,11 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
auto *Recent = const_cast<FunctionDecl *>(
FoundByLookup->getMostRecentDecl());
ToFunction->setPreviousDecl(Recent);
// FIXME Probably we should merge exception specifications. E.g. In the
// "To" context the existing function may have exception specification with
// noexcept-unevaluated, while the newly imported function may have an
// evaluated noexcept. A call to adjustExceptionSpec() on the imported
// decl and its redeclarations may be required.
}
// Import Ctor initializers.

View File

@ -322,6 +322,36 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return true;
}
/// Check the equivalence of exception specifications.
static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context,
const FunctionProtoType *Proto1,
const FunctionProtoType *Proto2) {
auto Spec1 = Proto1->getExceptionSpecType();
auto Spec2 = Proto2->getExceptionSpecType();
if (isUnresolvedExceptionSpec(Spec1) || isUnresolvedExceptionSpec(Spec2))
return true;
if (Spec1 != Spec2)
return false;
if (Spec1 == EST_Dynamic) {
if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
return false;
for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I),
Proto2->getExceptionType(I)))
return false;
}
} else if (isComputedNoexcept(Spec1)) {
if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(),
Proto2->getNoexceptExpr()))
return false;
}
return true;
}
/// Determine structural equivalence of two types.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
QualType T1, QualType T2) {
@ -536,24 +566,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
cast<FunctionProtoType>(OrigT1.getDesugaredType(Context.FromCtx));
const auto *OrigProto2 =
cast<FunctionProtoType>(OrigT2.getDesugaredType(Context.ToCtx));
auto Spec1 = OrigProto1->getExceptionSpecType();
auto Spec2 = OrigProto2->getExceptionSpecType();
if (Spec1 != Spec2)
if (!IsEquivalentExceptionSpec(Context, OrigProto1, OrigProto2))
return false;
if (Spec1 == EST_Dynamic) {
if (OrigProto1->getNumExceptions() != OrigProto2->getNumExceptions())
return false;
for (unsigned I = 0, N = OrigProto1->getNumExceptions(); I != N; ++I) {
if (!IsStructurallyEquivalent(Context, OrigProto1->getExceptionType(I),
OrigProto2->getExceptionType(I)))
return false;
}
} else if (isComputedNoexcept(Spec1)) {
if (!IsStructurallyEquivalent(Context, OrigProto1->getNoexceptExpr(),
OrigProto2->getNoexceptExpr()))
return false;
}
// Fall through to check the bits common with FunctionNoProtoType.
LLVM_FALLTHROUGH;