r191730 - [OpenMP] Added parsing and semantic analysis for firstprivate clause

Alexey Bataev a.bataev at hotmail.com
Mon Sep 30 22:32:34 PDT 2013


Author: abataev
Date: Tue Oct  1 00:32:34 2013
New Revision: 191730

URL: http://llvm.org/viewvc/llvm-project?rev=191730&view=rev
Log:
[OpenMP] Added parsing and semantic analysis for firstprivate clause

Added:
    cfe/trunk/test/OpenMP/parallel_firstprivate_messages.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/StmtOpenMP.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/OpenMPKinds.def
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/Stmt.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtProfile.cpp
    cfe/trunk/lib/Basic/OpenMPKinds.cpp
    cfe/trunk/lib/Parse/ParseOpenMP.cpp
    cfe/trunk/lib/Sema/SemaOpenMP.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
    cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
    cfe/trunk/test/OpenMP/parallel_ast_print.cpp
    cfe/trunk/test/OpenMP/parallel_private_messages.cpp
    cfe/trunk/test/OpenMP/parallel_shared_messages.cpp
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/tools/libclang/RecursiveASTVisitor.h

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Tue Oct  1 00:32:34 2013
@@ -2367,6 +2367,13 @@ bool RecursiveASTVisitor<Derived>::Visit
 }
 
 template<typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
+                                                    OMPFirstprivateClause *C) {
+  VisitOMPClauseList(C);
+  return true;
+}
+
+template<typename Derived>
 bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
   VisitOMPClauseList(C);
   return true;

Modified: cfe/trunk/include/clang/AST/StmtOpenMP.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtOpenMP.h?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtOpenMP.h (original)
+++ cfe/trunk/include/clang/AST/StmtOpenMP.h Tue Oct  1 00:32:34 2013
@@ -249,6 +249,67 @@ public:
   }
 };
 
+/// \brief This represents clause 'firstprivate' in the '#pragma omp ...'
+/// directives.
+///
+/// \code
+/// #pragma omp parallel firstprivate(a,b)
+/// \endcode
+/// In this example directive '#pragma omp parallel' has clause 'firstprivate'
+/// with the variables 'a' and 'b'.
+///
+class OMPFirstprivateClause : public OMPClause,
+                              public OMPVarList<OMPFirstprivateClause> {
+  /// \brief Build clause with number of variables \a N.
+  ///
+  /// \param StartLoc Starting location of the clause.
+  /// \param LParenLoc Location of '('.
+  /// \param EndLoc Ending location of the clause.
+  /// \param N Number of the variables in the clause.
+  ///
+  OMPFirstprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+                   SourceLocation EndLoc, unsigned N)
+    : OMPClause(OMPC_firstprivate, StartLoc, EndLoc),
+      OMPVarList<OMPFirstprivateClause>(LParenLoc, N) { }
+
+  /// \brief Build an empty clause.
+  ///
+  /// \param N Number of variables.
+  ///
+  explicit OMPFirstprivateClause(unsigned N)
+    : OMPClause(OMPC_firstprivate, SourceLocation(), SourceLocation()),
+      OMPVarList<OMPFirstprivateClause>(SourceLocation(), N) { }
+public:
+  /// \brief Creates clause with a list of variables \a VL.
+  ///
+  /// \param C AST context.
+  /// \param StartLoc Starting location of the clause.
+  /// \param LParenLoc Location of '('.
+  /// \param EndLoc Ending location of the clause.
+  /// \param VL List of references to the variables.
+  ///
+  static OMPFirstprivateClause *Create(const ASTContext &C,
+                                       SourceLocation StartLoc,
+                                       SourceLocation LParenLoc,
+                                       SourceLocation EndLoc,
+                                       ArrayRef<Expr *> VL);
+  /// \brief Creates an empty clause with the place for \a N variables.
+  ///
+  /// \param C AST context.
+  /// \param N The number of variables.
+  ///
+  static OMPFirstprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
+
+  StmtRange children() {
+    return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
+                     reinterpret_cast<Stmt **>(varlist_end()));
+  }
+
+  static bool classof(const OMPClause *T) {
+    return T->getClauseKind() == OMPC_firstprivate;
+  }
+};
+
 /// \brief This represents clause 'shared' in the '#pragma omp ...' directives.
 ///
 /// \code

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Oct  1 00:32:34 2013
@@ -6627,6 +6627,8 @@ def err_omp_var_thread_local : Error<
   "variable %0 cannot be threadprivate because it is thread-local">;
 def err_omp_private_incomplete_type : Error<
   "a private variable with incomplete type %0">;
