Feature:
  OpenMP support.

Sub-Feature:
  Support for "#pragma omp ..." registration with
  Preprocessor.

Files Changed/Added:
  * include/clang/Basic/DiagnosticGroups.td (C)
  * include/clang/Basic/DiagnosticParseKinds.td (C)
  * include/clang/Basic/TokenKinds.def (C)
  * include/clang/Parse/Parser.h (C)
  * lib/Parse/Parser.cpp (C)

Test Cases Changed/Added:
  * test/Preprocessor/pragma_omp.c (A)
  * test/Preprocessor/pragma_omp_ignored_warning.c (A)


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166869 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 1635633..e6c10e5 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -251,6 +251,7 @@
 def UninitializedSometimes : DiagGroup<"sometimes-uninitialized">;
 def Uninitialized  : DiagGroup<"uninitialized", [UninitializedSometimes]>;
 def UnknownPragmas : DiagGroup<"unknown-pragmas">;
+def OpenMPPragmas  : DiagGroup<"openmp-pragmas">;
 def NSobjectAttribute : DiagGroup<"NSObject-attribute">;
 def UnknownAttributes : DiagGroup<"attributes">;
 def IgnoredAttributes : DiagGroup<"ignored-attributes">;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 51270ab..ca1ed31 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -734,6 +734,11 @@
   "'#pragma fp_contract' should only appear at file scope or at the start of a "
   "compound expression">; 
 
+// OpenMP
+def warn_pragma_omp_ignored : Warning<
+  "pragma omp ignored; did you forget to add '-fopenmp' flag?">,
+  InGroup<OpenMPPragmas>;
+
 // OpenCL Section 6.8.g
 def err_not_opencl_storage_class_specifier : Error<
   "OpenCL does not support the '%0' storage class specifier">;
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 25e8d5a..ed43e17 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -637,6 +637,42 @@
 // handles them.
 ANNOTATION(pragma_opencl_extension)
 
+// Annotations for OpenMP pragma directive statements - "\#pragam omp ..."
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+//
+// Note that OpenMP pragma annotations below are listed in the same order
+// as listed in the OpenMP 3.1 standard specification document. Please do
+// *adhere* to the same order.
+
+// OpenMP parallel constructs.
+ANNOTATION(pragma_omp_parallel)
+
+// OpenMP work sharing constructs.
+ANNOTATION(pragma_omp_for)
+ANNOTATION(pragma_omp_sections)
+ANNOTATION(pragma_omp_single)
+ANNOTATION(pragma_omp_section)
+
+// OpenMP combined parallel work sharing constructs.
+// TODO
+
+// OpenMP tasking constructs.
+ANNOTATION(pragma_omp_task)
+ANNOTATION(pragma_omp_taskyield)
+
+// OpenMP master and synchronization constructs.
+ANNOTATION(pragma_omp_master)
+ANNOTATION(pragma_omp_critical)
+ANNOTATION(pragma_omp_barrier)
+ANNOTATION(pragma_omp_taskwait)
+ANNOTATION(pragma_omp_atomic)
+ANNOTATION(pragma_omp_flush)
+ANNOTATION(pragma_omp_ordered)
+
+// OpenMP data environment related constructs. 
+ANNOTATION(pragma_omp_threadprivate)
+
 #undef ANNOTATION
 #undef TESTING_KEYWORD
 #undef OBJC2_AT_KEYWORD
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 20b13ba..852e77f 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -43,6 +43,7 @@
   class InMessageExpressionRAIIObject;
   class PoisonSEHIdentifiersRAIIObject;
   class VersionTuple;
+  class OpenMP;
 
 /// PrettyStackTraceParserEntry - If a crash happens while the parser is active,
 /// an entry is printed for it.
@@ -180,6 +181,8 @@
   OwningPtr<PragmaHandler> OpenCLExtensionHandler;
   OwningPtr<CommentHandler> CommentSemaHandler;
 
