diff options
author | Gabor Marton <gabor.marton@ericsson.com> | 2019-07-01 12:44:39 +0000 |
---|---|---|
committer | Gabor Marton <gabor.marton@ericsson.com> | 2019-07-01 12:44:39 +0000 |
commit | c5dc3be894b5da943a897afaf80d27c688417425 (patch) | |
tree | e648742dee3907fca0cfbfc70feacf9baa797585 /unittests/AST | |
parent | 7411e94aa844d5bfc8cedab8dfc70e4247bbeed9 (diff) | |
download | clang-c5dc3be894b5da943a897afaf80d27c688417425.tar.gz |
[ASTImporter] Propagate error from ImportDeclContext
Summary:
During analysis of one project we failed to import one
CXXDestructorDecl. But since we did not propagate the error in
importDeclContext we had a CXXRecordDecl without a destructor. Then the
analyzer engine had a CallEvent where the nonexistent dtor was requested
(crash).
Solution is to propagate the errors we have during importing a
DeclContext.
Reviewers: a_sidorin, a.sidorin, shafik
Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63603
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@364752 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/AST')
-rw-r--r-- | unittests/AST/ASTImporterTest.cpp | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/unittests/AST/ASTImporterTest.cpp b/unittests/AST/ASTImporterTest.cpp index 41a041f101..215dc10a39 100644 --- a/unittests/AST/ASTImporterTest.cpp +++ b/unittests/AST/ASTImporterTest.cpp @@ -4738,6 +4738,93 @@ TEST_P(ErrorHandlingTest, ErrorHappensAfterNodeIsCreatedAndLinked) { EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct); } +// An error should be set for a class if we cannot import one member. +TEST_P(ErrorHandlingTest, ErrorIsPropagatedFromMemberToClass) { + TranslationUnitDecl *FromTU = getTuDecl( + std::string(R"( + class X { + void f() { )") + ErroneousStmt + R"( } // This member has the error + // during import. + void ok(); // The error should not prevent importing this. + }; // An error will be set for X too. + )", + Lang_CXX); + auto *FromX = FirstDeclMatcher<CXXRecordDecl>().match( + FromTU, cxxRecordDecl(hasName("X"))); + CXXRecordDecl *ImportedX = Import(FromX, Lang_CXX); + + // An error is set for X. + EXPECT_FALSE(ImportedX); + ASTImporter *Importer = findFromTU(FromX)->Importer.get(); + Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromX); + ASSERT_TRUE(OptErr); + EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct); + + // An error is set for f(). + auto *FromF = FirstDeclMatcher<CXXMethodDecl>().match( + FromTU, cxxMethodDecl(hasName("f"))); + OptErr = Importer->getImportDeclErrorIfAny(FromF); + ASSERT_TRUE(OptErr); + EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct); + // And any subsequent import should fail. + CXXMethodDecl *ImportedF = Import(FromF, Lang_CXX); + EXPECT_FALSE(ImportedF); + + // There is no error set for ok(). + auto *FromOK = FirstDeclMatcher<CXXMethodDecl>().match( + FromTU, cxxMethodDecl(hasName("ok"))); + OptErr = Importer->getImportDeclErrorIfAny(FromOK); + EXPECT_FALSE(OptErr); + // And we should be able to import. + CXXMethodDecl *ImportedOK = Import(FromOK, Lang_CXX); + EXPECT_TRUE(ImportedOK); + + // Unwary clients may access X even if the error is set, so, at least make + // sure the class is set to be complete. + CXXRecordDecl *ToX = cast<CXXRecordDecl>(ImportedOK->getDeclContext()); + EXPECT_TRUE(ToX->isCompleteDefinition()); +} + +TEST_P(ErrorHandlingTest, ErrorIsNotPropagatedFromMemberToNamespace) { + TranslationUnitDecl *FromTU = getTuDecl( + std::string(R"( + namespace X { + void f() { )") + ErroneousStmt + R"( } // This member has the error + // during import. + void ok(); // The error should not prevent importing this. + }; // An error will be set for X too. + )", + Lang_CXX); + auto *FromX = FirstDeclMatcher<NamespaceDecl>().match( + FromTU, namespaceDecl(hasName("X"))); + NamespaceDecl *ImportedX = Import(FromX, Lang_CXX); + + // There is no error set for X. + EXPECT_TRUE(ImportedX); + ASTImporter *Importer = findFromTU(FromX)->Importer.get(); + Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromX); + ASSERT_FALSE(OptErr); + + // An error is set for f(). + auto *FromF = FirstDeclMatcher<FunctionDecl>().match( + FromTU, functionDecl(hasName("f"))); + OptErr = Importer->getImportDeclErrorIfAny(FromF); + ASSERT_TRUE(OptErr); + EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct); + // And any subsequent import should fail. + FunctionDecl *ImportedF = Import(FromF, Lang_CXX); + EXPECT_FALSE(ImportedF); + + // There is no error set for ok(). + auto *FromOK = FirstDeclMatcher<FunctionDecl>().match( + FromTU, functionDecl(hasName("ok"))); + OptErr = Importer->getImportDeclErrorIfAny(FromOK); + EXPECT_FALSE(OptErr); + // And we should be able to import. + FunctionDecl *ImportedOK = Import(FromOK, Lang_CXX); + EXPECT_TRUE(ImportedOK); +} + INSTANTIATE_TEST_CASE_P(ParameterizedTests, ErrorHandlingTest, DefaultTestValuesForRunOptions, ); |