+def err_omp_firstprivate_incomplete_type : Error<
+  "a firstprivate variable with incomplete type %0">;
 def err_omp_unexpected_clause_value : Error <
   "expected %0 in OpenMP clause '%1'">;
 def err_omp_expected_var_name : Error <

Modified: cfe/trunk/include/clang/Basic/OpenMPKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/OpenMPKinds.def?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/OpenMPKinds.def (original)
+++ cfe/trunk/include/clang/Basic/OpenMPKinds.def Tue Oct  1 00:32:34 2013
@@ -33,11 +33,13 @@ OPENMP_DIRECTIVE(task)
 // OpenMP clauses.
 OPENMP_CLAUSE(default, OMPDefaultClause)
 OPENMP_CLAUSE(private, OMPPrivateClause)
+OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause)
 OPENMP_CLAUSE(shared,  OMPSharedClause)
 
 // Clauses allowed for OpenMP directives.
 OPENMP_PARALLEL_CLAUSE(default)
 OPENMP_PARALLEL_CLAUSE(private)
+OPENMP_PARALLEL_CLAUSE(firstprivate)
 OPENMP_PARALLEL_CLAUSE(shared)
 
 // Static attributes for 'default' clause.

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Oct  1 00:32:34 2013
@@ -7027,6 +7027,11 @@ public:
                                       SourceLocation StartLoc,
                                       SourceLocation LParenLoc,
                                       SourceLocation EndLoc);
+  /// \brief Called on well-formed 'firstprivate' clause.
+  OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
+                                           SourceLocation StartLoc,
+                                           SourceLocation LParenLoc,
+                                           SourceLocation EndLoc);
   /// \brief Called on well-formed 'shared' clause.
   OMPClause *ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
                                      SourceLocation StartLoc,

Modified: cfe/trunk/lib/AST/Stmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Stmt.cpp (original)
+++ cfe/trunk/lib/AST/Stmt.cpp Tue Oct  1 00:32:34 2013
@@ -1145,6 +1145,29 @@ OMPPrivateClause *OMPPrivateClause::Crea
   return new (Mem) OMPPrivateClause(N);
 }
 
+OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C,
+                                                     SourceLocation StartLoc,
+                                                     SourceLocation LParenLoc,
+                                                     SourceLocation EndLoc,
+                                                     ArrayRef<Expr *> VL) {
+  void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) +
+                         sizeof(Expr *) * VL.size(),
+                         llvm::alignOf<OMPFirstprivateClause>());
+  OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc,
+                                                                  LParenLoc,
+                                                                  EndLoc,
+                                                                  VL.size());
+  Clause->setVarRefs(VL);
+  return Clause;
+}
+
+OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C,
+                                                          unsigned N) {
+  void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) + sizeof(Expr *) * N,
+                         llvm::alignOf<OMPFirstprivateClause>());
+  return new (Mem) OMPFirstprivateClause(N);
+}
+
 OMPSharedClause *OMPSharedClause::Create(const ASTContext &C,
                                          SourceLocation StartLoc,
                                          SourceLocation LParenLoc,

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Tue Oct  1 00:32:34 2013
@@ -619,6 +619,14 @@ void OMPClausePrinter::VisitOMPPrivateCl
   }
 }
 
+void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) {
+  if (!Node->varlist_empty()) {
+    OS << "firstprivate";
+    VisitOMPClauseList(Node, '(');
+    OS << ")";
+  }
+}
+
 void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) {
   if (!Node->varlist_empty()) {
     OS << "shared";

Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Tue Oct  1 00:32:34 2013
@@ -278,6 +278,10 @@ void OMPClauseProfiler::VisitOMPClauseLi
 void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) {
   VisitOMPClauseList(C);
 }
+void OMPClauseProfiler::VisitOMPFirstprivateClause(
+                                         const OMPFirstprivateClause *C) {
+  VisitOMPClauseList(C);
+}
 void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) {
   VisitOMPClauseList(C);
 }

Modified: cfe/trunk/lib/Basic/OpenMPKinds.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/OpenMPKinds.cpp?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/OpenMPKinds.cpp (original)
+++ cfe/trunk/lib/Basic/OpenMPKinds.cpp Tue Oct  1 00:32:34 2013
@@ -78,6 +78,7 @@ unsigned clang::getOpenMPSimpleClauseTyp
   case OMPC_unknown:
   case OMPC_threadprivate:
   case OMPC_private:
+  case OMPC_firstprivate:
   case OMPC_shared:
   case NUM_OPENMP_CLAUSES:
     break;
@@ -100,6 +101,7 @@ const char *clang::getOpenMPSimpleClause
   case OMPC_unknown:
   case OMPC_threadprivate:
   case OMPC_private:
+  case OMPC_firstprivate:
   case OMPC_shared:
   case NUM_OPENMP_CLAUSES:
     break;