+  OwningPtr<OpenMP> OpenMPHandler;
+
   /// Whether the '>' token acts as an operator or not. This will be
   /// true except when we are parsing an expression within a C++
   /// template argument list, where the '>' closes the template
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 99c3636..5a23573 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -23,6 +23,237 @@
 #include "clang/AST/ASTConsumer.h"
 using namespace clang;
 
+
+namespace clang {
+
+/// \brief An instance of this interface is defined to initiate OpenMP parsing,
+/// and to help Parser during subsequent parsing of OpenMP constrcuts.
+class OpenMP {
+  // Private Member Objects.
+private:
+  // \brief The member object reference to the Preprocessor.
+  Preprocessor &PP;
+
+  // \brief Handler objects which handle different OpenMP pragma directive
+  // statements.
+  OwningPtr<PragmaHandler> ParallelHandler;
+  OwningPtr<PragmaHandler> ForHandler;
+  OwningPtr<PragmaHandler> SectionsHandler;
+  OwningPtr<PragmaHandler> SectionHandler;
+  OwningPtr<PragmaHandler> SingleHandler;
+  OwningPtr<PragmaHandler> TaskHandler;
+  OwningPtr<PragmaHandler> MasterHandler;
+  OwningPtr<PragmaHandler> CriticalHandler;
+  OwningPtr<PragmaHandler> BarrierHandler;
+  OwningPtr<PragmaHandler> TaskwaitHandler;
+  OwningPtr<PragmaHandler> TaskyieldHandler;
+  OwningPtr<PragmaHandler> AtomicHandler;
+  OwningPtr<PragmaHandler> FlushHandler;
+  OwningPtr<PragmaHandler> OrderedHandler;
+  OwningPtr<PragmaHandler> ThreadPrivateHandler;
+
+  // \brief When an OpenMP pragma is ignored, we emit a warning message
+  // saying so, but only once per translation unit irrespective of the
+  // number of OpenMP pragmas appeared in the translation unit. This flag
+  // keeps track of whether the unkown pragma warning message is emitted
+  // or not for the current translation unit.
+  bool OmpUnknownWarned;
+
+  // Private Member Methods.
+private:
+  // \brief When source contains omp pragmas, but user does not pass the
+  // '-fopenmp' flag, we emit a warning message saying so, but only once per
+  // source file.
+  void SetPragmaOmpUnknownWarned() { OmpUnknownWarned = true; }
+  void ResetPragmaOmpUnknownWarned() { OmpUnknownWarned = false; }
+  bool PragmaOmpUnknownWarned() { return OmpUnknownWarned; }
+  
+  // \brief Handles "\#pragma omp ...". 
+  // It Checks if the user has passed the flag, '-fopenmp', if so,
+  // it enters the *token* which is *representing* the current OpenMP
+  // pragma *directive* into the TokenStream, so that the Parser can
+  // recognizes it and can parse the respective OpenMP pragma directive
+  // statement. Otherwise, it reports a warning that the current OpenMP
+  // directive statement will be ignored. However, note that only
+  // *one* warning message per translation unit is reported
+  // irrespective of the number of OpenMP directive statments which
+  // appear in the translation unit.
+  void HandlePragma(Token &OmpTok, tok::TokenKind TKind) {
+    if (!PP.getLangOpts().OpenMP) {
+      if (!PragmaOmpUnknownWarned()) {
+        PP.Diag(OmpTok, diag::warn_pragma_omp_ignored);
+        SetPragmaOmpUnknownWarned();
+      }
+    } else {
+      Token *Toks = new Token[1];
+      Toks[0].startToken();
+      Toks[0].setKind(TKind);
+      Toks[0].setLocation(OmpTok.getLocation());
+      PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
+                          /*OwnsTokens=*/false);
+    }
+  }
+
+  // Constructors and Destructors.
+public:
+  OpenMP(Preprocessor &pp);
+  ~OpenMP();
+
+private:
+  // \brief An OpenMP pragma handler interface. It acts as an intermediate
+  // between the Preprocessor class and the OpenMP (this) class. It by passes
+  // the omp pragma handling call to OpenMP class upon requested by the
+  // Preprocessor.
+  struct PragmaOmpHandler : public PragmaHandler {
+    friend class OpenMP;
+    tok::TokenKind TKind;
+    OpenMP *Omp;
+    PragmaOmpHandler(tok::TokenKind Kind, StringRef Name, OpenMP *omp)
+    : PragmaHandler(Name), TKind(Kind), Omp(omp) {}
+    virtual ~PragmaOmpHandler() { Omp = 0; }
+    virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+                              Token &OmpTok) {
+      Omp->HandlePragma(OmpTok, TKind);
+    }
+  };
+};
+
+} // end of namespace clang
+
+OpenMP::OpenMP(Preprocessor &pp)
+  : PP(pp) {
+
+  // Add "#pragma omp ..." handlers. These are removed and destroyed
+  // in the destructor.
+  //
+  // Note that OpenMP pragma annotations below are listed in the same order
+  // as listed in the OpenMP 3.1 standard specification document. Please
+  // do *adhere* to the same order.
+
+  // OpenMP parallel constructs.
+  ParallelHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_parallel, "parallel", this));
+  PP.AddPragmaHandler("omp", ParallelHandler.get());
+
+  // OpenMP work sharing constructs.
+  ForHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_for, "for", this));
+  PP.AddPragmaHandler("omp", ForHandler.get());
+
+  SectionsHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_sections, "sections", this));
+  PP.AddPragmaHandler("omp", SectionsHandler.get());
+
+  SingleHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_single, "single", this));
+  PP.AddPragmaHandler("omp", SingleHandler.get());
+
+  SectionHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_section, "section", this));
+  PP.AddPragmaHandler("omp", SectionHandler.get());
+
+  // OpenMP combined parallel work sharing constructs.
+  // FIXME: not supported yet.
+
+  // OpenMP tasking constructs.
+  TaskHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_task, "task", this));
+  PP.AddPragmaHandler("omp", TaskHandler.get());
+
+  TaskyieldHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_taskyield, "taskyield", this));
+  PP.AddPragmaHandler("omp", TaskyieldHandler.get());
+
+  // OpenMP master and synchronization constructs.
+  MasterHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_master, "master", this));
+  PP.AddPragmaHandler("omp", MasterHandler.get());
+
+  CriticalHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_critical, "critical", this));
+  PP.AddPragmaHandler("omp", CriticalHandler.get());
+
+  BarrierHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_barrier, "barrier", this));
+  PP.AddPragmaHandler("omp", BarrierHandler.get());
+
+  TaskwaitHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_taskwait, "taskwait", this));
+  PP.AddPragmaHandler("omp", TaskwaitHandler.get());
+
+  AtomicHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_atomic, "atomic", this));
+  PP.AddPragmaHandler("omp", AtomicHandler.get());
+
+  FlushHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_flush, "flush", this));
+  PP.AddPragmaHandler("omp", FlushHandler.get());
+
+  OrderedHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_ordered, "ordered", this));
+  PP.AddPragmaHandler("omp", OrderedHandler.get());
+
+  // OpenMP data environment related constructs.
+  ThreadPrivateHandler.reset(new PragmaOmpHandler(
+              tok::annot_pragma_omp_threadprivate, "threadprivate", this));
+  PP.AddPragmaHandler("omp", ThreadPrivateHandler.get());
+
+  // We have not yet reported the unknown OpenMP pragma *warning* message
+  // as we have not yet started the processing of translation unit.
+  ResetPragmaOmpUnknownWarned();
+}
+
+OpenMP::~OpenMP() {
+  // Remove the "#pragma omp ..." handlers we installed.
+  //
+  // Note that OpenMP pragma annotations below are listed in the same order
+  // as listed in the OpenMP 3.1 standard specification document. Please
+  // do *adhere* to the same order.
+
+  // OpenMP parallel constructs.
+  PP.RemovePragmaHandler("omp", ParallelHandler.get());
+  ParallelHandler.reset();
+
+  // OpenMP work sharing constructs.
+  PP.RemovePragmaHandler("omp", ForHandler.get());
+  ForHandler.reset();
+  PP.RemovePragmaHandler("omp", SectionsHandler.get());
+  SectionsHandler.reset();
+  PP.RemovePragmaHandler("omp", SingleHandler.get());
+  SingleHandler.reset();
+  PP.RemovePragmaHandler("omp", SectionHandler.get());
+  SectionHandler.reset();
+
+  // OpenMP combined parallel work sharing constructs.
+  // FIXME: Yet to support.
+
+  // OpenMP tasking constructs.
+  PP.RemovePragmaHandler("omp", TaskHandler.get());
+  TaskHandler.reset();
+  PP.RemovePragmaHandler("omp", TaskyieldHandler.get());
+  TaskyieldHandler.reset();
+
+  // OpenMP master and synchronization constructs.
+  PP.RemovePragmaHandler("omp", MasterHandler.get());
+  MasterHandler.reset();
+  PP.RemovePragmaHandler("omp", CriticalHandler.get());
+  CriticalHandler.reset();
+  PP.RemovePragmaHandler("omp", BarrierHandler.get());
+  BarrierHandler.reset();
+  PP.RemovePragmaHandler("omp", TaskwaitHandler.get());
+  TaskwaitHandler.reset();
+  PP.RemovePragmaHandler("omp", AtomicHandler.get());
+  AtomicHandler.reset();
+  PP.RemovePragmaHandler("omp", FlushHandler.get());
+  FlushHandler.reset();
+  PP.RemovePragmaHandler("omp", OrderedHandler.get());
+  OrderedHandler.reset();
+
+  // OpenMP data environment related constructs.
+  PP.RemovePragmaHandler("omp", ThreadPrivateHandler.get());
+  ThreadPrivateHandler.reset();
+}
+
 namespace {
 /// \brief A comment handler that passes comments found by the preprocessor
 /// to the parser action.
@@ -98,6 +329,8 @@
   PP.addCommentHandler(CommentSemaHandler.get());
 
   PP.setCodeCompletionHandler(*this);
+
+  OpenMPHandler.reset(new OpenMP(pp));
 }
 
 /// If a crash happens while the parser is active, print out a line indicating
