Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -2502,7 +2502,11 @@ */ CXCursor_OMPTargetTeamsDistributeSimdDirective = 279, - CXCursor_LastStmt = CXCursor_OMPTargetTeamsDistributeSimdDirective, + /** \brief Intercal compatibility. + */ + CXCursor_ComeFromStmt = 280, + + CXCursor_LastStmt = CXCursor_ComeFromStmt, /** * \brief Cursor that represents the translation unit itself. Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2147,6 +2147,7 @@ DEF_TRAVERSE_STMT(DoStmt, {}) DEF_TRAVERSE_STMT(ForStmt, {}) DEF_TRAVERSE_STMT(GotoStmt, {}) +DEF_TRAVERSE_STMT(ComeFromStmt, {}) DEF_TRAVERSE_STMT(IfStmt, {}) DEF_TRAVERSE_STMT(IndirectGotoStmt, {}) DEF_TRAVERSE_STMT(LabelStmt, {}) Index: include/clang/AST/Stmt.h =================================================================== --- include/clang/AST/Stmt.h +++ include/clang/AST/Stmt.h @@ -1285,6 +1285,40 @@ } }; +/// ComeFromStmt - This represents a comefrom statement. +/// +class ComeFromStmt : public Stmt { + LabelDecl *Label; + SourceLocation ComeFromLoc; + SourceLocation LabelLoc; +public: + ComeFromStmt(LabelDecl *label, SourceLocation CFL, SourceLocation LL) + : Stmt(ComeFromStmtClass), Label(label), ComeFromLoc(CFL), LabelLoc(LL) {} + + /// \brief Build an empty comefrom statement. + explicit ComeFromStmt(EmptyShell Empty) : Stmt(ComeFromStmtClass, Empty) { } + + LabelDecl *getLabel() const { return Label; } + void setLabel(LabelDecl *D) { Label = D; } + + SourceLocation getComeFromLoc() const { return ComeFromLoc; } + void setComeFromLoc(SourceLocation L) { ComeFromLoc = L; } + SourceLocation getLabelLoc() const { return LabelLoc; } + void setLabelLoc(SourceLocation L) { LabelLoc = L; } + + SourceLocation getLocStart() const LLVM_READONLY { return ComeFromLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return LabelLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ComeFromStmtClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + /// GotoStmt - This represents a direct goto. class GotoStmt : public Stmt { LabelDecl *Label; Index: include/clang/Basic/StmtNodes.td =================================================================== --- include/clang/Basic/StmtNodes.td +++ include/clang/Basic/StmtNodes.td @@ -20,6 +20,7 @@ def ForStmt : Stmt; def GotoStmt : Stmt; def IndirectGotoStmt : Stmt; +def ComeFromStmt : Stmt; def ContinueStmt : Stmt; def BreakStmt : Stmt; def ReturnStmt : Stmt; Index: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -276,6 +276,7 @@ KEYWORD(float , KEYALL) KEYWORD(for , KEYALL) KEYWORD(goto , KEYALL) +KEYWORD(comefrom , KEYALL) KEYWORD(if , KEYALL) KEYWORD(inline , KEYC99|KEYCXX|KEYGNU) KEYWORD(int , KEYALL) Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -1776,6 +1776,7 @@ StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc); StmtResult ParseDoStatement(); StmtResult ParseForStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseComeFromStatement(); StmtResult ParseGotoStatement(); StmtResult ParseContinueStatement(); StmtResult ParseBreakStatement(); Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3775,6 +3775,9 @@ BuildForRangeKind Kind); StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body); + StmtResult ActOnComeFromStmt(SourceLocation GotoLoc, + SourceLocation LabelLoc, + LabelDecl *TheDecl); StmtResult ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, LabelDecl *TheDecl); Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -343,6 +343,11 @@ PrintRawCompoundStmt(Node->getSubStmt()); } +void StmtPrinter::VisitComeFromStmt(ComeFromStmt *Node) { + Indent() << "comefrom " << Node->getLabel()->getName() << ";"; + if (Policy.IncludeNewlines) OS << "\n"; +} + void StmtPrinter::VisitGotoStmt(GotoStmt *Node) { Indent() << "goto " << Node->getLabel()->getName() << ";"; if (Policy.IncludeNewlines) OS << "\n"; Index: lib/CodeGen/CGStmt.cpp =================================================================== --- lib/CodeGen/CGStmt.cpp +++ lib/CodeGen/CGStmt.cpp @@ -96,6 +96,7 @@ case Stmt::LabelStmtClass: case Stmt::AttributedStmtClass: case Stmt::GotoStmtClass: + case Stmt::ComeFromStmtClass: case Stmt::BreakStmtClass: case Stmt::ContinueStmtClass: case Stmt::DefaultStmtClass: @@ -356,6 +357,7 @@ case Stmt::AttributedStmtClass: EmitAttributedStmt(cast(*S)); break; case Stmt::GotoStmtClass: EmitGotoStmt(cast(*S)); break; + case Stmt::ComeFromStmtClass: EmitComeFromStmt(cast(*S)); break; case Stmt::BreakStmtClass: EmitBreakStmt(cast(*S)); break; case Stmt::ContinueStmtClass: EmitContinueStmt(cast(*S)); break; case Stmt::DefaultStmtClass: EmitDefaultStmt(cast(*S)); break; @@ -559,8 +561,13 @@ void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) { - EmitLabel(S.getDecl()); - EmitStmt(S.getSubStmt()); + JumpDest &Dest = ComeFromMap[S.getDecl()]; + if (Dest.isValid()) { + EmitBranchThroughCleanup(Dest); + } else { + EmitLabel(S.getDecl()); + EmitStmt(S.getSubStmt()); + } } void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) { @@ -577,6 +584,11 @@ EmitBranchThroughCleanup(getJumpDestForLabel(S.getLabel())); } +void CodeGenFunction::EmitComeFromStmt(const ComeFromStmt &S) { + auto L = S.getLabel(); + EmitLabel(L); + ComeFromMap[L] = getJumpDestForLabel(L); +} void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) { if (const LabelDecl *Target = S.getConstantTarget()) { Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -1108,6 +1108,9 @@ /// LabelMap - This keeps track of the LLVM basic block for each C label. llvm::DenseMap LabelMap; + /// ComeFromMap - This keeps track of the LLVM basic block for each comefrom stmt. + llvm::DenseMap ComeFromMap; + // BreakContinueStack - This keeps track of where break and continue // statements should jump to. struct BreakContinue { @@ -2625,6 +2628,7 @@ void EmitLabelStmt(const LabelStmt &S); void EmitAttributedStmt(const AttributedStmt &S); + void EmitComeFromStmt(const ComeFromStmt &S); void EmitGotoStmt(const GotoStmt &S); void EmitIndirectGotoStmt(const IndirectGotoStmt &S); void EmitIfStmt(const IfStmt &S); Index: lib/Parse/ParseStmt.cpp =================================================================== --- lib/Parse/ParseStmt.cpp +++ lib/Parse/ParseStmt.cpp @@ -254,6 +254,10 @@ Res = ParseGotoStatement(); SemiError = "goto"; break; + case tok::kw_comefrom: // Intercal compatibility + Res = ParseComeFromStatement(); + SemiError = "comefrom"; + break; case tok::kw_continue: // C99 6.8.6.2: continue-statement Res = ParseContinueStatement(); SemiError = "continue"; @@ -1861,6 +1865,31 @@ return Res; } +/// ParseComeFromStatement +/// jump-statement: +/// 'comefrom' identifier ';' +/// +/// Note: this lets the caller parse the end ';'. +/// +StmtResult Parser::ParseComeFromStatement() { + assert(Tok.is(tok::kw_comefrom) && "Not a comefrom stmt!"); + SourceLocation ComeFromLoc = ConsumeToken(); // eat the 'comefrom'. + + StmtResult Res; + if (Tok.is(tok::identifier)) { + LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(), + Tok.getLocation()); + Res = Actions.ActOnComeFromStmt(ComeFromLoc, Tok.getLocation(), LD); + ConsumeToken(); + } else { + Diag(Tok, diag::err_expected) << tok::identifier; + return StmtError(); + } + + return Res; +} + + /// ParseContinueStatement /// jump-statement: /// 'continue' ';' Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -1442,6 +1442,10 @@ FoundDecl = true; } + void VisitComeFromStmt(ComeFromStmt *S) { + FoundDecl = true; + } + void VisitCastExpr(CastExpr *E) { if (E->getCastKind() == CK_LValueToRValue) CheckLValueToRValueCast(E->getSubExpr()); @@ -2789,6 +2793,14 @@ return new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc); } +StmtResult Sema::ActOnComeFromStmt(SourceLocation ComeFromLoc, + SourceLocation LabelLoc, + LabelDecl *TheDecl) { + getCurFunction()->setHasBranchIntoScope(); + TheDecl->markUsed(Context); + return new (Context) ComeFromStmt(TheDecl, ComeFromLoc, LabelLoc); +} + StmtResult Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, Expr *E) { Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -6752,6 +6752,12 @@ S->getRParenLoc(), Body.get()); } +template +StmtResult +TreeTransform::TransformComeFromStmt(ComeFromStmt *S) { + return S; +} + template StmtResult TreeTransform::TransformGotoStmt(GotoStmt *S) { Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1358,6 +1358,7 @@ case Stmt::DoStmtClass: case Stmt::ForStmtClass: case Stmt::GotoStmtClass: + case Stmt::ComeFromStmtClass: case Stmt::IfStmtClass: case Stmt::IndirectGotoStmtClass: case Stmt::LabelStmtClass: Index: tools/libclang/CXCursor.cpp =================================================================== --- tools/libclang/CXCursor.cpp +++ tools/libclang/CXCursor.cpp @@ -140,6 +140,10 @@ K = CXCursor_ForStmt; break; + case Stmt::ComeFromStmtClass: + K = CXCursor_ComeFromStmt; + break; + case Stmt::GotoStmtClass: K = CXCursor_GotoStmt; break;