diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index e73162d2fec2..8059ad2f2e04 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1601,12 +1601,22 @@ public: QualType t) : Expr(AddrLabelExprClass, t), AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) {} + /// \brief Build an empty address of a label expression. + explicit AddrLabelExpr(EmptyShell Empty) + : Expr(AddrLabelExprClass, Empty) { } + + SourceLocation getAmpAmpLoc() const { return AmpAmpLoc; } + void setAmpAmpLoc(SourceLocation L) { AmpAmpLoc = L; } + SourceLocation getLabelLoc() const { return LabelLoc; } + void setLabelLoc(SourceLocation L) { LabelLoc = L; } + virtual SourceRange getSourceRange() const { return SourceRange(AmpAmpLoc, LabelLoc); } LabelStmt *getLabel() const { return Label; } - + void setLabel(LabelStmt *S) { Label = S; } + static bool classof(const Stmt *T) { return T->getStmtClass() == AddrLabelExprClass; } diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 29e193174659..d5e4abb949f1 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -852,13 +852,18 @@ public: class IndirectGotoStmt : public Stmt { Stmt *Target; // FIXME: Add location information (e.g. SourceLocation objects). - // When doing so, update the serialization routines. + // When doing so, update the PCH serialization routines. public: IndirectGotoStmt(Expr *target) : Stmt(IndirectGotoStmtClass), Target((Stmt*)target){} + + /// \brief Build an empty indirect goto statement. + explicit IndirectGotoStmt(EmptyShell Empty) + : Stmt(IndirectGotoStmtClass, Empty) { } Expr *getTarget(); const Expr *getTarget() const; + void setTarget(Expr *E) { Target = reinterpret_cast(E); } virtual SourceRange getSourceRange() const { return SourceRange(); } diff --git a/clang/include/clang/Frontend/PCHBitCodes.h b/clang/include/clang/Frontend/PCHBitCodes.h index fceafb096f0c..93b78f100e55 100644 --- a/clang/include/clang/Frontend/PCHBitCodes.h +++ b/clang/include/clang/Frontend/PCHBitCodes.h @@ -397,6 +397,8 @@ namespace clang { STMT_FOR, /// \brief A GotoStmt record. STMT_GOTO, + /// \brief An IndirectGotoStmt record. + STMT_INDIRECT_GOTO, /// \brief A ContinueStmt record. STMT_CONTINUE, /// \brief A BreakStmt record. @@ -405,6 +407,7 @@ namespace clang { STMT_RETURN, /// \brief A DeclStmt record. STMT_DECL, + /// FIXME: An AsmStmt record. /// \brief A PredefinedExpr record. EXPR_PREDEFINED, /// \brief A DeclRefExpr record. @@ -453,7 +456,8 @@ namespace clang { EXPR_IMPLICIT_VALUE_INIT, /// \brief A VAArgExpr record. EXPR_VA_ARG, - // FIXME: AddrLabelExpr + // An AddrLabelExpr record. + EXPR_ADDR_LABEL, // FIXME: StmtExpr /// \brief A TypesCompatibleExpr record. EXPR_TYPES_COMPATIBLE, diff --git a/clang/include/clang/Frontend/PCHReader.h b/clang/include/clang/Frontend/PCHReader.h index c5737976936e..0507cfa5f5c9 100644 --- a/clang/include/clang/Frontend/PCHReader.h +++ b/clang/include/clang/Frontend/PCHReader.h @@ -37,6 +37,7 @@ namespace llvm { namespace clang { +class AddrLabelExpr; class ASTContext; class Attr; class Decl; @@ -143,6 +144,11 @@ private: /// de-serialized. std::multimap UnresolvedGotoStmts; + /// \brief Mapping from label IDs to the set of address label + /// expressions that point to that label before the label itself has + /// been de-serialized. + std::multimap UnresolvedAddrLabelExprs; + PCHReadResult ReadPCHBlock(); bool CheckPredefinesBuffer(const char *PCHPredef, unsigned PCHPredefLen, @@ -278,6 +284,15 @@ public: /// immediately (updating the statement) or it may queue the /// statement to be back-patched later. void SetLabelOf(GotoStmt *S, unsigned ID); + + /// \brief Set the label of the given expression 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(AddrLabelExpr *S, unsigned ID); }; } // end namespace clang diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index 9597b37082ce..8928b063cf23 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/lib/Frontend/PCHReader.cpp @@ -256,6 +256,7 @@ namespace { unsigned VisitDoStmt(DoStmt *S); unsigned VisitForStmt(ForStmt *S); unsigned VisitGotoStmt(GotoStmt *S); + unsigned VisitIndirectGotoStmt(IndirectGotoStmt *S); unsigned VisitContinueStmt(ContinueStmt *S); unsigned VisitBreakStmt(BreakStmt *S); unsigned VisitReturnStmt(ReturnStmt *S); @@ -287,6 +288,7 @@ namespace { unsigned VisitDesignatedInitExpr(DesignatedInitExpr *E); unsigned VisitImplicitValueInitExpr(ImplicitValueInitExpr *E); unsigned VisitVAArgExpr(VAArgExpr *E); + unsigned VisitAddrLabelExpr(AddrLabelExpr *E); unsigned VisitTypesCompatibleExpr(TypesCompatibleExpr *E); unsigned VisitChooseExpr(ChooseExpr *E); unsigned VisitGNUNullExpr(GNUNullExpr *E); @@ -407,6 +409,12 @@ unsigned PCHStmtReader::VisitGotoStmt(GotoStmt *S) { return 0; } +unsigned PCHStmtReader::VisitIndirectGotoStmt(IndirectGotoStmt *S) { + VisitStmt(S); + S->setTarget(cast_or_null(StmtStack.back())); + return 1; +} + unsigned PCHStmtReader::VisitContinueStmt(ContinueStmt *S) { VisitStmt(S); S->setContinueLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); @@ -733,6 +741,14 @@ unsigned PCHStmtReader::VisitVAArgExpr(VAArgExpr *E) { return 1; } +unsigned PCHStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) { + VisitExpr(E); + E->setAmpAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setLabelLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + Reader.SetLabelOf(E, Record[Idx++]); + return 0; +} + unsigned PCHStmtReader::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) { VisitExpr(E); E->setArgType1(Reader.GetType(Record[Idx++])); @@ -2218,6 +2234,10 @@ Stmt *PCHReader::ReadStmt() { case pch::STMT_GOTO: S = new (Context) GotoStmt(Empty); break; + + case pch::STMT_INDIRECT_GOTO: + S = new (Context) IndirectGotoStmt(Empty); + break; case pch::STMT_CONTINUE: S = new (Context) ContinueStmt(Empty); @@ -2335,6 +2355,10 @@ Stmt *PCHReader::ReadStmt() { S = new (Context) VAArgExpr(Empty); break; + case pch::EXPR_ADDR_LABEL: + S = new (Context) AddrLabelExpr(Empty); + break; + case pch::EXPR_TYPES_COMPATIBLE: S = new (Context) TypesCompatibleExpr(Empty); break; @@ -2418,6 +2442,16 @@ void PCHReader::RecordLabelStmt(LabelStmt *S, unsigned ID) { for (GotoIter Goto = Gotos.first; Goto != Gotos.second; ++Goto) Goto->second->setLabel(S); UnresolvedGotoStmts.erase(Gotos.first, Gotos.second); + + // If we've already seen any address-label statements that point to + // this label, resolve them now. + typedef std::multimap::iterator AddrLabelIter; + std::pair AddrLabels + = UnresolvedAddrLabelExprs.equal_range(ID); + for (AddrLabelIter AddrLabel = AddrLabels.first; + AddrLabel != AddrLabels.second; ++AddrLabel) + AddrLabel->second->setLabel(S); + UnresolvedAddrLabelExprs.erase(AddrLabels.first, AddrLabels.second); } /// \brief Set the label of the given statement to the label @@ -2439,3 +2473,23 @@ void PCHReader::SetLabelOf(GotoStmt *S, unsigned ID) { UnresolvedGotoStmts.insert(std::make_pair(ID, S)); } } + +/// \brief Set the label of the given expression 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(AddrLabelExpr *S, unsigned ID) { + std::map::iterator Label = LabelStmts.find(ID); + if (Label != LabelStmts.end()) { + // We've already seen this label, so set the label of the + // label-address expression and we're done. + S->setLabel(Label->second); + } else { + // We haven't seen this label yet, so add this label-address + // expression to the set of unresolved label-address expressions. + UnresolvedAddrLabelExprs.insert(std::make_pair(ID, S)); + } +} diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index bde859665f1f..4bbaaa0c7605 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -458,6 +458,7 @@ namespace { void VisitDoStmt(DoStmt *S); void VisitForStmt(ForStmt *S); void VisitGotoStmt(GotoStmt *S); + void VisitIndirectGotoStmt(IndirectGotoStmt *S); void VisitContinueStmt(ContinueStmt *S); void VisitBreakStmt(BreakStmt *S); void VisitReturnStmt(ReturnStmt *S); @@ -489,6 +490,7 @@ namespace { void VisitDesignatedInitExpr(DesignatedInitExpr *E); void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E); void VisitVAArgExpr(VAArgExpr *E); + void VisitAddrLabelExpr(AddrLabelExpr *E); void VisitTypesCompatibleExpr(TypesCompatibleExpr *E); void VisitChooseExpr(ChooseExpr *E); void VisitGNUNullExpr(GNUNullExpr *E); @@ -601,6 +603,12 @@ void PCHStmtWriter::VisitGotoStmt(GotoStmt *S) { Code = pch::STMT_GOTO; } +void PCHStmtWriter::VisitIndirectGotoStmt(IndirectGotoStmt *S) { + VisitStmt(S); + Writer.WriteSubStmt(S->getTarget()); + Code = pch::STMT_INDIRECT_GOTO; +} + void PCHStmtWriter::VisitContinueStmt(ContinueStmt *S) { VisitStmt(S); Writer.AddSourceLocation(S->getContinueLoc(), Record); @@ -880,6 +888,14 @@ void PCHStmtWriter::VisitVAArgExpr(VAArgExpr *E) { Code = pch::EXPR_VA_ARG; } +void PCHStmtWriter::VisitAddrLabelExpr(AddrLabelExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getAmpAmpLoc(), Record); + Writer.AddSourceLocation(E->getLabelLoc(), Record); + Record.push_back(Writer.GetLabelID(E->getLabel())); + Code = pch::EXPR_ADDR_LABEL; +} + void PCHStmtWriter::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) { VisitExpr(E); Writer.AddTypeRef(E->getArgType1(), Record); diff --git a/clang/test/PCH/stmts.c b/clang/test/PCH/stmts.c index a2278bf16c0c..fc6cfc29a20b 100644 --- a/clang/test/PCH/stmts.c +++ b/clang/test/PCH/stmts.c @@ -8,3 +8,5 @@ void g0(void) { f0(5); } int g1(int x) { return f1(x); } const char* query_name(void) { return what_is_my_name(); } + +int use_computed_goto(int x) { return computed_goto(x); } diff --git a/clang/test/PCH/stmts.h b/clang/test/PCH/stmts.h index f1cd81526801..10842e8b295d 100644 --- a/clang/test/PCH/stmts.h +++ b/clang/test/PCH/stmts.h @@ -68,3 +68,21 @@ int f1(int x) { } const char* what_is_my_name(void) { return __func__; } + +int computed_goto(int x) { + start: + x = x << 1; + void *location = &&start; + + if (x > 17) + location = &&done; + + while (x > 12) { + --x; + if (x == 15) + goto *location; + } + + done: + return 5; +}