[PATCH] D63603: [ASTImporter] Propagate error from ImportDeclContext

2019-07-01 Thread Gabor Marton via Phabricator via cfe-commits
martong added a comment.

Jenkins is green: 
http://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake/29802/


Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63603/new/

https://reviews.llvm.org/D63603



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D63603: [ASTImporter] Propagate error from ImportDeclContext

2019-07-01 Thread Gabor Marton via Phabricator via cfe-commits
martong added a comment.

@shafik I've been looking for any lldb regression in our Mac machine, could not 
find any. Now I am looking at 
http://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake/ . I don't expect 
regression because here we changed logic about the error handling only, so I'd 
expect to have regression only if we had testcases in lldb for erroneous cases, 
but apparently there are no such tests.


Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63603/new/

https://reviews.llvm.org/D63603



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D63603: [ASTImporter] Propagate error from ImportDeclContext

2019-07-01 Thread Gabor Marton via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL364752: [ASTImporter] Propagate error from ImportDeclContext 
(authored by martong, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D63603?vs=206250&id=207274#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63603/new/

https://reviews.llvm.org/D63603

Files:
  cfe/trunk/lib/AST/ASTImporter.cpp
  cfe/trunk/unittests/AST/ASTImporterTest.cpp

Index: cfe/trunk/lib/AST/ASTImporter.cpp
===
--- cfe/trunk/lib/AST/ASTImporter.cpp
+++ cfe/trunk/lib/AST/ASTImporter.cpp
@@ -57,6 +57,7 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Casting.h"
@@ -1631,16 +1632,32 @@
 auto ToDCOrErr = Importer.ImportContext(FromDC);
 return ToDCOrErr.takeError();
   }
+
+  // We use strict error handling in case of records and enums, but not
+  // with e.g. namespaces.
+  //
+  // FIXME Clients of the ASTImporter should be able to choose an
+  // appropriate error handling strategy for their needs.  For instance,
+  // they may not want to mark an entire namespace as erroneous merely
+  // because there is an ODR error with two typedefs.  As another example,
+  // the client may allow EnumConstantDecls with same names but with
+  // different values in two distinct translation units.
+  bool AccumulateChildErrors = isa(FromDC);
+
+  Error ChildErrors = Error::success();
   llvm::SmallVector ImportedDecls;
   for (auto *From : FromDC->decls()) {
 ExpectedDecl ImportedOrErr = import(From);
-if (!ImportedOrErr)
-  // Ignore the error, continue with next Decl.
-  // FIXME: Handle this case somehow better.
-  consumeError(ImportedOrErr.takeError());
+if (!ImportedOrErr) {
+  if (AccumulateChildErrors)
+ChildErrors =
+joinErrors(std::move(ChildErrors), ImportedOrErr.takeError());
+  else
+consumeError(ImportedOrErr.takeError());
+}
   }
 
-  return Error::success();
+  return ChildErrors;
 }
 
 Error ASTNodeImporter::ImportDeclContext(
@@ -1698,6 +1715,11 @@
   }
 
   To->startDefinition();
+  // Complete the definition even if error is returned.
+  // The RecordDecl may be already part of the AST so it is better to
+  // have it in complete state even if something is wrong with it.
+  auto DefinitionCompleter =
+  llvm::make_scope_exit([To]() { To->completeDefinition(); });
 
   if (Error Err = setTypedefNameForAnonDecl(From, To, Importer))
 return Err;
@@ -1822,7 +1844,6 @@
 if (Error Err = ImportDeclContext(From, /*ForceImport=*/true))
   return Err;
 
-  To->completeDefinition();
   return Error::success();
 }
 
Index: cfe/trunk/unittests/AST/ASTImporterTest.cpp
===
--- cfe/trunk/unittests/AST/ASTImporterTest.cpp
+++ cfe/trunk/unittests/AST/ASTImporterTest.cpp
@@ -4738,6 +4738,93 @@
   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().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 OptErr = Importer->getImportDeclErrorIfAny(FromX);
+  ASSERT_TRUE(OptErr);
+  EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+
+  // An error is set for f().
+  auto *FromF = FirstDeclMatcher().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().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

[PATCH] D63603: [ASTImporter] Propagate error from ImportDeclContext

2019-06-30 Thread Aleksei Sidorin via Phabricator via cfe-commits
a_sidorin accepted this revision.
a_sidorin added a comment.
This revision is now accepted and ready to land.

Hi Gabor,
The patch looks good. Thanks!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63603/new/

https://reviews.llvm.org/D63603



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D63603: [ASTImporter] Propagate error from ImportDeclContext

