lpereira created this revision.
Herald added a subscriber: cfe-commits.

This commit is part of a grand series of changes that aims to reduce
the amount of evil in the world.  The "goto" statement is one of such
evils that must be fought; however, due to both compatibility reasons,
and lack of support in mainstream compilers, it can't be removed just
now.

This patch implements Intercal's "comefrom" statement in both C and C++
modes.

When comparing to the original implementation, the astute reader will
note that behavior such as producing an error when more than one line
comes from another label or not properly handling when a line comes
from a label and goes to a label.  This is to keep the tone of both C
and C++ languages, with regards to undefined behavior.


Repository:
  rC Clang

https://reviews.llvm.org/D45147

Files:
  include/clang-c/Index.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Stmt.h
  include/clang/Basic/StmtNodes.td
  include/clang/Basic/TokenKinds.def
  include/clang/Parse/Parser.h
  include/clang/Sema/Sema.h
  lib/AST/StmtPrinter.cpp
  lib/CodeGen/CGStmt.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Parse/ParseStmt.cpp
  lib/Sema/SemaStmt.cpp
  lib/Sema/TreeTransform.h
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  tools/libclang/CXCursor.cpp

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;
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: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -6752,6 +6752,12 @@
                                      S->getRParenLoc(), Body.get());
 }
 
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformComeFromStmt(ComeFromStmt *S) {
+  return S;
+}
+
 template<typename Derived>
 StmtResult
 TreeTransform<Derived>::TransformGotoStmt(GotoStmt *S) {
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/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/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<const LabelDecl*, JumpDest> LabelMap;
 
+  /// ComeFromMap - This keeps track of the LLVM basic block for each comefrom stmt.
+  llvm::DenseMap<const LabelDecl*, JumpDest> 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/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<AttributedStmt>(*S)); break;
   case Stmt::GotoStmtClass:     EmitGotoStmt(cast<GotoStmt>(*S));         break;
+  case Stmt::ComeFromStmtClass: EmitComeFromStmt(cast<ComeFromStmt>(*S)); break;
   case Stmt::BreakStmtClass:    EmitBreakStmt(cast<BreakStmt>(*S));       break;
   case Stmt::ContinueStmtClass: EmitContinueStmt(cast<ContinueStmt>(*S)); break;
   case Stmt::DefaultStmtClass:  EmitDefaultStmt(cast<DefaultStmt>(*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/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: 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: 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/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/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/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/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-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.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D45147: [cla... Leandro A. F. Pereira via Phabricator via cfe-commits

Reply via email to