Modified: cfe/trunk/lib/Parse/ParseOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseOpenMP.cpp?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseOpenMP.cpp (original)
+++ cfe/trunk/lib/Parse/ParseOpenMP.cpp Tue Oct  1 00:32:34 2013
@@ -252,7 +252,7 @@ bool Parser::ParseOpenMPSimpleVarList(Op
 /// \brief Parsing of OpenMP clauses.
 ///
 ///    clause:
-///       default-clause|private-clause|shared-clause
+///       default-clause|private-clause|firstprivate-clause|shared-clause
 ///
 OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
                                      OpenMPClauseKind CKind, bool FirstClause) {
@@ -278,6 +278,7 @@ OMPClause *Parser::ParseOpenMPClause(Ope
     Clause = ParseOpenMPSimpleClause(CKind);
     break;
   case OMPC_private:
+  case OMPC_firstprivate:
   case OMPC_shared:
     Clause = ParseOpenMPVarListClause(CKind);
     break;
@@ -330,6 +331,8 @@ OMPClause *Parser::ParseOpenMPSimpleClau
 ///
 ///    private-clause:
 ///       'private' '(' list ')'
+///    firstprivate-clause:
+///       'firstprivate' '(' list ')'
 ///    shared-clause:
 ///       'shared' '(' list ')'
 ///

Modified: cfe/trunk/lib/Sema/SemaOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOpenMP.cpp?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOpenMP.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOpenMP.cpp Tue Oct  1 00:32:34 2013
@@ -106,6 +106,11 @@ public:
   DSAVarData getTopDSA(VarDecl *D);
   /// \brief Returns data-sharing attributes for the specified declaration.
   DSAVarData getImplicitDSA(VarDecl *D);
+  /// \brief Checks if the specified variables has \a CKind data-sharing
+  /// attribute in \a DKind directive.
+  DSAVarData hasDSA(VarDecl *D, OpenMPClauseKind CKind,
+                    OpenMPDirectiveKind DKind = OMPD_unknown);
+
 
   /// \brief Returns currently analyzed directive.
   OpenMPDirectiveKind getCurrentDirective() const {
@@ -138,6 +143,13 @@ DSAStackTy::DSAVarData DSAStackTy::getDS
     if (!D->isFunctionOrMethodVarDecl())
       DVar.CKind = OMPC_shared;
 
+    // OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced
+    // in a region but not in construct]
+    //  Variables with static storage duration that are declared in called
+    //  routines in the region are shared.
+    if (D->hasGlobalStorage())
+      DVar.CKind = OMPC_shared;
+
     return DVar;
   }
   DVar.DKind = Iter->Directive;
@@ -189,16 +201,14 @@ DSAStackTy::DSAVarData DSAStackTy::getDS
         if (DVarTemp.CKind != OMPC_shared) {
           DVar.RefExpr = 0;
           DVar.DKind = OMPD_task;
-          DVar.CKind = OMPC_unknown;
-          // TODO: should return OMPC_firstprivate
+          DVar.CKind = OMPC_firstprivate;
           return DVar;
         }
         if (I->Directive == OMPD_parallel) break;
       }
       DVar.DKind = OMPD_task;
-      // TODO: Should return OMPC_firstprivate instead of OMPC_unknown.
       DVar.CKind =
-        (DVarTemp.CKind == OMPC_unknown) ? OMPC_unknown : OMPC_shared;
+        (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared;
       return DVar;
     }
   }
@@ -272,9 +282,12 @@ DSAStackTy::DSAVarData DSAStackTy::getTo
   // in a Construct, C/C++, predetermined, p.4]
   //  Static data memebers are shared.
   if (D->isStaticDataMember()) {
-    // Variables with const-qualified type having no mutable member may be
-    // listed in a firstprivate clause, even if they are static data members.
-    // TODO:
+    // Variables with const-qualified type having no mutable member may be listed
+    // in a firstprivate clause, even if they are static data members.
+    DSAVarData DVarTemp = hasDSA(D, OMPC_firstprivate);
+    if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)
+      return DVar;
+
     DVar.CKind = OMPC_shared;
     return DVar;
   }
@@ -295,7 +308,10 @@ DSAStackTy::DSAVarData DSAStackTy::getTo
       !(Actions.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) {
     // Variables with const-qualified type having no mutable member may be
     // listed in a firstprivate clause, even if they are static data members.
-    // TODO
+    DSAVarData DVarTemp = hasDSA(D, OMPC_firstprivate);
+    if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)
+      return DVar;
+
     DVar.CKind = OMPC_shared;
     return DVar;
   }
@@ -323,6 +339,19 @@ DSAStackTy::DSAVarData DSAStackTy::getIm
   return getDSA(Stack.rbegin() + 1, D);
 }
 
+DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, OpenMPClauseKind CKind,
+                                          OpenMPDirectiveKind DKind) {
+  for (StackTy::reverse_iterator I = Stack.rbegin() + 1,
+                                 E = Stack.rend() - 1;
+       I != E; ++I) {
+    if (DKind != OMPD_unknown && DKind != I->Directive) continue;
+    DSAVarData DVar = getDSA(I, D);
+    if (DVar.CKind == CKind)
+      return DVar;
+  }
+  return DSAVarData();
+}
+
 void Sema::InitDataSharingAttributesStack() {
   VarDataSharingAttributesStack = new DSAStackTy(*this);
 }
@@ -551,10 +580,10 @@ class DSAAttrChecker : public StmtVisito
   Sema &Actions;
   bool ErrorFound;
   CapturedStmt *CS;
+  llvm::SmallVector<Expr *, 8> ImplicitFirstprivate;
 public:
   void VisitDeclRefExpr(DeclRefExpr *E) {
     if(VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) {
-      if (VD->isImplicit() && VD->hasAttr<UnusedAttr>()) return;
       // Skip internally declared variables.
       if (VD->isLocalVarDecl() && !CS->capturesVariable(VD)) return;
 
@@ -564,9 +593,8 @@ public:
       DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD);
       if (DVar.CKind != OMPC_unknown) {
         if (DKind == OMPD_task && DVar.CKind != OMPC_shared &&
-            DVar.CKind != OMPC_threadprivate && !DVar.RefExpr) {
-          // TODO: should be marked as firstprivate.
-        }
+            DVar.CKind != OMPC_threadprivate && !DVar.RefExpr)
+          ImplicitFirstprivate.push_back(DVar.RefExpr);
         return;
       }
       // The default(none) clause requires that each variable that is referenced
@@ -588,9 +616,8 @@ public:
 
       // Define implicit data-sharing attributes for task.
       DVar = Stack->getImplicitDSA(VD);
-      if (DKind == OMPD_task && DVar.CKind != OMPC_shared) {
-        // TODO: should be marked as firstprivate.
-      }
+      if (DKind == OMPD_task && DVar.CKind != OMPC_shared)
+        ImplicitFirstprivate.push_back(DVar.RefExpr);
     }
   }
   void VisitOMPExecutableDirective(OMPExecutableDirective *S) {
@@ -611,6 +638,7 @@ public:
     }
 
   bool isErrorFound() { return ErrorFound; }
+  ArrayRef<Expr *> getImplicitFirstprivate() { return ImplicitFirstprivate; }
 
   DSAAttrChecker(DSAStackTy *S, Sema &Actions, CapturedStmt *CS)
     : Stack(S), Actions(Actions), ErrorFound(false), CS(CS) { }
@@ -631,10 +659,27 @@ StmtResult Sema::ActOnOpenMPExecutableDi
   DSAChecker.Visit(cast<CapturedStmt>(AStmt)->getCapturedStmt());
   if (DSAChecker.isErrorFound())
     return StmtError();
+  // Generate list of implicitly defined firstprivate variables.
+  llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit;
+  ClausesWithImplicit.append(Clauses.begin(), Clauses.end());
+
+  bool ErrorFound = false;
+  if (!DSAChecker.getImplicitFirstprivate().empty()) {
+    if (OMPClause *Implicit =
+         ActOnOpenMPFirstprivateClause(DSAChecker.getImplicitFirstprivate(),
+                                       SourceLocation(), SourceLocation(),
+                                       SourceLocation())) {
+      ClausesWithImplicit.push_back(Implicit);
+      ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() !=
+                                    DSAChecker.getImplicitFirstprivate().size();
+    } else
+      ErrorFound = true;
+  }
 
   switch (Kind) {
   case OMPD_parallel:
-    Res = ActOnOpenMPParallelDirective(Clauses, AStmt, StartLoc, EndLoc);
+    Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt,
+                                       StartLoc, EndLoc);
     break;
   case OMPD_threadprivate:
   case OMPD_task:
@@ -643,6 +688,8 @@ StmtResult Sema::ActOnOpenMPExecutableDi
   case NUM_OPENMP_DIRECTIVES:
     llvm_unreachable("Unknown OpenMP directive");
   }
+
+  if (ErrorFound) return StmtError();
   return Res;
 }
 
@@ -670,6 +717,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause
                                ArgumentLoc, StartLoc, LParenLoc, EndLoc);
     break;
   case OMPC_private:
+  case OMPC_firstprivate:
   case OMPC_shared:
   case OMPC_threadprivate:
   case OMPC_unknown:
