OpenMP threadprivate directive parsing and semantic analysis

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177705 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
new file mode 100644
index 0000000..507a6b1
--- /dev/null
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -0,0 +1,118 @@
+//===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file implements parsing of all OpenMP directives and clauses.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "RAIIObjectsForParser.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// OpenMP declarative directives.
+//===----------------------------------------------------------------------===//
+
+/// \brief Parses OpenMP declarative directive
+///       threadprivate-directive
+///         annot_pragma_openmp threadprivate simple-variable-list
+///
+Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
+  assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+
+  SourceLocation Loc = ConsumeToken();
+  SmallVector<DeclarationNameInfo, 5> Identifiers;
+  OpenMPDirectiveKind Kind = Tok.isAnnotation() ?
+                                 OMPD_unknown :
+                                 getOpenMPDirectiveKind(PP.getSpelling(Tok));
+  switch(Kind) {
+  case OMPD_threadprivate:
+    ConsumeToken();
+    if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers)) {
+      // The last seen token is annot_pragma_openmp_end - need to check for
+      // extra tokens.
+      if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+        Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+          << getOpenMPDirectiveName(OMPD_threadprivate);
+        SkipUntil(tok::annot_pragma_openmp_end, false, true);
+      }
+      ConsumeToken();
+      return Actions.ActOnOpenMPThreadprivateDirective(Loc,
+                                                       getCurScope(),
+                                                       Identifiers);
+    }
+    break;
+  case OMPD_unknown:
+    Diag(Tok, diag::err_omp_unknown_directive);
+    break;
+  default:
+    Diag(Tok, diag::err_omp_unexpected_directive)
+      << getOpenMPDirectiveName(Kind);
+    break;
+  }
+  SkipUntil(tok::annot_pragma_openmp_end, false);
+  return DeclGroupPtrTy();
+}
+
+/// \brief Parses list of simple variables for '#pragma omp threadprivate'
+/// directive
+/// simple-variable-list:
+///   ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end
+///
+bool Parser::ParseOpenMPSimpleVarList(
+  OpenMPDirectiveKind Kind,
+  SmallVectorImpl<DeclarationNameInfo> &IdList) {
+  // Parse '('.
+  bool IsCorrect = true;
+  BalancedDelimiterTracker T(*this, tok::l_paren);
+  if (T.expectAndConsume(diag::err_expected_lparen_after,
+                         getOpenMPDirectiveName(Kind))) {
+    SkipUntil(tok::annot_pragma_openmp_end, false, true);
+    return false;
+  }
+
+  // Read tokens while ')' or annot_pragma_openmp_end is not found.
+  do {
+    CXXScopeSpec SS;
+    SourceLocation TemplateKWLoc;
+    UnqualifiedId Name;
+    // Read var name.
+    Token PrevTok = Tok;
+
+    if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
+                           TemplateKWLoc, Name)) {
+      IsCorrect = false;
+      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+                false, true);
+    }
+    else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
+             Tok.isNot(tok::annot_pragma_openmp_end)) {
+      IsCorrect = false;
+      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+                false, true);
+      Diag(PrevTok.getLocation(), diag::err_expected_unqualified_id)
+        << getLangOpts().CPlusPlus
+        << SourceRange(PrevTok.getLocation(), PrevTokLocation);
+    } else {
+      IdList.push_back(Actions.GetNameFromUnqualifiedId(Name));
+    }
+    // Consume ','.
+    if (Tok.is(tok::comma)) {
+      ConsumeToken();
+    }
+  } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end));
+
+  if (IsCorrect || Tok.is(tok::r_paren)) {
+    IsCorrect = !T.consumeClose() && IsCorrect;
+  }
+
+  return !IsCorrect && IdList.empty();
+}