diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index c20d602a7cc7..2c88ff42540f 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -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(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(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(SubExprs[LHS]); } Expr *getRHS() { return reinterpret_cast(SubExprs[RHS]); } Stmt *getSubStmt() { return SubExprs[SUBSTMT]; } + const Expr *getLHS() const { return reinterpret_cast(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(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast(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(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(SubExprs[COND]);} const Stmt *getBody() const { return SubExprs[BODY]; } const SwitchCase *getSwitchCaseList() const { return FirstCase; } Expr *getCond() { return reinterpret_cast(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast(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) { diff --git a/clang/include/clang/Frontend/PCHBitCodes.h b/clang/include/clang/Frontend/PCHBitCodes.h index a218a5fcf64c..98d27a091603 100644 --- a/clang/include/clang/Frontend/PCHBitCodes.h +++ b/clang/include/clang/Frontend/PCHBitCodes.h @@ -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. diff --git a/clang/include/clang/Frontend/PCHReader.h b/clang/include/clang/Frontend/PCHReader.h index 995a1d563f2c..07531df1f34a 100644 --- a/clang/include/clang/Frontend/PCHReader.h +++ b/clang/include/clang/Frontend/PCHReader.h @@ -26,6 +26,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/DataTypes.h" +#include #include #include #include @@ -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 ExternalDefinitions; + /// \brief Mapping from switch-case IDs in the PCH file to + /// switch-case statements. + std::map 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 diff --git a/clang/include/clang/Frontend/PCHWriter.h b/clang/include/clang/Frontend/PCHWriter.h index 4af64e6ee100..5828637b04c4 100644 --- a/clang/include/clang/Frontend/PCHWriter.h +++ b/clang/include/clang/Frontend/PCHWriter.h @@ -20,6 +20,7 @@ #include "clang/Frontend/PCHBitCodes.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" +#include #include 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 StmtsToEmit; + /// \brief Mapping from SwitchCase statements to IDs. + std::map 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 diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index ce55fae87e9a..8e2cf861f837 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -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(); diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index 0f208fb7ac9d..e39f3e580b8f 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/lib/Frontend/PCHReader.cpp @@ -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(Reader.ReadStmt())); FD->setPreviousDeclaration( cast_or_null(Reader.GetDecl(Record[Idx++]))); FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]); @@ -229,15 +230,28 @@ namespace { unsigned &Idx, llvm::SmallVectorImpl &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(StmtStack[StmtStack.size() - 3])); + S->setRHS(cast_or_null(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(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(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]; +} diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index 056aeec2d7e4..8f09030ac800 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -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]; +} diff --git a/clang/test/PCH/stmts.c b/clang/test/PCH/stmts.c new file mode 100644 index 000000000000..b71db63e67ca --- /dev/null +++ b/clang/test/PCH/stmts.c @@ -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); } diff --git a/clang/test/PCH/stmts.h b/clang/test/PCH/stmts.h new file mode 100644 index 000000000000..ab71c5044034 --- /dev/null +++ b/clang/test/PCH/stmts.h @@ -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; + } +}