[PATCH] D82940: [ASTReader][ASTWriter][PCH][Modules] Fix (de)serialization of SwitchCases

Gabor Marton via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 1 02:39:56 PDT 2020


martong created this revision.
martong added reviewers: vabridgers, riccibruno, aaron.ballman.
Herald added subscribers: cfe-commits, gamesh411, Szelethus, dkrupp, rnkovacs.
Herald added a project: clang.

https://github.com/llvm/llvm-project/commit/05843dc6ab97a00cbde7aa4f08bf3692eb83109d
introduces a regression: deserialization a function crashes if it has a switch
and a lambda with a switch (see the test case).
In this case the AST contains the exact same SwitchStmt both in the lambda's
CXXMethodDecl and as a child of the LambdaExpr:

  -LambdaExpr 0x55fc0fb0b4a0 <col:12, line:22:3>
   |-CXXRecordDecl 0x55fc0fb0afc8 <line:19:12> col:12 implicit class definition
   | |-CXXMethodDecl 0x55fc0fb0b108 <col:14, line:22:3> line:19:12 constexpr operator() 'auto () const -> void' inline
   | | `-CompoundStmt 0x55fc0fb0b2b0 <col:16, line:22:3>
   | |   `-SwitchStmt 0x55fc0fb0b208 <line:20:5, line:21:12>
   `-CompoundStmt 0x55fc0fb0b2b0 <col:16, line:22:3>
     `-SwitchStmt 0x55fc0fb0b208 <line:20:5, line:21:12>

During the serialization, each SwitchCase gets an id that is unique in a function.
Durint the deserialization, we fail to properly clear the existing ids, thus we receive the

  Assertion `(*CurrSwitchCaseStmts)[ID] == nullptr && "Already have a SwitchCase with this ID"' failed

This patch introduces a solution which removes the enforcment of unique ids per function.
We track the ids and make them unique per PCH.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82940

Files:
  clang/lib/Serialization/ASTReader.cpp
  clang/lib/Serialization/ASTWriterDecl.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/test/AST/ast-dump-lambda.cpp


Index: clang/test/AST/ast-dump-lambda.cpp
===================================================================
--- clang/test/AST/ast-dump-lambda.cpp
+++ clang/test/AST/ast-dump-lambda.cpp
@@ -34,6 +34,21 @@
   []() noexcept {};
   []() -> int { return 0; };
 }
+
+class {
+public:
+  enum {} a;
+} b;
+void should_not_crash_with_switch_in_lambda() {
+  switch (b.a)
+  default:;
+    enum { e } d;
+  auto f = [d] {
+    switch (d)
+    case e:;
+  };
+}
+
 // CHECK:Dumping test:
 // CHECK-NEXT:FunctionTemplateDecl {{.*}} <{{.*}}ast-dump-lambda.cpp:15:1, line:36:1> line:15:32{{( imported)?}} test
 // CHECK-NEXT:|-TemplateTypeParmDecl {{.*}} <col:11, col:23> col:23{{( imported)?}} referenced typename depth 0 index 0 ... Ts
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2611,11 +2611,12 @@
 //===----------------------------------------------------------------------===//
 
 unsigned ASTWriter::RecordSwitchCaseID(SwitchCase *S) {
-  assert(SwitchCaseIDs.find(S) == SwitchCaseIDs.end() &&
-         "SwitchCase recorded twice");
   unsigned NextID = SwitchCaseIDs.size();
-  SwitchCaseIDs[S] = NextID;
-  return NextID;
+  assert(NextID < UINT_MAX && "Too many SwitchCase to serialize");
+  // If we already recorded this SwitchCase then just return with its ID, else
+  // insert it with the next ID.
+  auto Res = SwitchCaseIDs.insert({S, NextID});
+  return Res.first->second;
 }
 
 unsigned ASTWriter::getSwitchCaseID(SwitchCase *S) {
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -2453,9 +2453,6 @@
 }
 
 void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
-  // Switch case IDs are per function body.
-  Writer->ClearSwitchCaseIDs();
-
   assert(FD->doesThisDeclarationHaveABody());
   bool ModulesCodegen = false;
   if (Writer->WritingModule && !FD->isDependentContext()) {
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -7461,8 +7461,6 @@
 /// source each time it is called, and is meant to be used via a
 /// LazyOffsetPtr (which is used by Decls for the body of functions, etc).
 Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
-  // Switch case IDs are per Decl.
-  ClearSwitchCaseIDs();
 
   // Offset here is a global offset across the entire chain.
   RecordLocation Loc = getLocalBitOffset(Offset);
@@ -9067,8 +9065,7 @@
 /// Record that the given ID maps to the given switch-case
 /// statement.
 void ASTReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) {
-  assert((*CurrSwitchCaseStmts)[ID] == nullptr &&
-         "Already have a SwitchCase with this ID");
+  // We may already have a SwitchCase with this ID, drop the existing.
   (*CurrSwitchCaseStmts)[ID] = SC;
 }
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D82940.274727.patch
Type: text/x-patch
Size: 3113 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200701/2d585803/attachment-0001.bin>


More information about the cfe-commits mailing list