@@ -731,6 +779,9 @@ OMPClause *Sema::ActOnOpenMPVarListClaus
   case OMPC_private:
     Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc);
     break;
+  case OMPC_firstprivate:
+    Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
+    break;
   case OMPC_shared:
     Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
     break;
@@ -876,6 +927,177 @@ OMPClause *Sema::ActOnOpenMPPrivateClaus
   return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
 }
 
+OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
+                                               SourceLocation StartLoc,
+                                               SourceLocation LParenLoc,
+                                               SourceLocation EndLoc) {
+  SmallVector<Expr *, 8> Vars;
+  for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end();
+       I != E; ++I) {
+    assert(*I && "NULL expr in OpenMP firstprivate clause.");
+    if (isa<DependentScopeDeclRefExpr>(*I)) {
+      // It will be analyzed later.
+      Vars.push_back(*I);
+      continue;
+    }
+
+    SourceLocation ELoc = (*I)->getExprLoc();
+    // OpenMP [2.1, C/C++]
+    //  A list item is a variable name.
+    // OpenMP  [2.9.3.3, Restrictions, p.1]
+    //  A variable that is part of another variable (as an array or
+    //  structure element) cannot appear in a private clause.
+    DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I);
+    if (!DE || !isa<VarDecl>(DE->getDecl())) {
+      Diag(ELoc, diag::err_omp_expected_var_name)
+        << (*I)->getSourceRange();
+      continue;
+    }
+    Decl *D = DE->getDecl();
+    VarDecl *VD = cast<VarDecl>(D);
+
+    QualType Type = VD->getType();
+    if (Type->isDependentType() || Type->isInstantiationDependentType()) {
+      // It will be analyzed later.
+      Vars.push_back(DE);
+      continue;
+    }
+
+    // OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
+    //  A variable that appears in a private clause must not have an incomplete
+    //  type or a reference type.
+    if (RequireCompleteType(ELoc, Type,
+                            diag::err_omp_firstprivate_incomplete_type)) {
+      continue;
+    }
+    if (Type->isReferenceType()) {
+      Diag(ELoc, diag::err_omp_clause_ref_type_arg)
+        << getOpenMPClauseName(OMPC_firstprivate) << Type;
+      bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+                    VarDecl::DeclarationOnly;
+      Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+                                       diag::note_defined_here) << VD;
+      continue;
+    }
+
+    // OpenMP [2.9.3.4, Restrictions, C/C++, p.1]
+    //  A variable of class type (or array thereof) that appears in a private
+    //  clause requires an accesible, unambiguous copy constructor for the
+    //  class type.
+    Type = Context.getBaseElementType(Type);
+    CXXRecordDecl *RD = getLangOpts().CPlusPlus ?
+                          Type.getNonReferenceType()->getAsCXXRecordDecl() : 0;
+    if (RD) {
+      CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0);
+      PartialDiagnostic PD =
+        PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
+      if (!CD ||
+          CheckConstructorAccess(ELoc, CD,
+                                 InitializedEntity::InitializeTemporary(Type),
+                                 CD->getAccess(), PD) == AR_inaccessible ||
+          CD->isDeleted()) {
+        Diag(ELoc, diag::err_omp_required_method)
+             << getOpenMPClauseName(OMPC_firstprivate) << 1;
+        bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+                      VarDecl::DeclarationOnly;
+        Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+                                         diag::note_defined_here) << VD;
+        Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+        continue;
+      }
+      MarkFunctionReferenced(ELoc, CD);
+      DiagnoseUseOfDecl(CD, ELoc);
+
+      CXXDestructorDecl *DD = RD->getDestructor();
+      if (DD) {
+        if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
+            DD->isDeleted()) {
+          Diag(ELoc, diag::err_omp_required_method)
+               << getOpenMPClauseName(OMPC_firstprivate) << 4;
+          bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+                        VarDecl::DeclarationOnly;
+          Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+                                           diag::note_defined_here) << VD;
+          Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+          continue;
+        }
+        MarkFunctionReferenced(ELoc, DD);
+        DiagnoseUseOfDecl(DD, ELoc);
+      }
+    }
+
+    // If StartLoc and EndLoc are invalid - this is an implicit firstprivate
+    // variable and it was checked already.
+    if (StartLoc.isValid() && EndLoc.isValid()) {
+      DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+      Type = Type.getNonReferenceType().getCanonicalType();
+      bool IsConstant = Type.isConstant(Context);
+      Type = Context.getBaseElementType(Type);
+      // OpenMP [2.4.13, Data-sharing Attribute Clauses]
+      //  A list item that specifies a given variable may not appear in more
+      // than one clause on the same directive, except that a variable may be
+      //  specified in both firstprivate and lastprivate clauses.
+      //  TODO: add processing for lastprivate.
+      if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate &&
+          DVar.RefExpr) {
+        Diag(ELoc, diag::err_omp_wrong_dsa)
+           << getOpenMPClauseName(DVar.CKind)
+           << getOpenMPClauseName(OMPC_firstprivate);
+        Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
+           << getOpenMPClauseName(DVar.CKind);
+        continue;
+      }
+
+      // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+      // in a Construct]
+      //  Variables with the predetermined data-sharing attributes may not be
+      //  listed in data-sharing attributes clauses, except for the cases
+      //  listed below. For these exceptions only, listing a predetermined
+      //  variable in a data-sharing attribute clause is allowed and overrides
+      //  the variable's predetermined data-sharing attributes.
+      // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+      // in a Construct, C/C++, p.2]
+      //  Variables with const-qualified type having no mutable member may be
+      //  listed in a firstprivate clause, even if they are static data members.
+      if (!(IsConstant || VD->isStaticDataMember()) && !DVar.RefExpr &&
+          DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) {
+        Diag(ELoc, diag::err_omp_wrong_dsa)
+           << getOpenMPClauseName(DVar.CKind)
+           << getOpenMPClauseName(OMPC_firstprivate);
+        Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
+           << getOpenMPClauseName(DVar.CKind);
+        continue;
+      }
+
+      // OpenMP [2.9.3.4, Restrictions, p.2]
+      //  A list item that is private within a parallel region must not appear
+      //  in a firstprivate clause on a worksharing construct if any of the
+      //  worksharing regions arising from the worksharing construct ever bind
+      //  to any of the parallel regions arising from the parallel construct.
+      // OpenMP [2.9.3.4, Restrictions, p.3]
+      //  A list item that appears in a reduction clause of a parallel construct
+      //  must not appear in a firstprivate clause on a worksharing or task
+      //  construct if any of the worksharing or task regions arising from the
+      //  worksharing or task construct ever bind to any of the parallel regions
+      //  arising from the parallel construct.
+      // OpenMP [2.9.3.4, Restrictions, p.4]
+      //  A list item that appears in a reduction clause in worksharing
+      //  construct must not appear in a firstprivate clause in a task construct
+      //  encountered during execution of any of the worksharing regions arising
+      //  from the worksharing construct.
+      // TODO:
+    }
+
+    DSAStack->addDSA(VD, DE, OMPC_firstprivate);
+    Vars.push_back(DE);
+  }
+
+  if (Vars.empty()) return 0;
+
+  return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+                                       Vars);
+}
+
 OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
                                          SourceLocation StartLoc,
                                          SourceLocation LParenLoc,

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Oct  1 00:32:34 2013
@@ -1313,6 +1313,18 @@ public:
                                               EndLoc);
   }
 
