PCH support for the first batch of statements, including null,

compound, case, default, if, switch, and break statements.

llvm-svn: 69329
This commit is contained in:
Douglas Gregor 2009-04-17 00:04:06 +00:00
parent e8eeffdf16
commit a9af1d13da
9 changed files with 367 additions and 13 deletions

View File

@ -136,11 +136,22 @@ public:
void operator delete(void*, std::size_t) throw() { }
void operator delete(void*, void*) throw() { }
public:
/// \brief A placeholder type used to construct an empty shell of a
/// type, that will be filled in later (e.g., by some
/// de-serialization).
struct EmptyShell { };
protected:
/// DestroyChildren - Invoked by destructors of subclasses of Stmt to
/// recursively release child AST nodes.
void DestroyChildren(ASTContext& Ctx);
/// \brief Construct an empty statement.
explicit Stmt(StmtClass SC, EmptyShell) : sClass(SC) {
if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
}
public:
Stmt(StmtClass SC) : sClass(SC) {
if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
@ -211,11 +222,6 @@ public:
return const_child_iterator(const_cast<Stmt*>(this)->child_end());
}
/// \brief A placeholder type used to construct an empty shell of a
/// type, that will be filled in later (e.g., by some
/// de-serialization).
struct EmptyShell { };
void Emit(llvm::Serializer& S) const;
static Stmt* Create(llvm::Deserializer& D, ASTContext& C);
@ -288,7 +294,11 @@ class NullStmt : public Stmt {
public:
NullStmt(SourceLocation L) : Stmt(NullStmtClass), SemiLoc(L) {}
/// \brief Build an empty null statement.
explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) { }
SourceLocation getSemiLoc() const { return SemiLoc; }
void setSemiLoc(SourceLocation L) { SemiLoc = L; }
virtual SourceRange getSourceRange() const { return SourceRange(SemiLoc); }
@ -323,9 +333,16 @@ public:
Body = new (C) Stmt*[NumStmts];
memcpy(Body, StmtStart, numStmts * sizeof(*Body));
}
// \brief Build an empty compound statement.
explicit CompoundStmt(EmptyShell Empty)
: Stmt(CompoundStmtClass, Empty), Body(0), NumStmts(0) { }
void setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts);
bool body_empty() const { return NumStmts == 0; }
unsigned size() const { return NumStmts; }
typedef Stmt** body_iterator;
body_iterator body_begin() { return Body; }
body_iterator body_end() { return Body + NumStmts; }
@ -360,7 +377,9 @@ public:
}
SourceLocation getLBracLoc() const { return LBracLoc; }
void setLBracLoc(SourceLocation L) { LBracLoc = L; }
SourceLocation getRBracLoc() const { return RBracLoc; }
void setRBracLoc(SourceLocation L) { RBracLoc = L; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CompoundStmtClass;
@ -418,12 +437,17 @@ public:
SubExprs[RHS] = reinterpret_cast<Stmt*>(rhs);
CaseLoc = caseLoc;
}
/// \brief Build an empty switch case statement.
explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass) { }
SourceLocation getCaseLoc() const { return CaseLoc; }
void setCaseLoc(SourceLocation L) { CaseLoc = L; }
Expr *getLHS() { return reinterpret_cast<Expr*>(SubExprs[LHS]); }
Expr *getRHS() { return reinterpret_cast<Expr*>(SubExprs[RHS]); }
Stmt *getSubStmt() { return SubExprs[SUBSTMT]; }
const Expr *getLHS() const {
return reinterpret_cast<const Expr*>(SubExprs[LHS]);
}
@ -465,11 +489,16 @@ class DefaultStmt : public SwitchCase {
public:
DefaultStmt(SourceLocation DL, Stmt *substmt) :
SwitchCase(DefaultStmtClass), SubStmt(substmt), DefaultLoc(DL) {}
/// \brief Build an empty default statement.
explicit DefaultStmt(EmptyShell) : SwitchCase(DefaultStmtClass) { }
Stmt *getSubStmt() { return SubStmt; }
const Stmt *getSubStmt() const { return SubStmt; }
void setSubStmt(Stmt *S) { SubStmt = S; }
SourceLocation getDefaultLoc() const { return DefaultLoc; }
void setDefaultLoc(SourceLocation L) { DefaultLoc = L; }
virtual SourceRange getSourceRange() const {
return SourceRange(DefaultLoc, SubStmt->getLocEnd());
@ -537,14 +566,23 @@ public:
IfLoc = IL;
}
/// \brief Build an empty if/then/else statement
explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { }
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
const Stmt *getThen() const { return SubExprs[THEN]; }
void setThen(Stmt *S) { SubExprs[THEN] = S; }
const Stmt *getElse() const { return SubExprs[ELSE]; }
void setElse(Stmt *S) { SubExprs[ELSE] = S; }
Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
Stmt *getThen() { return SubExprs[THEN]; }
Stmt *getElse() { return SubExprs[ELSE]; }
SourceLocation getIfLoc() const { return IfLoc; }
void setIfLoc(SourceLocation L) { IfLoc = L; }
virtual SourceRange getSourceRange() const {
if (SubExprs[ELSE])
return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd());
@ -579,13 +617,22 @@ public:
SubExprs[BODY] = NULL;
}
/// \brief Build a empty switch statement.
explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { }
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
const Stmt *getBody() const { return SubExprs[BODY]; }
const SwitchCase *getSwitchCaseList() const { return FirstCase; }
Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]);}
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
Stmt *getBody() { return SubExprs[BODY]; }
void setBody(Stmt *S) { SubExprs[BODY] = S; }
SwitchCase *getSwitchCaseList() { return FirstCase; }
void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
SourceLocation getSwitchLoc() const { return SwitchLoc; }
void setSwitchLoc(SourceLocation L) { SwitchLoc = L; }
void setBody(Stmt *S, SourceLocation SL) {
SubExprs[BODY] = S;
@ -814,6 +861,12 @@ class BreakStmt : public Stmt {
public:
BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) {}
/// \brief Build an empty break statement.
explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) { }
SourceLocation getBreakLoc() const { return BreakLoc; }
void setBreakLoc(SourceLocation L) { BreakLoc = L; }
virtual SourceRange getSourceRange() const { return SourceRange(BreakLoc); }
static bool classof(const Stmt *T) {

View File

@ -375,6 +375,20 @@ namespace clang {
STMT_STOP,
/// \brief A NULL expression.
STMT_NULL_PTR,
/// \brief A NullStmt record.
STMT_NULL,
/// \brief A CompoundStmt record.
STMT_COMPOUND,
/// \brief A CaseStmt record.
STMT_CASE,
/// \brief A DefaultStmt record.
STMT_DEFAULT,
/// \brief An IfStmt record.
STMT_IF,
/// \brief A SwitchStmt record.
STMT_SWITCH,
/// \brief A BreakStmt record.
STMT_BREAK,
/// \brief A PredefinedExpr record.
EXPR_PREDEFINED,
/// \brief A DeclRefExpr record.

View File

@ -26,6 +26,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/DataTypes.h"
#include <map>
#include <string>
#include <utility>
#include <vector>
@ -41,6 +42,7 @@ class Attr;
class Decl;
class DeclContext;
class Preprocessor;
class SwitchCase;
/// \brief Reads a precompiled head containing the contents of a
/// translation unit.
@ -126,6 +128,10 @@ private:
/// file.
llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
/// \brief Mapping from switch-case IDs in the PCH file to
/// switch-case statements.
std::map<unsigned, SwitchCase *> SwitchCaseStmts;
PCHReadResult ReadPCHBlock();
bool CheckPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen,
@ -241,6 +247,13 @@ public:
/// \brief Retrieve the AST context that this PCH reader
/// supplements.
ASTContext &getContext() { return Context; }
/// \brief Record that the given ID maps to the given switch-case
/// statement.
void RecordSwitchCaseID(SwitchCase *SC, unsigned ID);
/// \brief Retrieve the switch-case statement with the given ID.
SwitchCase *getSwitchCaseWithID(unsigned ID);
};
} // end namespace clang

