aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Serialization/ASTBitCodes.h2
-rw-r--r--include/clang/Serialization/ASTWriter.h5
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp17
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp45
-rw-r--r--test/PCH/designated-init.c7
-rw-r--r--test/PCH/designated-init.c.h42
6 files changed, 113 insertions, 5 deletions
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index e7f126514b..49f1ddfa26 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -875,6 +875,8 @@ namespace clang {
STMT_STOP = 100,
/// \brief A NULL expression.
STMT_NULL_PTR,
+ /// \brief A reference to a previously [de]serialized Stmt record.
+ STMT_REF_PTR,
/// \brief A NullStmt record.
STMT_NULL,
/// \brief A CompoundStmt record.
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index 7a49e485f2..7d89ce7db0 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -24,6 +24,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include <map>
#include <queue>
@@ -331,7 +332,9 @@ private:
SmallVector<QueuedCXXBaseSpecifiers, 2> CXXBaseSpecifiersToWrite;
/// \brief Write the given subexpression to the bitstream.
- void WriteSubStmt(Stmt *S);
+ void WriteSubStmt(Stmt *S,
+ llvm::DenseMap<Stmt *, uint64_t> &SubStmtEntries,
+ llvm::DenseSet<Stmt *> &ParentStmts);
void WriteBlockInfoBlock();
void WriteMetadata(ASTContext &Context, StringRef isysroot,
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index ab07b85bf4..85d0f929c4 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1444,6 +1444,10 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
ReadingKindTracker ReadingKind(Read_Stmt, *this);
llvm::BitstreamCursor &Cursor = F.DeclsCursor;
+
+ // Map of offset to previously deserialized stmt. The offset points
+ /// just after the stmt record.
+ llvm::DenseMap<uint64_t, Stmt *> StmtEntries;
#ifndef NDEBUG
unsigned PrevNumStmts = StmtStack.size();
@@ -1483,11 +1487,19 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
Idx = 0;
Record.clear();
bool Finished = false;
+ bool IsStmtReference = false;
switch ((StmtCode)Cursor.ReadRecord(Code, Record)) {
case STMT_STOP:
Finished = true;
break;
+ case STMT_REF_PTR:
+ IsStmtReference = true;
+ assert(StmtEntries.find(Record[0]) != StmtEntries.end() &&
+ "No stmt was recorded for this offset reference!");
+ S = StmtEntries[Record[Idx++]];
+ break;
+
case STMT_NULL_PTR:
S = 0;
break;
@@ -2041,8 +2053,11 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
++NumStatementsRead;
- if (S)
+ if (S && !IsStmtReference) {
Reader.Visit(S);
+ StmtEntries[Cursor.GetCurrentBitNo()] = S;
+ }
+
assert(Idx == Record.size() && "Invalid deserialization of statement");
StmtStack.push_back(S);
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 7e2d45c5e7..463203b4a0 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1443,7 +1443,9 @@ unsigned ASTWriter::getOpaqueValueID(OpaqueValueExpr *e) {
/// \brief Write the given substatement or subexpression to the
/// bitstream.
-void ASTWriter::WriteSubStmt(Stmt *S) {
+void ASTWriter::WriteSubStmt(Stmt *S,
+ llvm::DenseMap<Stmt *, uint64_t> &SubStmtEntries,
+ llvm::DenseSet<Stmt *> &ParentStmts) {
RecordData Record;
ASTStmtWriter Writer(*this, Record);
++NumStatements;
@@ -1453,6 +1455,32 @@ void ASTWriter::WriteSubStmt(Stmt *S) {
return;
}
+ llvm::DenseMap<Stmt *, uint64_t>::iterator I = SubStmtEntries.find(S);
+ if (I != SubStmtEntries.end()) {
+ Record.push_back(I->second);
+ Stream.EmitRecord(serialization::STMT_REF_PTR, Record);
+ return;
+ }
+
+#ifndef NDEBUG
+ assert(!ParentStmts.count(S) && "There is a Stmt cycle!");
+
+ struct ParentStmtInserterRAII {
+ Stmt *S;
+ llvm::DenseSet<Stmt *> &ParentStmts;
+
+ ParentStmtInserterRAII(Stmt *S, llvm::DenseSet<Stmt *> &ParentStmts)
+ : S(S), ParentStmts(ParentStmts) {
+ ParentStmts.insert(S);
+ }
+ ~ParentStmtInserterRAII() {
+ ParentStmts.erase(S);
+ }
+ };
+
+ ParentStmtInserterRAII ParentStmtInserter(S, ParentStmts);
+#endif
+
// Redirect ASTWriter::AddStmt to collect sub stmts.
SmallVector<Stmt *, 16> SubStmts;
CollectedStmts = &SubStmts;
@@ -1478,9 +1506,11 @@ void ASTWriter::WriteSubStmt(Stmt *S) {
// This simplifies reading and allows to store a variable number of sub stmts
// without knowing it in advance.
while (!SubStmts.empty())
- WriteSubStmt(SubStmts.pop_back_val());
+ WriteSubStmt(SubStmts.pop_back_val(), SubStmtEntries, ParentStmts);
Stream.EmitRecord(Writer.Code, Record, Writer.AbbrevToUse);
+
+ SubStmtEntries[S] = Stream.GetCurrentBitNo();
}
/// \brief Flush all of the statements that have been added to the
@@ -1488,8 +1518,14 @@ void ASTWriter::WriteSubStmt(Stmt *S) {
void ASTWriter::FlushStmts() {
RecordData Record;
+ /// \brief Set of parent Stmts for the currently serializing sub stmt.
+ llvm::DenseSet<Stmt *> ParentStmts;
+ /// \brief Offsets of sub stmts already serialized. The offset points
+ /// just after the stmt record.
+ llvm::DenseMap<Stmt *, uint64_t> SubStmtEntries;
+
for (unsigned I = 0, N = StmtsToEmit.size(); I != N; ++I) {
- WriteSubStmt(StmtsToEmit[I]);
+ WriteSubStmt(StmtsToEmit[I], SubStmtEntries, ParentStmts);
assert(N == StmtsToEmit.size() &&
"Substatement written via AddStmt rather than WriteSubStmt!");
@@ -1498,6 +1534,9 @@ void ASTWriter::FlushStmts() {
// expression records that follow this one are part of a different
// expression.
Stream.EmitRecord(serialization::STMT_STOP, Record);
+
+ SubStmtEntries.clear();
+ ParentStmts.clear();
}
StmtsToEmit.clear();
diff --git a/test/PCH/designated-init.c b/test/PCH/designated-init.c
new file mode 100644
index 0000000000..beb4dffe61
--- /dev/null
+++ b/test/PCH/designated-init.c
@@ -0,0 +1,7 @@
+// Test this without pch.
+// RUN: %clang_cc1 %s -include %s.h -emit-llvm -o %t.withoutpch.ll
+
+// Test with pch.
+// RUN: %clang_cc1 %s.h -emit-pch -o %t.pch
+// RUN: %clang_cc1 %s -include-pch %t.pch -emit-llvm -o %t.withpch.ll
+// RUN: diff %t.withoutpch.ll %t.withpch.ll
diff --git a/test/PCH/designated-init.c.h b/test/PCH/designated-init.c.h
new file mode 100644
index 0000000000..63b1f790ea
--- /dev/null
+++ b/test/PCH/designated-init.c.h
@@ -0,0 +1,42 @@
+static void *FooToken = &FooToken;
+static void *FooTable[256] = {
+ [0x3] = (void *[256]) { // 1
+ [0x5b] = (void *[256]) { // 2
+ [0x81] = (void *[256]) { // 3
+ [0x42] = (void *[256]) { // 4
+ [0xa2] = (void *[256]) { // 5
+ [0xe] = (void *[256]) { // 6
+ [0x20] = (void *[256]) { // 7
+ [0xd7] = (void *[256]) { // 8
+ [0x39] = (void *[256]) { // 9
+ [0xf1] = (void *[256]) { // 10
+ [0xa4] = (void *[256]) { // 11
+ [0xa8] = (void *[256]) { // 12
+ [0x21] = (void *[256]) { // 13
+ [0x86] = (void *[256]) { // 14
+ [0x1d] = (void *[256]) { // 15
+ [0xdc] = (void *[256]) { // 16
+ [0xa5] = (void *[256]) { // 17
+ [0xef] = (void *[256]) { // 18
+ [0x9] = (void *[256]) { // 19
+ [0x34] = &FooToken,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+};