2019-06-28 Thread Gabor Marton via Phabricator via cfe-commits
martong added a comment.

@a_sidorin Ping


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63603/new/

https://reviews.llvm.org/D63603



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D63603: [ASTImporter] Propagate error from ImportDeclContext

2019-06-24 Thread Gabor Marton via Phabricator via cfe-commits
martong updated this revision to Diff 206250.
martong marked 2 inline comments as done.
martong added a comment.

- Use make_scope_exit
- Add test ErrorIsNotPropagatedFromMemberToNamespace


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63603/new/

https://reviews.llvm.org/D63603

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -4738,6 +4738,93 @@
   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().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 OptErr = Importer->getImportDeclErrorIfAny(FromX);
+  ASSERT_TRUE(OptErr);
+  EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+
+  // An error is set for f().
+  auto *FromF = FirstDeclMatcher().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().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(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().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 OptErr = Importer->getImportDeclErrorIfAny(FromX);
+  ASSERT_FALSE(OptErr);
+
+  // An error is set for f().
+  auto *FromF = FirstDeclMatcher().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().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, );
 
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -57,6 +57,7 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Casting.h"
@@ -1631,16 +1632,32 @@
 auto ToDCOrErr = Importer.ImportContext(FromDC);
 return ToDCOrErr.takeError();
   }
+
+  // We use strict error handling in case of records and enums, but not
+  // with e.g. namespaces.
+  //
+  // FIXME Clients of the ASTImporter should be able to choose an

[PATCH] D63603: [ASTImporter] Propagate error from ImportDeclContext

2019-06-24 Thread Gabor Marton via Phabricator via cfe-commits
martong marked 4 inline comments as done.
martong added inline comments.



Comment at: clang/lib/AST/ASTImporter.cpp:1724
+  };
+  DefinitionCompleter CompleterRAII(To);
 

jkorous wrote:
> You might consider using just a lambda with `llvm::make_scope_exit`.
> 
> https://llvm.org/doxygen/namespacellvm.html#a4896534f3c6278be56967444daf38e3f
> 
> For example:
> ```
> To->startDefinition();
> auto DefinitionCompleter = llvm::make_scope_exit( 
> [To](){To->completeDefinition();} );
> ```
Thanks! I have changed to make_scope_exit.



Comment at: clang/unittests/AST/ASTImporterTest.cpp:4743
+}
+
 INSTANTIATE_TEST_CASE_P(ParameterizedTests, ErrorHandlingTest,

balazske wrote:
> Maybe add a similar test for namespace and check that the error is not 
> propagated?
Ok, I have added that test.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63603/new/

https://reviews.llvm.org/D63603



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D63603: [ASTImporter] Propagate error from ImportDeclContext

2019-06-24 Thread Gabor Marton via Phabricator via cfe-commits
martong updated this revision to Diff 206223.
martong added a comment.

- Remove the macro and use std::string.op+


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63603/new/

https://reviews.llvm.org/D63603

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -4738,6 +4738,53 @@
   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().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 OptErr = Importer->getImportDeclErrorIfAny(FromX);
+  ASSERT_TRUE(OptErr);
+  EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+
+  // An error is set for f().
+  auto *FromF = FirstDeclMatcher().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().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(ImportedOK->getDeclContext());
+  EXPECT_TRUE(ToX->isCompleteDefinition());
+}
+
 INSTANTIATE_TEST_CASE_P(ParameterizedTests, ErrorHandlingTest,
 DefaultTestValuesForRunOptions, );
 
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -1631,16 +1631,32 @@
 auto ToDCOrErr = Importer.ImportContext(FromDC);
 return ToDCOrErr.takeError();
   }
+
+  // We use strict error handling in case of records and enums, but not
+  // with e.g. namespaces.
+  //
+  // FIXME Clients of the ASTImporter should be able to choose an
+  // appropriate error handling strategy for their needs.  For instance,
+  // they may not want to mark an entire namespace as erroneous merely
+  // because there is an ODR error with two typedefs.  As another example,
+  // the client may allow EnumConstantDecls with same names but with
+  // different values in two distinct translation units.
+  bool AccumulateChildErrors = isa(FromDC);
+
+  Error ChildErrors = Error::success();
   llvm::SmallVector ImportedDecls;
   for (auto *From : FromDC->decls()) {
 ExpectedDecl ImportedOrErr = import(From);
-if (!ImportedOrErr)
-  // Ignore the error, continue with next Decl.
-  // FIXME: Handle this case somehow better.
-  consumeError(ImportedOrErr.takeError());
+if (!ImportedOrErr) {
+  if (AccumulateChildErrors)
+ChildErrors =
+joinErrors(std::move(ChildErrors), ImportedOrErr.takeError());
+  else
+consumeError(ImportedOrErr.takeError());
+}
   }
 