View File

@ -20,6 +20,7 @@
#include "clang/Frontend/PCHBitCodes.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include <map>
#include <queue>
namespace llvm {
@ -33,6 +34,7 @@ namespace clang {
class ASTContext;
class Preprocessor;
class SourceManager;
class SwitchCase;
class TargetInfo;
/// \brief Writes a precompiled header containing the contents of a
@ -108,6 +110,9 @@ private:
/// declaration or type.
llvm::SmallVector<Stmt *, 8> StmtsToEmit;
/// \brief Mapping from SwitchCase statements to IDs.
std::map<SwitchCase *, unsigned> SwitchCaseIDs;
void WriteTargetTriple(const TargetInfo &Target);
void WriteLanguageOptions(const LangOptions &LangOpts);
void WriteSourceManagerBlock(SourceManager &SourceMgr);
@ -170,6 +175,13 @@ public:
/// \brief Flush all of the statements and expressions that have
/// been added to the queue via AddStmt().
void FlushStmts();
/// \brief Record an ID for the given switch-case statement.
unsigned RecordSwitchCaseID(SwitchCase *S);
/// \brief Retrieve the ID for the given switch-case statement.
unsigned getSwitchCaseID(SwitchCase *S);
};
} // end namespace clang

View File

@ -96,6 +96,14 @@ bool Stmt::CollectingStats(bool enable) {
return StatSwitch;
}
void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
if (this->Body)
C.Deallocate(Body);
this->NumStmts = NumStmts;
Body = new (C) Stmt*[NumStmts];
memcpy(Body, Stmts, sizeof(Stmt *) * NumStmts);
}
const char *LabelStmt::getName() const {
return getID()->getName();

View File

@ -139,7 +139,8 @@ void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
VisitValueDecl(FD);
// FIXME: function body
if (Record[Idx++])
FD->setBody(cast<CompoundStmt>(Reader.ReadStmt()));
FD->setPreviousDeclaration(
cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]);
@ -229,15 +230,28 @@ namespace {
unsigned &Idx, llvm::SmallVectorImpl<Stmt *> &StmtStack)
: Reader(Reader), Record(Record), Idx(Idx), StmtStack(StmtStack) { }
/// \brief The number of record fields required for the Stmt class
/// itself.
static const unsigned NumStmtFields = 0;
/// \brief The number of record fields required for the Expr class
/// itself.
static const unsigned NumExprFields = 3;
static const unsigned NumExprFields = NumStmtFields + 3;
// Each of the Visit* functions reads in part of the expression
// from the given record and the current expression stack, then
// return the total number of operands that it read from the
// expression stack.
unsigned VisitStmt(Stmt *S);
unsigned VisitNullStmt(NullStmt *S);
unsigned VisitCompoundStmt(CompoundStmt *S);
unsigned VisitSwitchCase(SwitchCase *S);
unsigned VisitCaseStmt(CaseStmt *S);
unsigned VisitDefaultStmt(DefaultStmt *S);
unsigned VisitIfStmt(IfStmt *S);
unsigned VisitSwitchStmt(SwitchStmt *S);
unsigned VisitBreakStmt(BreakStmt *S);
unsigned VisitExpr(Expr *E);
unsigned VisitPredefinedExpr(PredefinedExpr *E);
unsigned VisitDeclRefExpr(DeclRefExpr *E);
@ -273,7 +287,83 @@ namespace {
};
}
unsigned PCHStmtReader::VisitStmt(Stmt *S) {
assert(Idx == NumStmtFields && "Incorrect statement field count");
return 0;
}
unsigned PCHStmtReader::VisitNullStmt(NullStmt *S) {
VisitStmt(S);
S->setSemiLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
return 0;
}
unsigned PCHStmtReader::VisitCompoundStmt(CompoundStmt *S) {
VisitStmt(S);
unsigned NumStmts = Record[Idx++];
S->setStmts(Reader.getContext(),
&StmtStack[StmtStack.size() - NumStmts], NumStmts);
S->setLBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
S->setRBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
return NumStmts;
}
unsigned PCHStmtReader::VisitSwitchCase(SwitchCase *S) {
VisitStmt(S);
Reader.RecordSwitchCaseID(S, Record[Idx++]);
return 0;
}
unsigned PCHStmtReader::VisitCaseStmt(CaseStmt *S) {
VisitSwitchCase(S);
S->setLHS(cast<Expr>(StmtStack[StmtStack.size() - 3]));
S->setRHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2]));
S->setSubStmt(StmtStack.back());
S->setCaseLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
return 3;
}
unsigned PCHStmtReader::VisitDefaultStmt(DefaultStmt *S) {
VisitSwitchCase(S);
S->setSubStmt(StmtStack.back());
S->setDefaultLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
return 1;
}
unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) {
VisitStmt(S);
S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 3]));
S->setThen(StmtStack[StmtStack.size() - 2]);
S->setElse(StmtStack[StmtStack.size() - 1]);
S->setIfLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
return 3;
}
unsigned PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) {
VisitStmt(S);
S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 2]));
S->setBody(StmtStack.back());
S->setSwitchLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
SwitchCase *PrevSC = 0;
for (unsigned N = Record.size(); Idx != N; ++Idx) {
SwitchCase *SC = Reader.getSwitchCaseWithID(Record[Idx]);
if (PrevSC)
PrevSC->setNextSwitchCase(SC);
else
S->setSwitchCaseList(SC);
PrevSC = SC;
}
return 2;
}
unsigned PCHStmtReader::VisitBreakStmt(BreakStmt *S) {
VisitStmt(S);
S->setBreakLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
return 0;
}
unsigned PCHStmtReader::VisitExpr(Expr *E) {
VisitStmt(E);
E->setType(Reader.GetType(Record[Idx++]));
E->setTypeDependent(Record[Idx++]);
E->setValueDependent(Record[Idx++]);
@ -2002,6 +2092,34 @@ Stmt *PCHReader::ReadStmt() {
S = 0;
break;
case pch::STMT_NULL:
S = new (Context) NullStmt(Empty);
break;
case pch::STMT_COMPOUND:
S = new (Context) CompoundStmt(Empty);
break;
case pch::STMT_CASE:
S = new (Context) CaseStmt(Empty);
break;
case pch::STMT_DEFAULT:
S = new (Context) DefaultStmt(Empty);
break;
case pch::STMT_IF:
S = new (Context) IfStmt(Empty);
break;
case pch::STMT_SWITCH:
S = new (Context) SwitchStmt(Empty);
break;
case pch::STMT_BREAK:
S = new (Context) BreakStmt(Empty);
break;
case pch::EXPR_PREDEFINED:
// FIXME: untested (until we can serialize function bodies).
S = new (Context) PredefinedExpr(Empty);
@ -2157,3 +2275,16 @@ DiagnosticBuilder PCHReader::Diag(SourceLocation Loc, unsigned DiagID) {
Context.getSourceManager()),
DiagID);
}
/// \brief Record that the given ID maps to the given switch-case
/// statement.
void PCHReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) {
assert(SwitchCaseStmts[ID] == 0 && "Already have a SwitchCase with this ID");
SwitchCaseStmts[ID] = SC;
}
/// \brief Retrieve the switch-case statement with the given ID.
SwitchCase *PCHReader::getSwitchCaseWithID(unsigned ID) {
assert(SwitchCaseStmts[ID] != 0 && "No SwitchCase with this ID");
return SwitchCaseStmts[ID];
}

