[ASTImporter] Propagate errors during import of overridden methods.

Summary:
If importing overridden methods fails for a method it can be seen
incorrectly as non-virtual. To avoid this inconsistency the method
is marked with import error to avoid later use of it.

Reviewers: martong, a.sidorin, shafik, a_sidorin

Reviewed By: martong, shafik

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

Tags: #clang

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

llvm-svn: 370457
This commit is contained in:
Balazs Keri 2019-08-30 10:12:14 +00:00
parent 6381b143f6
commit b4fd7d4258
2 changed files with 55 additions and 5 deletions

View File

@ -639,7 +639,8 @@ namespace clang {
return ImportArrayChecked(InContainer.begin(), InContainer.end(), Obegin);
}
void ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod);
Error ImportOverriddenMethods(CXXMethodDecl *ToMethod,
CXXMethodDecl *FromMethod);
Expected<FunctionDecl *> FindFunctionTemplateSpecialization(
FunctionDecl *FromFD);
@ -3370,7 +3371,9 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
ImportOverrides(cast<CXXMethodDecl>(ToFunction), FromCXXMethod);
if (Error Err = ImportOverriddenMethods(cast<CXXMethodDecl>(ToFunction),
FromCXXMethod))
return std::move(Err);
// Import the rest of the chain. I.e. import all subsequent declarations.
for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) {
@ -7804,15 +7807,18 @@ ExpectedStmt ASTNodeImporter::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
*ToTypeOrErr, *ToExprOperandOrErr, *ToSourceRangeOrErr);
}
void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod,
CXXMethodDecl *FromMethod) {
Error ASTNodeImporter::ImportOverriddenMethods(CXXMethodDecl *ToMethod,
CXXMethodDecl *FromMethod) {
Error ImportErrors = Error::success();
for (auto *FromOverriddenMethod : FromMethod->overridden_methods()) {
if (auto ImportedOrErr = import(FromOverriddenMethod))
ToMethod->getCanonicalDecl()->addOverriddenMethod(cast<CXXMethodDecl>(
(*ImportedOrErr)->getCanonicalDecl()));
else
consumeError(ImportedOrErr.takeError());
ImportErrors =
joinErrors(std::move(ImportErrors), ImportedOrErr.takeError());
}
return ImportErrors;
}
ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,

View File

@ -5183,6 +5183,50 @@ TEST_P(ErrorHandlingTest,
}
}
TEST_P(ErrorHandlingTest, ImportOfOverriddenMethods) {
auto MatchFooA =
functionDecl(hasName("foo"), hasAncestor(cxxRecordDecl(hasName("A"))));
auto MatchFooB =
functionDecl(hasName("foo"), hasAncestor(cxxRecordDecl(hasName("B"))));
auto MatchFooC =
functionDecl(hasName("foo"), hasAncestor(cxxRecordDecl(hasName("C"))));
// Provoke import of a method that has overridden methods with import error.
TranslationUnitDecl *FromTU = getTuDecl(std::string(R"(
struct C;
struct A {
virtual void foo();
void f1(C *);
};
void A::foo() {
)") + ErroneousStmt + R"(
}
struct B : public A {
void foo() override;
};
struct C : public B {
void foo() override;
};
)",
Lang_CXX11);
auto *FromFooA = FirstDeclMatcher<FunctionDecl>().match(FromTU, MatchFooA);
auto *FromFooB = FirstDeclMatcher<FunctionDecl>().match(FromTU, MatchFooB);
auto *FromFooC = FirstDeclMatcher<FunctionDecl>().match(FromTU, MatchFooC);
EXPECT_FALSE(Import(FromFooA, Lang_CXX11));
ASTImporter *Importer = findFromTU(FromFooA)->Importer.get();
auto CheckError = [&Importer](Decl *FromD) {
Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromD);
ASSERT_TRUE(OptErr);
EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
};
CheckError(FromFooA);
EXPECT_FALSE(Import(FromFooB, Lang_CXX11));
CheckError(FromFooB);
EXPECT_FALSE(Import(FromFooC, Lang_CXX11));
CheckError(FromFooC);
}
TEST_P(ASTImporterOptionSpecificTestBase, LambdaInFunctionBody) {
Decl *FromTU = getTuDecl(
R"(