+  /// \brief Build a new OpenMP 'firstprivate' clause.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OMPClause *RebuildOMPFirstprivateClause(ArrayRef<Expr *> VarList,
+                                          SourceLocation StartLoc,
+                                          SourceLocation LParenLoc,
+                                          SourceLocation EndLoc) {
+    return getSema().ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc,
+                                                   EndLoc);
+  }
+
   OMPClause *RebuildOMPSharedClause(ArrayRef<Expr *> VarList,
                                     SourceLocation StartLoc,
                                     SourceLocation LParenLoc,
@@ -6342,6 +6354,26 @@ TreeTransform<Derived>::TransformOMPPriv
 }
 
 template<typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPFirstprivateClause(
+                                                 OMPFirstprivateClause *C) {
+  llvm::SmallVector<Expr *, 16> Vars;
+  Vars.reserve(C->varlist_size());
+  for (OMPFirstprivateClause::varlist_iterator I = C->varlist_begin(),
+                                               E = C->varlist_end();
+       I != E; ++I) {
+    ExprResult EVar = getDerived().TransformExpr(cast<Expr>(*I));
+    if (EVar.isInvalid())
+      return 0;
+    Vars.push_back(EVar.take());
+  }
+  return getDerived().RebuildOMPFirstprivateClause(Vars,
+                                                   C->getLocStart(),
+                                                   C->getLParenLoc(),
+                                                   C->getLocEnd());
+}
+
+template<typename Derived>
 OMPClause *
 TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) {
   llvm::SmallVector<Expr *, 16> Vars;

Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Tue Oct  1 00:32:34 2013
@@ -1697,6 +1697,9 @@ OMPClause *OMPClauseReader::readClause()
   case OMPC_private:
     C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]);
     break;
+  case OMPC_firstprivate:
+    C = OMPFirstprivateClause::CreateEmpty(Context, Record[Idx++]);
+    break;
   case OMPC_shared:
     C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]);
     break;
