From: Gabor Marton Date: Wed, 8 May 2019 15:23:48 +0000 (+0000) Subject: [ASTImporter] Fix inequivalence of unresolved exception spec X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1cba198da9e5c6a3f9763cf2fbe642508a68c922;p=clang [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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@360261 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index da0d68900a..7ce2abee6c 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -3130,6 +3130,11 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { auto *Recent = const_cast( 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. diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp index 567945c16c..bf084e325c 100644 --- a/lib/AST/ASTStructuralEquivalence.cpp +++ b/lib/AST/ASTStructuralEquivalence.cpp @@ -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(OrigT1.getDesugaredType(Context.FromCtx)); const auto *OrigProto2 = cast(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;