-  return Error::success();
+  return ChildErrors;
 }
 
 Error ASTNodeImporter::ImportDeclContext(
@@ -1697,7 +1713,15 @@
 return Error::success();
   }
 
-  To->startDefinition();
+  // Complete the definition even if error is returned.
+  // The RecordDecl may be already part of the AST so it is better to
+  // have it in complete state even if something is wrong with it.
+  struct DefinitionCompleter {
+RecordDecl *To;
+DefinitionCompleter(RecordDecl *To) : To(To) { To->startDefinition(); }
+~DefinitionCompleter() { To->completeDefinition(); }
+  };
+  DefinitionCompleter CompleterRAII(To);
 
   if (Error Err = setTypedefNameForAnonDecl(From, To, Importer))
 return Err;
@@ -1822,7 +1846,6 @@
 if (Error Err = ImportDeclContext(From, /*ForceImport=*/true))
   return Err;
 
-  To->completeDefinition();
   return Error::success();
 }
 
__

[PATCH] D63603: [ASTImporter] Propagate error from ImportDeclContext

2019-06-24 Thread Balázs Kéri via Phabricator via cfe-commits
balazske added inline comments.



Comment at: clang/unittests/AST/ASTImporterTest.cpp:4743
+}
+
 INSTANTIATE_TEST_CASE_P(ParameterizedTests, ErrorHandlingTest,

Maybe add a similar test for namespace and check that the error is not 
propagated?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63603/new/

https://reviews.llvm.org/D63603



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D63603: [ASTImporter] Propagate error from ImportDeclContext

2019-06-21 Thread Gabor Marton via Phabricator via cfe-commits
martong updated this revision to Diff 206018.
martong added a comment.

- Remove formatv b/c it can't handle braces in code


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63603/new/

https://reviews.llvm.org/D63603

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -4694,6 +4694,53 @@
   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(
+  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().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 OptErr = Importer->getImportDeclErrorIfAny(FromX);
+  ASSERT_TRUE(OptErr);
+  EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+
+  // An error is set for f().
+  auto *FromF = FirstDeclMatcher().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().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(ImportedOK->getDeclContext());
+  EXPECT_TRUE(ToX->isCompleteDefinition());
+}
+
 INSTANTIATE_TEST_CASE_P(ParameterizedTests, ErrorHandlingTest,
 DefaultTestValuesForRunOptions, );
 
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -1631,16 +1631,32 @@
 auto ToDCOrErr = Importer.ImportContext(FromDC);
 return ToDCOrErr.takeError();
   }
+
+  // We use strict error handling in case of records and enums, but not
+  // with e.g. namespaces.
+  //
+  // FIXME Clients of the ASTImporter should be able to choose an
+  // appropriate error handling strategy for their needs.  For instance,
+  // they may not want to mark an entire namespace as erroneous merely
+  // because there is an ODR error with two typedefs.  As another example,
+  // the client may allow EnumConstantDecls with same names but with
+  // different values in two distinct translation units.
+  bool AccumulateChildErrors = isa(FromDC);
+
+  Error ChildErrors = Error::success();
   llvm::SmallVector ImportedDecls;
   for (auto *From : FromDC->decls()) {
 ExpectedDecl ImportedOrErr = import(From);
-if (!ImportedOrErr)
-  // Ignore the error, continue with next Decl.
-  // FIXME: Handle this case somehow better.
-  consumeError(ImportedOrErr.takeError());
+if (!ImportedOrErr) {
+  if (AccumulateChildErrors)
+ChildErrors =
+joinErrors(std::move(ChildErrors), ImportedOrErr.takeError());
+  else
+consumeError(ImportedOrErr.takeError());
+}
   }
 
-  return Error::success();
+  return ChildErrors;
 }
 
 Error ASTNodeImporter::ImportDeclContext(
@@ -1697,7 +1713,15 @@
 return Error::success();
   }
 
-  To->startDefinition();
+  // Complete the definition even if error is returned.
+  // The RecordDecl may be already part of the AST so it is better to
+  // have it in complete state even if something is wrong with it.
+  struct DefinitionCompleter {
+RecordDecl *To;
+DefinitionCompleter(RecordDecl *To) : To(To) { To->startDefinition(); }
+~DefinitionCompleter() { To->completeDefinition(); }
+  };
+  DefinitionCompleter CompleterRAII(To);
 
   if (Error Err = setTypedefNameForAnonDecl(From, To, Importer))
 return Err;
