diff options
-rw-r--r-- | include/clang/AST/Stmt.h | 14 | ||||
-rw-r--r-- | include/clang/Frontend/PCHBitCodes.h | 4 | ||||
-rw-r--r-- | include/clang/Frontend/PCHReader.h | 24 | ||||
-rw-r--r-- | include/clang/Frontend/PCHWriter.h | 8 | ||||
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 65 | ||||
-rw-r--r-- | lib/Frontend/PCHWriter.cpp | 31 | ||||
-rw-r--r-- | test/PCH/stmts.h | 8 |
7 files changed, 152 insertions, 2 deletions
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index d0531f95a5..29e1931746 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -530,13 +530,16 @@ public: LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt) : Stmt(LabelStmtClass), Label(label), SubStmt(substmt), IdentLoc(IL) {} + + // \brief Build an empty label statement. + explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) { } SourceLocation getIdentLoc() const { return IdentLoc; } IdentifierInfo *getID() const { return Label; } + void setID(IdentifierInfo *II) { Label = II; } const char *getName() const; Stmt *getSubStmt() { return SubStmt; } const Stmt *getSubStmt() const { return SubStmt; } - void setIdentLoc(SourceLocation L) { IdentLoc = L; } void setSubStmt(Stmt *SS) { SubStmt = SS; } @@ -817,7 +820,16 @@ public: GotoStmt(LabelStmt *label, SourceLocation GL, SourceLocation LL) : Stmt(GotoStmtClass), Label(label), GotoLoc(GL), LabelLoc(LL) {} + /// \brief Build an empty goto statement. + explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) { } + LabelStmt *getLabel() const { return Label; } + void setLabel(LabelStmt *S) { Label = S; } + + SourceLocation getGotoLoc() const { return GotoLoc; } + void setGotoLoc(SourceLocation L) { GotoLoc = L; } + SourceLocation getLabelLoc() const { return LabelLoc; } + void setLabelLoc(SourceLocation L) { LabelLoc = L; } virtual SourceRange getSourceRange() const { return SourceRange(GotoLoc, LabelLoc); diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index f5b023430a..fceafb096f 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -383,6 +383,8 @@ namespace clang { STMT_CASE, /// \brief A DefaultStmt record. STMT_DEFAULT, + /// \brief A LabelStmt record. + STMT_LABEL, /// \brief An IfStmt record. STMT_IF, /// \brief A SwitchStmt record. @@ -393,6 +395,8 @@ namespace clang { STMT_DO, /// \brief A ForStmt record. STMT_FOR, + /// \brief A GotoStmt record. + STMT_GOTO, /// \brief A ContinueStmt record. STMT_CONTINUE, /// \brief A BreakStmt record. diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 07531df1f3..c573797693 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -41,6 +41,8 @@ class ASTContext; class Attr; class Decl; class DeclContext; +class GotoStmt; +class LabelStmt; class Preprocessor; class SwitchCase; @@ -132,6 +134,15 @@ private: /// switch-case statements. std::map<unsigned, SwitchCase *> SwitchCaseStmts; + /// \brief Mapping from label statement IDs in the PCH file to label + /// statements. + std::map<unsigned, LabelStmt *> LabelStmts; + + /// \brief Mapping from label IDs to the set of "goto" statements + /// that point to that label before the label itself has been + /// de-serialized. + std::multimap<unsigned, GotoStmt *> UnresolvedGotoStmts; + PCHReadResult ReadPCHBlock(); bool CheckPredefinesBuffer(const char *PCHPredef, unsigned PCHPredefLen, @@ -254,6 +265,19 @@ public: /// \brief Retrieve the switch-case statement with the given ID. SwitchCase *getSwitchCaseWithID(unsigned ID); + + /// \brief Record that the given label statement has been + /// deserialized and has the given ID. + void RecordLabelStmt(LabelStmt *S, unsigned ID); + + /// \brief Set the label of the given statement to the label + /// identified by ID. + /// + /// Depending on the order in which the label and other statements + /// referencing that label occur, this operation may complete + /// immediately (updating the statement) or it may queue the + /// statement to be back-patched later. + void SetLabelOf(GotoStmt *S, unsigned ID); }; } // end namespace clang diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index 5828637b04..d8f43bb305 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -32,6 +32,7 @@ namespace llvm { namespace clang { class ASTContext; +class LabelStmt; class Preprocessor; class SourceManager; class SwitchCase; @@ -113,6 +114,9 @@ private: /// \brief Mapping from SwitchCase statements to IDs. std::map<SwitchCase *, unsigned> SwitchCaseIDs; + /// \brief Mapping from LabelStmt statements to IDs. + std::map<LabelStmt *, unsigned> LabelIDs; + void WriteTargetTriple(const TargetInfo &Target); void WriteLanguageOptions(const LangOptions &LangOpts); void WriteSourceManagerBlock(SourceManager &SourceMgr); @@ -182,6 +186,10 @@ public: /// \brief Retrieve the ID for the given switch-case statement. unsigned getSwitchCaseID(SwitchCase *S); + /// \brief Retrieve the ID for the given label statement, which may + /// or may not have been emitted yet. + unsigned GetLabelID(LabelStmt *S); + }; } // end namespace clang diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 50378966e1..9597b37082 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -249,11 +249,13 @@ namespace { unsigned VisitSwitchCase(SwitchCase *S); unsigned VisitCaseStmt(CaseStmt *S); unsigned VisitDefaultStmt(DefaultStmt *S); + unsigned VisitLabelStmt(LabelStmt *S); unsigned VisitIfStmt(IfStmt *S); unsigned VisitSwitchStmt(SwitchStmt *S); unsigned VisitWhileStmt(WhileStmt *S); unsigned VisitDoStmt(DoStmt *S); unsigned VisitForStmt(ForStmt *S); + unsigned VisitGotoStmt(GotoStmt *S); unsigned VisitContinueStmt(ContinueStmt *S); unsigned VisitBreakStmt(BreakStmt *S); unsigned VisitReturnStmt(ReturnStmt *S); @@ -336,6 +338,15 @@ unsigned PCHStmtReader::VisitDefaultStmt(DefaultStmt *S) { return 1; } +unsigned PCHStmtReader::VisitLabelStmt(LabelStmt *S) { + VisitStmt(S); + S->setID(Reader.GetIdentifierInfo(Record, Idx)); + S->setSubStmt(StmtStack.back()); + S->setIdentLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + Reader.RecordLabelStmt(S, Record[Idx++]); + return 1; +} + unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) { VisitStmt(S); S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 3])); @@ -388,6 +399,14 @@ unsigned PCHStmtReader::VisitForStmt(ForStmt *S) { return 4; } +unsigned PCHStmtReader::VisitGotoStmt(GotoStmt *S) { + VisitStmt(S); + Reader.SetLabelOf(S, Record[Idx++]); + S->setGotoLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setLabelLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + unsigned PCHStmtReader::VisitContinueStmt(ContinueStmt *S) { VisitStmt(S); S->setContinueLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); @@ -2172,6 +2191,10 @@ Stmt *PCHReader::ReadStmt() { S = new (Context) DefaultStmt(Empty); break; + case pch::STMT_LABEL: + S = new (Context) LabelStmt(Empty); + break; + case pch::STMT_IF: S = new (Context) IfStmt(Empty); break; @@ -2192,6 +2215,10 @@ Stmt *PCHReader::ReadStmt() { S = new (Context) ForStmt(Empty); break; + case pch::STMT_GOTO: + S = new (Context) GotoStmt(Empty); + break; + case pch::STMT_CONTINUE: S = new (Context) ContinueStmt(Empty); break; @@ -2342,7 +2369,7 @@ Stmt *PCHReader::ReadStmt() { } } - assert(Idx == Record.size() && "Invalid deserialization of expression"); + assert(Idx == Record.size() && "Invalid deserialization of statement"); StmtStack.push_back(S); } assert(StmtStack.size() == 1 && "Extra expressions on stack!"); @@ -2376,3 +2403,39 @@ SwitchCase *PCHReader::getSwitchCaseWithID(unsigned ID) { assert(SwitchCaseStmts[ID] != 0 && "No SwitchCase with this ID"); return SwitchCaseStmts[ID]; } + +/// \brief Record that the given label statement has been +/// deserialized and has the given ID. +void PCHReader::RecordLabelStmt(LabelStmt *S, unsigned ID) { + assert(LabelStmts.find(ID) == LabelStmts.end() && + "Deserialized label twice"); + LabelStmts[ID] = S; + + // If we've already seen any goto statements that point to this + // label, resolve them now. + typedef std::multimap<unsigned, GotoStmt *>::iterator GotoIter; + std::pair<GotoIter, GotoIter> Gotos = UnresolvedGotoStmts.equal_range(ID); + for (GotoIter Goto = Gotos.first; Goto != Gotos.second; ++Goto) + Goto->second->setLabel(S); + UnresolvedGotoStmts.erase(Gotos.first, Gotos.second); +} + +/// \brief Set the label of the given statement to the label +/// identified by ID. +/// +/// Depending on the order in which the label and other statements +/// referencing that label occur, this operation may complete +/// immediately (updating the statement) or it may queue the +/// statement to be back-patched later. +void PCHReader::SetLabelOf(GotoStmt *S, unsigned ID) { + std::map<unsigned, LabelStmt *>::iterator Label = LabelStmts.find(ID); + if (Label != LabelStmts.end()) { + // We've already seen this label, so set the label of the goto and + // we're done. + S->setLabel(Label->second); + } else { + // We haven't seen this label yet, so add this goto to the set of + // unresolved goto statements. + UnresolvedGotoStmts.insert(std::make_pair(ID, S)); + } +} diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 4b4e897166..bde859665f 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -451,11 +451,13 @@ namespace { void VisitSwitchCase(SwitchCase *S); void VisitCaseStmt(CaseStmt *S); void VisitDefaultStmt(DefaultStmt *S); + void VisitLabelStmt(LabelStmt *S); void VisitIfStmt(IfStmt *S); void VisitSwitchStmt(SwitchStmt *S); void VisitWhileStmt(WhileStmt *S); void VisitDoStmt(DoStmt *S); void VisitForStmt(ForStmt *S); + void VisitGotoStmt(GotoStmt *S); void VisitContinueStmt(ContinueStmt *S); void VisitBreakStmt(BreakStmt *S); void VisitReturnStmt(ReturnStmt *S); @@ -536,6 +538,15 @@ void PCHStmtWriter::VisitDefaultStmt(DefaultStmt *S) { Code = pch::STMT_DEFAULT; } +void PCHStmtWriter::VisitLabelStmt(LabelStmt *S) { + VisitStmt(S); + Writer.AddIdentifierRef(S->getID(), Record); + Writer.WriteSubStmt(S->getSubStmt()); + Writer.AddSourceLocation(S->getIdentLoc(), Record); + Record.push_back(Writer.GetLabelID(S)); + Code = pch::STMT_LABEL; +} + void PCHStmtWriter::VisitIfStmt(IfStmt *S) { VisitStmt(S); Writer.WriteSubStmt(S->getCond()); @@ -582,6 +593,14 @@ void PCHStmtWriter::VisitForStmt(ForStmt *S) { Code = pch::STMT_FOR; } +void PCHStmtWriter::VisitGotoStmt(GotoStmt *S) { + VisitStmt(S); + Record.push_back(Writer.GetLabelID(S->getLabel())); + Writer.AddSourceLocation(S->getGotoLoc(), Record); + Writer.AddSourceLocation(S->getLabelLoc(), Record); + Code = pch::STMT_GOTO; +} + void PCHStmtWriter::VisitContinueStmt(ContinueStmt *S) { VisitStmt(S); Writer.AddSourceLocation(S->getContinueLoc(), Record); @@ -1857,3 +1876,15 @@ unsigned PCHWriter::getSwitchCaseID(SwitchCase *S) { "SwitchCase hasn't been seen yet"); return SwitchCaseIDs[S]; } + +/// \brief Retrieve the ID for the given label statement, which may +/// or may not have been emitted yet. +unsigned PCHWriter::GetLabelID(LabelStmt *S) { + std::map<LabelStmt *, unsigned>::iterator Pos = LabelIDs.find(S); + if (Pos != LabelIDs.end()) + return Pos->second; + + unsigned NextID = LabelIDs.size(); + LabelIDs[S] = NextID; + return NextID; +} diff --git a/test/PCH/stmts.h b/test/PCH/stmts.h index 685811ad08..f1cd815268 100644 --- a/test/PCH/stmts.h +++ b/test/PCH/stmts.h @@ -33,17 +33,25 @@ void f0(int x) { continue; } else if (x < 5) break; + else + goto done; } do { x++; } while (x < 10); + almost_done: for (int y = x; y < 20; ++y) { if (x + y == 12) return; + else if (x - y == 7) + goto almost_done; } + done: + x = x + 2; + int z = x, *y, j = 5; } |