[OPENMP] parsing 'linear' clause (for directive 'omp simd')

Differential Revision: http://reviews.llvm.org/D3272

llvm-svn: 206891
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index f1b6107..bf3753f 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -258,7 +258,7 @@
 ///
 ///    clause:
 ///       if-clause | num_threads-clause | safelen-clause | default-clause |
-///       private-clause | firstprivate-clause | shared-clause
+///       private-clause | firstprivate-clause | shared-clause | linear-clause
 ///
 OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
                                      OpenMPClauseKind CKind, bool FirstClause) {
@@ -301,6 +301,7 @@
   case OMPC_private:
   case OMPC_firstprivate:
   case OMPC_shared:
+  case OMPC_linear:
   case OMPC_copyin:
     Clause = ParseOpenMPVarListClause(CKind);
     break;
@@ -392,10 +393,13 @@
 ///       'firstprivate' '(' list ')'
 ///    shared-clause:
 ///       'shared' '(' list ')'
+///    linear-clause:
+///       'linear' '(' list [ ':' linear-step ] ')'
 ///
 OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
   SourceLocation Loc = Tok.getLocation();
   SourceLocation LOpen = ConsumeToken();
+  SourceLocation ColonLoc = SourceLocation();
   // Parse '('.
   BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
   if (T.expectAndConsume(diag::err_expected_lparen_after,
@@ -404,8 +408,10 @@
 
   SmallVector<Expr *, 5> Vars;
   bool IsComma = true;
-  while (IsComma || (Tok.isNot(tok::r_paren) &&
+  const bool MayHaveTail = (Kind == OMPC_linear);
+  while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
                      Tok.isNot(tok::annot_pragma_openmp_end))) {
+    ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
     // Parse variable
     ExprResult VarExpr = ParseAssignmentExpression();
     if (VarExpr.isUsable()) {
@@ -416,21 +422,34 @@
     }
     // Skip ',' if any
     IsComma = Tok.is(tok::comma);
-    if (IsComma) {
+    if (IsComma)
       ConsumeToken();
-    } else if (Tok.isNot(tok::r_paren) &&
-               Tok.isNot(tok::annot_pragma_openmp_end)) {
-      Diag(Tok, diag::err_omp_expected_punc)
-        << getOpenMPClauseName(Kind);
-    }
+    else if (Tok.isNot(tok::r_paren) &&
+             Tok.isNot(tok::annot_pragma_openmp_end) &&
+             (!MayHaveTail || Tok.isNot(tok::colon)))
+      Diag(Tok, diag::err_omp_expected_punc) << getOpenMPClauseName(Kind);
+  }
+
+  // Parse ':' linear-step
+  Expr *TailExpr = 0;
+  const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
+  if (MustHaveTail) {
+    ColonLoc = Tok.getLocation();
+    ConsumeToken();
+    ExprResult Tail = ParseAssignmentExpression();
+    if (Tail.isUsable())
+      TailExpr = Tail.take();
+    else
+      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+                StopBeforeMatch);
   }
 
   // Parse ')'.
   T.consumeClose();
-  if (Vars.empty())
+  if (Vars.empty() || (MustHaveTail && !TailExpr))
     return 0;
 
-  return Actions.ActOnOpenMPVarListClause(Kind, Vars, Loc, LOpen,
-                                          Tok.getLocation());
+  return Actions.ActOnOpenMPVarListClause(Kind, Vars, TailExpr, Loc, LOpen,
+                                          ColonLoc, Tok.getLocation());
 }