@@ -1719,6 +1722,16 @@ void OMPClauseReader::VisitOMPPrivateCla
   C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
   unsigned NumVars = C->varlist_size();
   SmallVector<Expr *, 16> Vars;
+  Vars.reserve(NumVars);
+  for (unsigned i = 0; i != NumVars; ++i)
+    Vars.push_back(Reader->Reader.ReadSubExpr());
+  C->setVarRefs(Vars);
+}
+
+void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
+  C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+  unsigned NumVars = C->varlist_size();
+  SmallVector<Expr *, 16> Vars;
   Vars.reserve(NumVars);
   for (unsigned i = 0; i != NumVars; ++i)
     Vars.push_back(Reader->Reader.ReadSubExpr());

Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Tue Oct  1 00:32:34 2013
@@ -1712,6 +1712,15 @@ void OMPClauseWriter::VisitOMPPrivateCla
     Writer->Writer.AddStmt(*I);
 }
 
+void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
+  Record.push_back(C->varlist_size());
+  Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+  for (OMPFirstprivateClause::varlist_iterator I = C->varlist_begin(),
+                                               E = C->varlist_end();
+       I != E; ++I)
+    Writer->Writer.AddStmt(*I);
+}
+
 void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) {
   Record.push_back(C->varlist_size());
   Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);

Modified: cfe/trunk/test/OpenMP/parallel_ast_print.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_ast_print.cpp?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/parallel_ast_print.cpp (original)
+++ cfe/trunk/test/OpenMP/parallel_ast_print.cpp Tue Oct  1 00:32:34 2013
@@ -8,7 +8,41 @@
 
 void foo() {}
 