@@ -456,6 +689,8 @@
 
   PP.clearCodeCompletionHandler();
 
+  OpenMPHandler.reset();
+
   assert(TemplateIds.empty() && "Still alive TemplateIdAnnotations around?");
 }
 
diff --git a/test/Preprocessor/pragma_omp.c b/test/Preprocessor/pragma_omp.c
new file mode 100644
index 0000000..deb162c
--- /dev/null
+++ b/test/Preprocessor/pragma_omp.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -E -verify %s
+// RUN: %clang_cc1 -E -verify -fopenmp %s
+// RUN: %clang_cc1 -Eonly -verify %s
+// RUN: %clang_cc1 -Eonly -verify -fopenmp %s
+// RUN: %clang_cc1 -E -P -verify %s
+// RUN: %clang_cc1 -E -P -verify -fopenmp %s
+
+int pragma_omp_test() {
+  int i, VarA;
+  #pragma omp parallel // expected-no-diagnostics 
+  {
+    #pragma omp for    // expected-no-diagnostics 
+    for(i=0; i<10; i++) {
+      VarA = 29;
+    }
+  }
+  return VarA;
+}
diff --git a/test/Preprocessor/pragma_omp_ignored_warning.c b/test/Preprocessor/pragma_omp_ignored_warning.c
new file mode 100644
index 0000000..1b6ac8a
--- /dev/null
+++ b/test/Preprocessor/pragma_omp_ignored_warning.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int pragma_omp_ignored_warning_test() {
+  int i, VarA;
+  #pragma omp parallel // expected-warning {{pragma omp ignored; did you forget to add '-fopenmp' flag?}}
+  {
+    #pragma omp for    
+    for(i=0; i<10; i++) {
+      VarA = 29;
+    }
+  }
+  return VarA;
+}