From ce6b78128f7fde3b26b6cf66adc6c982cde90bb8 Mon Sep 17 00:00:00 2001 From: Gabor Marton Date: Wed, 8 May 2019 15:23:48 +0000 Subject: [PATCH] [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 --- clang/lib/AST/ASTImporter.cpp | 5 ++++ clang/lib/AST/ASTStructuralEquivalence.cpp | 48 +++++++++++++++++++----------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index da0d689..7ce2abe 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/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/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 567945c..bf084e3 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/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; -- 2.7.4