View File

@ -338,7 +338,9 @@ void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
VisitValueDecl(D);
// FIXME: function body
Record.push_back(D->isThisDeclarationADefinition());
if (D->isThisDeclarationADefinition())
Writer.AddStmt(D->getBody());
Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
Record.push_back(D->isInline());
@ -443,6 +445,15 @@ namespace {
PCHStmtWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
: Writer(Writer), Record(Record) { }
void VisitStmt(Stmt *S);
void VisitNullStmt(NullStmt *S);
void VisitCompoundStmt(CompoundStmt *S);
void VisitSwitchCase(SwitchCase *S);
void VisitCaseStmt(CaseStmt *S);
void VisitDefaultStmt(DefaultStmt *S);
void VisitIfStmt(IfStmt *S);
void VisitSwitchStmt(SwitchStmt *S);
void VisitBreakStmt(BreakStmt *S);
void VisitExpr(Expr *E);
void VisitPredefinedExpr(PredefinedExpr *E);
void VisitDeclRefExpr(DeclRefExpr *E);
@ -478,7 +489,75 @@ namespace {
};
}
void PCHStmtWriter::VisitStmt(Stmt *S) {
}
void PCHStmtWriter::VisitNullStmt(NullStmt *S) {
VisitStmt(S);
Writer.AddSourceLocation(S->getSemiLoc(), Record);
Code = pch::STMT_NULL;
}
void PCHStmtWriter::VisitCompoundStmt(CompoundStmt *S) {
VisitStmt(S);
Record.push_back(S->size());
for (CompoundStmt::body_iterator CS = S->body_begin(), CSEnd = S->body_end();
CS != CSEnd; ++CS)
Writer.WriteSubStmt(*CS);
Writer.AddSourceLocation(S->getLBracLoc(), Record);
Writer.AddSourceLocation(S->getRBracLoc(), Record);
Code = pch::STMT_COMPOUND;
}
void PCHStmtWriter::VisitSwitchCase(SwitchCase *S) {
VisitStmt(S);
Record.push_back(Writer.RecordSwitchCaseID(S));
}
void PCHStmtWriter::VisitCaseStmt(CaseStmt *S) {
VisitSwitchCase(S);
Writer.WriteSubStmt(S->getLHS());
Writer.WriteSubStmt(S->getRHS());
Writer.WriteSubStmt(S->getSubStmt());
Writer.AddSourceLocation(S->getCaseLoc(), Record);
Code = pch::STMT_CASE;
}
void PCHStmtWriter::VisitDefaultStmt(DefaultStmt *S) {
VisitSwitchCase(S);
Writer.WriteSubStmt(S->getSubStmt());
Writer.AddSourceLocation(S->getDefaultLoc(), Record);
Code = pch::STMT_DEFAULT;
}
void PCHStmtWriter::VisitIfStmt(IfStmt *S) {
VisitStmt(S);
Writer.WriteSubStmt(S->getCond());
Writer.WriteSubStmt(S->getThen());
Writer.WriteSubStmt(S->getElse());
Writer.AddSourceLocation(S->getIfLoc(), Record);
Code = pch::STMT_IF;
}
void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
VisitStmt(S);
Writer.WriteSubStmt(S->getCond());
Writer.WriteSubStmt(S->getBody());
Writer.AddSourceLocation(S->getSwitchLoc(), Record);
for (SwitchCase *SC = S->getSwitchCaseList(); SC;
SC = SC->getNextSwitchCase())
Record.push_back(Writer.getSwitchCaseID(SC));
Code = pch::STMT_SWITCH;
}
void PCHStmtWriter::VisitBreakStmt(BreakStmt *S) {
VisitStmt(S);
Writer.AddSourceLocation(S->getBreakLoc(), Record);
Code = pch::STMT_BREAK;
}
void PCHStmtWriter::VisitExpr(Expr *E) {
VisitStmt(E);
Writer.AddTypeRef(E->getType(), Record);
Record.push_back(E->isTypeDependent());
Record.push_back(E->isValueDependent());
@ -1708,3 +1787,17 @@ void PCHWriter::FlushStmts() {
StmtsToEmit.clear();
}
unsigned PCHWriter::RecordSwitchCaseID(SwitchCase *S) {
assert(SwitchCaseIDs.find(S) == SwitchCaseIDs.end() &&
"SwitchCase recorded twice");
unsigned NextID = SwitchCaseIDs.size();
SwitchCaseIDs[S] = NextID;
return NextID;
}
unsigned PCHWriter::getSwitchCaseID(SwitchCase *S) {
assert(SwitchCaseIDs.find(S) != SwitchCaseIDs.end() &&
"SwitchCase hasn't been seen yet");
return SwitchCaseIDs[S];
}

8
clang/test/PCH/stmts.c Normal file
View File

@ -0,0 +1,8 @@
// Test this without pch.
// RUN: clang-cc -fblocks -include %S/stmts.h -fsyntax-only -emit-llvm -o - %s
// Test with pch.
// RUN: clang-cc -emit-pch -fblocks -o %t %S/stmts.h &&
// RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -emit-llvm -o - %s
void g0(void) { f0(5); }

22
clang/test/PCH/stmts.h Normal file
View File

@ -0,0 +1,22 @@
// Header for PCH test stmts.c
void f0(int x) {
// NullStmt
;
// IfStmt
if (x) {
} else if (x + 1) {
}
switch (x) {
case 0:
x = 17;
break;
case 1:
break;
default:
break;
}
}