@@ -1822,7 +1846,6 @@
 if (Error Err = ImportDeclContext(From, /*ForceImport=*/true))
   return Err;
 
-  To->completeDefinition();
   return Error::success();
 }
 
___

[PATCH] D63603: [ASTImporter] Propagate error from ImportDeclContext

2019-06-20 Thread Jan Korous via Phabricator via cfe-commits
jkorous added a comment.

I don't have the insight to LGTM the whole change - just a nit about 
implementation detail.




Comment at: clang/lib/AST/ASTImporter.cpp:1724
+  };
+  DefinitionCompleter CompleterRAII(To);
 

You might consider using just a lambda with `llvm::make_scope_exit`.

https://llvm.org/doxygen/namespacellvm.html#a4896534f3c6278be56967444daf38e3f

For example:
```
To->startDefinition();
auto DefinitionCompleter = llvm::make_scope_exit( 
[To](){To->completeDefinition();} );
```


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63603/new/

https://reviews.llvm.org/D63603



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D63603: [ASTImporter] Propagate error from ImportDeclContext

2019-06-20 Thread Gabor Marton via Phabricator via cfe-commits
martong created this revision.
martong added a reviewer: a_sidorin.
Herald added subscribers: cfe-commits, gamesh411, Szelethus, dkrupp, rnkovacs.
Herald added a reviewer: a.sidorin.
Herald added a reviewer: shafik.
Herald added a project: clang.
martong added a parent revision: D62373: [ASTImporter] Store import errors for 
Decls.
martong added a child revision: D62375: [ASTImporter] Mark erroneous nodes in 
from ctx.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D63603

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -4695,6 +4695,54 @@
   EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
 }
 
+// An error should be set for a class if we cannot import one member.
+TEST_P(ErrorHandlingTest, ErrorIsPropagatedFromMemberToClass) {
+  std::string Code = formatv(
+  R"(
+  class X {
+void f() { {0}; } // This member has the error during import.
+void ok();// The error should not prevent importing this.
+  };  // An error will be set for X too.
+  )",
+  ErroneousStmt);
+  TranslationUnitDecl *FromTU = getTuDecl(Code, Lang_CXX);
+
+  auto *FromX = FirstDeclMatcher().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 OptErr = Importer->getImportDeclErrorIfAny(FromX);
+  ASSERT_TRUE(OptErr);
+  EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+
+  // An error is set for f().
+  auto *FromF = FirstDeclMatcher().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().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(ImportedOK->getDeclContext());
+  EXPECT_TRUE(ToX->isCompleteDefinition());
+}
+
 INSTANTIATE_TEST_CASE_P(ParameterizedTests, ErrorHandlingTest,
 DefaultTestValuesForRunOptions, );
 
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -1631,16 +1631,32 @@
 auto ToDCOrErr = Importer.ImportContext(FromDC);
 return ToDCOrErr.takeError();
   }
+
+  // We use strict error handling in case of records and enums, but not
+  // with e.g. namespaces.
+  //
+  // FIXME Clients of the ASTImporter should be able to choose an
+  // appropriate error handling strategy for their needs.  For instance,
+  // they may not want to mark an entire namespace as erroneous merely
+  // because there is an ODR error with two typedefs.  As another example,
+  // the client may allow EnumConstantDecls with same names but with
+  // different values in two distinct translation units.
+  bool AccumulateChildErrors = isa(FromDC);
+
+  Error ChildErrors = Error::success();
   llvm::SmallVector ImportedDecls;
   for (auto *From : FromDC->decls()) {
 ExpectedDecl ImportedOrErr = import(From);
-if (!ImportedOrErr)
-  // Ignore the error, continue with next Decl.
-  // FIXME: Handle this case somehow better.
-  consumeError(ImportedOrErr.takeError());
+if (!ImportedOrErr) {
+  if (AccumulateChildErrors)
+ChildErrors =
+joinErrors(std::move(ChildErrors), ImportedOrErr.takeError());
+  else
+consumeError(ImportedOrErr.takeError());
+}
   }
 
-  return Error::success();
+  return ChildErrors;
 }
 
 Error ASTNodeImporter::ImportDeclContext(
@@ -1697,7 +1713,15 @@
 return Error::success();
   }
 
-  To->startDefinition();
+  // Complete the definition even if error is returned.
+  // The RecordDecl may be already part of the AST so it is better to
+  // have it in compl