+
+template <typename T>
+T tmain(T argc, T *argv) {
+  T b = argc, c, d, e, f, g;
+  static T a;
+#pragma omp parallel
+  a=2;
+#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d)
+  foo();
+  return 0;
+}
+// CHECK: template <typename T = int> int tmain(int argc, int *argv) {
+// CHECK-NEXT: int b = argc, c, d, e, f, g;
+// CHECK-NEXT: static int a;
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d)
+// CHECK-NEXT: foo()
+// CHECK: template <typename T = float> float tmain(float argc, float *argv) {
+// CHECK-NEXT: float b = argc, c, d, e, f, g;
+// CHECK-NEXT: static float a;
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d)
+// CHECK-NEXT: foo()
+// CHECK: template <typename T> T tmain(T argc, T *argv) {
+// CHECK-NEXT: T b = argc, c, d, e, f, g;
+// CHECK-NEXT: static T a;
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d)
+// CHECK-NEXT: foo()
+
 int main (int argc, char **argv) {
+  float x;
   int b = argc, c, d, e, f, g;
   static int a;
 // CHECK: static int a;
@@ -16,11 +50,11 @@ int main (int argc, char **argv) {
 // CHECK-NEXT: #pragma omp parallel
   a=2;
 // CHECK-NEXT: a = 2;
-#pragma omp parallel default(none), private(argc,b)
-// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b)
+#pragma omp parallel default(none), private(argc,b) firstprivate(argv)
+// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv)
   foo();
 // CHECK-NEXT: foo();
-  return (0);
+  return tmain(b, &b) + tmain(x, &x);
 }
 
 #endif

Added: cfe/trunk/test/OpenMP/parallel_firstprivate_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_firstprivate_messages.cpp?rev=191730&view=auto
==============================================================================
--- cfe/trunk/test/OpenMP/parallel_firstprivate_messages.cpp (added)
+++ cfe/trunk/test/OpenMP/parallel_firstprivate_messages.cpp Tue Oct  1 00:32:34 2013
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+  return argc;
+}
+
+struct S1; // expected-note {{declared here}} expected-note{{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+  mutable int a;
+public:
+  S2():a(0) { }
+  S2(S2 &s2):a(s2.a) { }
+  static float S2s;
+  static const float S2sc;
+};
+const float S2::S2sc = 0;
+const S2 b;
+const S2 ba[5];
+class S3 {
+  int a;
+public:
+  S3():a(0) { }
+  S3(S3 &s3):a(s3.a) { }
+};
+const S3 c;
+const S3 ca[5];
+extern const int f;
+class S4 { // expected-note {{'S4' declared here}}
+  int a;
+  S4();
+  S4(const S4 &s4);
+public:
+  S4(int v):a(v) { }
+};
+class S5 { // expected-note {{'S5' declared here}}
+  int a;
+  S5():a(0) {}
+  S5(const S5 &s5):a(s5.a) { }
+public:
+  S5(int v):a(v) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+
+int main(int argc, char **argv) {
+  const int d = 5;
+  const int da[5] = { 0 };
+  S4 e(4); // expected-note {{'e' defined here}}
+  S5 g(5); // expected-note {{'g' defined here}}
+  int i;
+  int &j = i; // expected-note {{'j' defined here}}
+  #pragma omp parallel firstprivate // expected-error {{expected '(' after 'firstprivate'}}
+  #pragma omp parallel firstprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  #pragma omp parallel firstprivate () // expected-error {{expected expression}}
+  #pragma omp parallel firstprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+  #pragma omp parallel firstprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  #pragma omp parallel firstprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+  #pragma omp parallel firstprivate (argc)
+  #pragma omp parallel firstprivate (S1) // expected-error {{'S1' does not refer to a value}}
+  #pragma omp parallel firstprivate (a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}}
+  #pragma omp parallel firstprivate (argv[1]) // expected-error {{expected variable name}}
+  #pragma omp parallel firstprivate(ba)
+  #pragma omp parallel firstprivate(ca)
+  #pragma omp parallel firstprivate(da)
+  #pragma omp parallel firstprivate(S2::S2s)
+  #pragma omp parallel firstprivate(S2::S2sc)
+  #pragma omp parallel firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+  #pragma omp parallel firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+  #pragma omp parallel private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
+  foo();
+  #pragma omp parallel shared(i)
+  #pragma omp parallel firstprivate(i)
+  #pragma omp parallel firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
+  foo();
+
+  return 0;
+}

Propchange: cfe/trunk/test/OpenMP/parallel_firstprivate_messages.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/OpenMP/parallel_firstprivate_messages.cpp
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Rev URL

Propchange: cfe/trunk/test/OpenMP/parallel_firstprivate_messages.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/OpenMP/parallel_private_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_private_messages.cpp?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/parallel_private_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/parallel_private_messages.cpp Tue Oct  1 00:32:34 2013
@@ -64,10 +64,18 @@ int main(int argc, char **argv) {
   #pragma omp parallel private(S2::S2s) // expected-error {{shared variable cannot be private}}
   #pragma omp parallel private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
   #pragma omp parallel private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}}
+  #pragma omp parallel shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
+  foo();
+  #pragma omp parallel firstprivate(i) private(i) // expected-error {{firstprivate variable cannot be private}} expected-note {{defined as firstprivate}}
   foo();
   #pragma omp parallel private(i)
   #pragma omp parallel private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type 'int &'}}
   foo();
+  #pragma omp parallel firstprivate(i)
+  for (int k = 0; k < 10; ++k) {
+    #pragma omp parallel private(i)
+    foo();
+  }
 
   return 0;
 }

Modified: cfe/trunk/test/OpenMP/parallel_shared_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_shared_messages.cpp?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/parallel_shared_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/parallel_shared_messages.cpp Tue Oct  1 00:32:34 2013
@@ -68,10 +68,16 @@ int main(int argc, char **argv) {
   #pragma omp parallel shared(h) // expected-error {{threadprivate or thread local variable cannot be shared}}
   #pragma omp parallel private(i), shared(i) // expected-error {{private variable cannot be shared}} expected-note {{defined as private}}
   foo();
+  #pragma omp parallel firstprivate(i), shared(i) // expected-error {{firstprivate variable cannot be shared}} expected-note {{defined as firstprivate}}
+  foo();
   #pragma omp parallel private(i)
   #pragma omp parallel shared(i)
   #pragma omp parallel shared(j)
   foo();
+  #pragma omp parallel firstprivate(i)
+  #pragma omp parallel shared(i)
+  #pragma omp parallel shared(j)
+  foo();
 
   return 0;
 }

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Tue Oct  1 00:32:34 2013
@@ -1934,6 +1934,10 @@ void OMPClauseEnqueue::VisitOMPClauseLis
 void OMPClauseEnqueue::VisitOMPPrivateClause(const OMPPrivateClause *C) {
   VisitOMPClauseList(C);
 }
+void OMPClauseEnqueue::VisitOMPFirstprivateClause(
+                                        const OMPFirstprivateClause *C) {
+  VisitOMPClauseList(C);
+}
 void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
   VisitOMPClauseList(C);
 }

Modified: cfe/trunk/tools/libclang/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/RecursiveASTVisitor.h?rev=191730&r1=191729&r2=191730&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/RecursiveASTVisitor.h (original)
+++ cfe/trunk/tools/libclang/RecursiveASTVisitor.h Tue Oct  1 00:32:34 2013
@@ -2345,6 +2345,13 @@ bool RecursiveASTVisitor<Derived>::Visit
 }
 
 template<typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
+                                                    OMPFirstprivateClause *C) {
+  VisitOMPClauseList(C);
+  return true;
+}
+
+template<typename Derived>
 bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
   VisitOMPClauseList(C);
   return true;





More information about the cfe-commits mailing list