Author: Zahira Ammarguellat
Date: 2026-01-15T09:48:24-05:00
New Revision: bde808bf1ccf4ba95011a08468c23d4cdfc5573c

URL: 
https://github.com/llvm/llvm-project/commit/bde808bf1ccf4ba95011a08468c23d4cdfc5573c
DIFF: 
https://github.com/llvm/llvm-project/commit/bde808bf1ccf4ba95011a08468c23d4cdfc5573c.diff

LOG: [CLANG][OpenMP] Add support for OpenMP6.0 transparent clause. (#174646)

Add basic parsing and semantic support for transparent clause for task
andtaskloop directives described in Section 17.9.6 of
https://www.openmp.org/wp-content/uploads/OpenMP-API-Specification-6-0.pdf
.

Added: 
    clang/test/OpenMP/task_transparent_messages.cpp
    clang/test/OpenMP/task_transparent_serialization.cpp

Modified: 
    clang/docs/OpenMPSupport.rst
    clang/docs/ReleaseNotes.rst
    clang/include/clang/AST/OpenMPClause.h
    clang/include/clang/AST/RecursiveASTVisitor.h
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Basic/OpenMPKinds.def
    clang/include/clang/Sema/SemaOpenMP.h
    clang/lib/AST/OpenMPClause.cpp
    clang/lib/AST/StmtProfile.cpp
    clang/lib/CodeGen/CGOpenMPRuntime.cpp
    clang/lib/Parse/ParseOpenMP.cpp
    clang/lib/Sema/SemaOpenMP.cpp
    clang/lib/Sema/TreeTransform.h
    clang/lib/Serialization/ASTReader.cpp
    clang/lib/Serialization/ASTWriter.cpp
    clang/test/OpenMP/task_ast_print.cpp
    clang/test/OpenMP/task_codegen.cpp
    clang/test/OpenMP/taskloop_ast_print.cpp
    clang/test/OpenMP/taskloop_codegen.cpp
    clang/tools/libclang/CIndex.cpp
    llvm/include/llvm/Frontend/OpenMP/ClauseT.h
    llvm/include/llvm/Frontend/OpenMP/OMP.td

Removed: 
    


################################################################################
diff  --git a/clang/docs/OpenMPSupport.rst b/clang/docs/OpenMPSupport.rst
index 7941c2e439ed6..c32dff82d9972 100644
--- a/clang/docs/OpenMPSupport.rst
+++ b/clang/docs/OpenMPSupport.rst
@@ -492,7 +492,7 @@ implementation.
 
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+
 | memscope clause for atomic and flush                        | 
:none:`unclaimed`         | :none:`unclaimed`         |                         
                                                 |
 
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+
-| transparent clause (hull tasks)                             | 
:none:`unclaimed`         | :none:`unclaimed`         |                         
                                                 |
+| transparent clause (hull tasks)                             | 
:part:`partial`           | :none:`unclaimed`         |  Clang parsing/sema  
https://github.com/llvm/llvm-project/pull/166810    |
 
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+
 | rule-based compound directives                              | :part:`In 
Progress`       | :part:`In Progress`       | kparzysz                          
                                       |
 |                                                             |                
           |                           | Testing for Fortran missing            
                                  |

diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4139d1d80ed4a..64d2e256547fe 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -235,6 +235,7 @@ Python Binding Changes
 
 OpenMP Support
 --------------
+- Added support for ``transparent`` clause in task and taskloop directives.
 
 Improvements
 ^^^^^^^^^^^^

diff  --git a/clang/include/clang/AST/OpenMPClause.h 
b/clang/include/clang/AST/OpenMPClause.h
index 6525e64ff102f..2ef363952f67f 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -1495,6 +1495,78 @@ class OMPThreadsetClause final : public OMPClause {
   }
 };
 
+/// This class represents the 'transparent' clause in the '#pragma omp task'
+/// directive.
+///
+/// \code
+/// #pragma omp task transparent(omp_not_impex)
+/// \endcode
+///
+/// In this example, the directive '#pragma omp task' has a 'transparent'
+/// clause with OpenMP keyword 'omp_not_impex`. Other valid keywords that may
+/// appear in this clause are 'omp_import', 'omp_export' and 'omp_impex'.
+///
+class OMPTransparentClause final : public OMPClause {
+  friend class OMPClauseReader;
+
+  /// Location of '('.
+  SourceLocation LParenLoc;
+
+  /// Argument of the 'transparent' clause.
+  Expr *ImpexType = nullptr;
+
+  /// Sets the location of '('.
+  void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+
+  void setImpexTypeKind(Expr *E) { ImpexType = E; }
+
+public:
+  /// Build 'transparent' clause with argument \a A ('omp_not_impex',
+  /// 'omp_import', 'omp_export' or 'omp_impex')
+  ///
+  /// \param A Argument of the clause ('omp_not_impex', 'omp_import',
+  /// 'omp_export' or 'omp_impex')
+  /// \param ALoc Starting location of the argument.
+  /// \param StartLoc Starting location of the clause.
+  /// \param LParenLoc Location of '('.
+  /// \param EndLoc Ending location of the clause.
+  OMPTransparentClause(Expr *ImpexTypeKind, SourceLocation StartLoc,
+                       SourceLocation LParenLoc, SourceLocation EndLoc)
+      : OMPClause(llvm::omp::OMPC_transparent, StartLoc, EndLoc),
+        LParenLoc(LParenLoc), ImpexType(ImpexTypeKind) {}
+
+  /// Build an empty clause.
+  OMPTransparentClause()
+      : OMPClause(llvm::omp::OMPC_transparent, SourceLocation(),
+                  SourceLocation()) {}
+
+  /// Returns the location of '('.
+  SourceLocation getLParenLoc() const { return LParenLoc; }
+
+  /// Returns argument of the clause.
+  Expr *getImpexType() const { return ImpexType; }
+
+  child_range children() {
+    return child_range(reinterpret_cast<Stmt **>(&ImpexType),
+                       reinterpret_cast<Stmt **>(&ImpexType) + 1);
+  }
+
+  const_child_range children() const {
+    return const_cast<OMPTransparentClause *>(this)->children();
+  }
+
+  child_range used_children() {
+    return child_range(child_iterator(), child_iterator());
+  }
+  const_child_range used_children() const {
+    return const_child_range(const_child_iterator(), const_child_iterator());
+  }
+
+  static bool classof(const OMPClause *T) {
+    return T->getClauseKind() == llvm::omp::OMPC_transparent;
+  }
+};
+
 /// This represents 'proc_bind' clause in the '#pragma omp ...'
 /// directive.
 ///

diff  --git a/clang/include/clang/AST/RecursiveASTVisitor.h 
b/clang/include/clang/AST/RecursiveASTVisitor.h
index ddec2c52fb681..c416625ad64fd 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3531,6 +3531,13 @@ bool 
RecursiveASTVisitor<Derived>::VisitOMPThreadsetClause(
   return true;
 }
 
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPTransparentClause(
+    OMPTransparentClause *C) {
+  TRY_TO(TraverseStmt(C->getImpexType()));
+  return true;
+}
+
 template <typename Derived>
 bool RecursiveASTVisitor<Derived>::VisitOMPProcBindClause(OMPProcBindClause *) 
{
   return true;

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5cbbc7d130c99..eb7a608f798b8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12477,6 +12477,10 @@ def err_ompx_bare_no_grid : Error<
   "'ompx_bare' clauses requires explicit grid size via 'num_teams' and 
'thread_limit' clauses">;
 def err_omp_multi_expr_not_allowed: Error<"only one expression allowed in '%0' 
clause">;
 def err_ompx_more_than_three_expr_not_allowed: Error<"at most three 
expressions are allowed in '%0' clause in 'target teams ompx_bare' construct">;
+def err_omp_transparent_invalid_value : Error<"invalid value for transparent 
clause,"
+  " expected one of: omp_not_impex, omp_import, omp_export, omp_impex">;
+def err_omp_transparent_invalid_type : Error<
+  "transparent clause cannot be applied to type: %0">;
 } // end of OpenMP category
 
 let CategoryName = "Related Result Type Issue" in {

diff  --git a/clang/include/clang/Basic/OpenMPKinds.def 
b/clang/include/clang/Basic/OpenMPKinds.def
index ceac89d3aba6d..4f7858097a0d4 100644
--- a/clang/include/clang/Basic/OpenMPKinds.def
+++ b/clang/include/clang/Basic/OpenMPKinds.def
@@ -107,6 +107,9 @@
 #ifndef OPENMP_THREADSET_KIND
 #define OPENMP_THREADSET_KIND(Name)
 #endif
+#ifndef OPENMP_TRANSPARENT_KIND
+#define OPENMP_TRANSPARENT_KIND(Name)
+#endif
 #ifndef OPENMP_NEED_DEVICE_PTR_KIND
 #define OPENMP_NEED_DEVICE_PTR_KIND(Name)
 #endif
@@ -314,4 +317,5 @@ OPENMP_NEED_DEVICE_PTR_KIND(fb_preserve)
 #undef OPENMP_DOACROSS_MODIFIER
 #undef OPENMP_ALLOCATE_MODIFIER
 #undef OPENMP_THREADSET_KIND
+#undef OPENMP_TRANSPARENT_KIND
 #undef OPENMP_NEED_DEVICE_PTR_KIND

diff  --git a/clang/include/clang/Sema/SemaOpenMP.h 
b/clang/include/clang/Sema/SemaOpenMP.h
index 2d05b4423140b..c932e8f9c1a52 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -981,6 +981,11 @@ class SemaOpenMP : public SemaBase {
                                         SourceLocation StartLoc,
                                         SourceLocation LParenLoc,
                                         SourceLocation EndLoc);
+  /// Called on well-formed 'transparent' clause.
+  OMPClause *ActOnOpenMPTransparentClause(Expr *Transparent,
+                                          SourceLocation StartLoc,
+                                          SourceLocation LParenLoc,
+                                          SourceLocation EndLoc);
   /// Called on well-formed 'proc_bind' clause.
   OMPClause *ActOnOpenMPProcBindClause(llvm::omp::ProcBindKind Kind,
                                        SourceLocation KindLoc,
@@ -1472,6 +1477,13 @@ class SemaOpenMP : public SemaBase {
 
   void setOpenMPDeviceNumID(StringRef ID);
 
+  enum class OpenMPImpexType {
+    OMP_NotImpex = 0,
+    OMP_Impex = 1,
+    OMP_Import = 2,
+    OMP_Export = 3
+  };
+
 private:
   void *VarDataSharingAttributesStack;
 

diff  --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index 2183d77de8fa7..fc364418ce51c 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -127,6 +127,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const 
OMPClause *C) {
   case OMPC_untied:
   case OMPC_mergeable:
   case OMPC_threadset:
+  case OMPC_transparent:
   case OMPC_threadprivate:
   case OMPC_groupprivate:
   case OMPC_flush:
@@ -2051,6 +2052,12 @@ void 
OMPClausePrinter::VisitOMPThreadsetClause(OMPThreadsetClause *Node) {
      << ")";
 }
 
+void OMPClausePrinter::VisitOMPTransparentClause(OMPTransparentClause *Node) {
+  OS << "transparent(";
+  Node->getImpexType()->printPretty(OS, nullptr, Policy, 0);
+  OS << ")";
+}
+
 void OMPClausePrinter::VisitOMPProcBindClause(OMPProcBindClause *Node) {
   OS << "proc_bind("
      << getOpenMPSimpleClauseTypeName(OMPC_proc_bind,

diff  --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index a626d043676e0..efabe9809c361 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -550,6 +550,12 @@ void OMPClauseProfiler::VisitOMPDefaultClause(const 
OMPDefaultClause *C) { }
 
 void OMPClauseProfiler::VisitOMPThreadsetClause(const OMPThreadsetClause *C) {}
 
+void OMPClauseProfiler::VisitOMPTransparentClause(
+    const OMPTransparentClause *C) {
+  if (C->getImpexType())
+    Profiler->VisitStmt(C->getImpexType());
+}
+
 void OMPClauseProfiler::VisitOMPProcBindClause(const OMPProcBindClause *C) { }
 
 void OMPClauseProfiler::VisitOMPUnifiedAddressClause(

diff  --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp 
b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 01661ad54ee2f..8981a0de6d0e4 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -3855,6 +3855,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, 
SourceLocation Loc,
     PriorityFlag = 0x20,
     DetachableFlag = 0x40,
     FreeAgentFlag = 0x80,
+    TransparentFlag = 0x100,
   };
   unsigned Flags = Data.Tied ? TiedFlag : 0;
   bool NeedsCleanup = false;
@@ -3869,6 +3870,9 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, 
SourceLocation Loc,
     if (Kind == OMPC_THREADSET_omp_pool)
       Flags = Flags | FreeAgentFlag;
   }
+  if (D.getSingleClause<OMPTransparentClause>())
+    Flags |= TransparentFlag;
+
   if (Data.Priority.getInt())
     Flags = Flags | PriorityFlag;
   if (D.hasClausesOfKind<OMPDetachClause>())

diff  --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 01fd05961f876..45f0497aeb116 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -3179,6 +3179,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind 
DKind,
   case OMPC_message:
   case OMPC_ompx_dyn_cgroup_mem:
   case OMPC_dyn_groupprivate:
+  case OMPC_transparent:
     // OpenMP [2.5, Restrictions]
     //  At most one num_threads clause can appear on the directive.
     // OpenMP [2.8.1, simd construct, Restrictions]

diff  --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 2a1337be13b99..246a2c9c90b1b 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -16554,6 +16554,9 @@ OMPClause 
*SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
   case OMPC_holds:
     Res = ActOnOpenMPHoldsClause(Expr, StartLoc, LParenLoc, EndLoc);
     break;
+  case OMPC_transparent:
+    Res = ActOnOpenMPTransparentClause(Expr, StartLoc, LParenLoc, EndLoc);
+    break;
   case OMPC_dyn_groupprivate:
   case OMPC_grainsize:
   case OMPC_num_tasks:
@@ -17457,6 +17460,64 @@ OMPClause 
*SemaOpenMP::ActOnOpenMPThreadsetClause(OpenMPThreadsetKind Kind,
       OMPThreadsetClause(Kind, KindLoc, StartLoc, LParenLoc, EndLoc);
 }
 
+static OMPClause *createTransparentClause(Sema &SemaRef, ASTContext &Ctx,
+                                          Expr *ImpexTypeArg,
+                                          SourceLocation StartLoc,
+                                          SourceLocation LParenLoc,
+                                          SourceLocation EndLoc) {
+  ExprResult ER = SemaRef.DefaultLvalueConversion(ImpexTypeArg);
+  if (ER.isInvalid())
+    return nullptr;
+
+  return new (Ctx) OMPTransparentClause(ER.get(), StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *SemaOpenMP::ActOnOpenMPTransparentClause(Expr *ImpexTypeArg,
+                                                    SourceLocation StartLoc,
+                                                    SourceLocation LParenLoc,
+                                                    SourceLocation EndLoc) {
+  QualType Ty = ImpexTypeArg->getType();
+
+  if (const auto *TT = Ty->getAs<TypedefType>()) {
+    const TypedefNameDecl *TypedefDecl = TT->getDecl();
+    llvm::StringRef TypedefName = TypedefDecl->getName();
+    IdentifierInfo &II = SemaRef.PP.getIdentifierTable().get(TypedefName);
+    ParsedType ImpexTy =
+        SemaRef.getTypeName(II, StartLoc, SemaRef.getCurScope());
+    if (!ImpexTy.getAsOpaquePtr() || ImpexTy.get().isNull()) {
+      SemaRef.Diag(StartLoc, diag::err_omp_implied_type_not_found)
+          << TypedefName;
+      return nullptr;
+    }
+    return createTransparentClause(SemaRef, getASTContext(), ImpexTypeArg,
+                                   StartLoc, LParenLoc, EndLoc);
+  }
+
+  if (Ty->isEnumeralType())
+    return createTransparentClause(SemaRef, getASTContext(), ImpexTypeArg,
+                                   StartLoc, LParenLoc, EndLoc);
+
+  if (Ty->isIntegerType()) {
+    if (isNonNegativeIntegerValue(ImpexTypeArg, SemaRef, OMPC_transparent,
+                                  /*StrictlyPositive=*/false)) {
+      ExprResult Value =
+          SemaRef.OpenMP().PerformOpenMPImplicitIntegerConversion(StartLoc,
+                                                                  
ImpexTypeArg);
+      if (std::optional<llvm::APSInt> Result =
+              Value.get()->getIntegerConstantExpr(SemaRef.Context)) {
+        if (Result->isNegative() ||
+            Result >
+                static_cast<int64_t>(SemaOpenMP::OpenMPImpexType::OMP_Export))
+          SemaRef.Diag(StartLoc, diag::err_omp_transparent_invalid_value);
+      }
+      return createTransparentClause(SemaRef, getASTContext(), ImpexTypeArg,
+                                     StartLoc, LParenLoc, EndLoc);
+    }
+  }
+  SemaRef.Diag(StartLoc, diag::err_omp_transparent_invalid_type) << Ty;
+  return nullptr;
+}
+
 OMPClause *SemaOpenMP::ActOnOpenMPProcBindClause(ProcBindKind Kind,
                                                  SourceLocation KindKwLoc,
                                                  SourceLocation StartLoc,

diff  --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index a53d578fc35ac..943719f97f9cd 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1851,6 +1851,13 @@ class TreeTransform {
     return getSema().OpenMP().ActOnOpenMPProcBindClause(
         Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
   }
+  OMPClause *RebuildOMPTransparentClause(Expr *ImpexTypeArg,
+                                         SourceLocation StartLoc,
+                                         SourceLocation LParenLoc,
+                                         SourceLocation EndLoc) {
+    return getSema().OpenMP().ActOnOpenMPTransparentClause(
+        ImpexTypeArg, StartLoc, LParenLoc, EndLoc);
+  }
 
   /// Build a new OpenMP 'schedule' clause.
   ///
@@ -4322,6 +4329,14 @@ class TreeTransform {
         AssociatedDecl, NTTP, Loc, Arg, PackIndex, Final);
   }
 
+  OMPClause *RebuildOpenMPTransparentClause(Expr *ImpexType,
+                                            SourceLocation StartLoc,
+                                            SourceLocation LParenLoc,
+                                            SourceLocation EndLoc) {
+    return getSema().OpenMP().ActOnOpenMPTransparentClause(ImpexType, StartLoc,
+                                                           LParenLoc, EndLoc);
+  }
+
 private:
   QualType TransformTypeInObjectScope(TypeLocBuilder &TLB, TypeLoc TL,
                                       QualType ObjectType,
@@ -10672,6 +10687,20 @@ 
TreeTransform<Derived>::TransformOMPThreadsetClause(OMPThreadsetClause *C) {
   return C;
 }
 
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPTransparentClause(OMPTransparentClause *C) 
{
+  Expr *Impex = C->getImpexType();
+  ExprResult TransformedImpex = getDerived().TransformExpr(Impex);
+
+  if (TransformedImpex.isInvalid())
+    return nullptr;
+
+  return getDerived().RebuildOMPTransparentClause(
+      TransformedImpex.get(), C->getBeginLoc(), C->getLParenLoc(),
+      C->getEndLoc());
+}
+
 template <typename Derived>
 OMPClause *
 TreeTransform<Derived>::TransformOMPProcBindClause(OMPProcBindClause *C) {

diff  --git a/clang/lib/Serialization/ASTReader.cpp 
b/clang/lib/Serialization/ASTReader.cpp
index f7be16e326c56..b7ea353f27385 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -11320,6 +11320,9 @@ OMPClause *OMPClauseReader::readClause() {
   case llvm::omp::OMPC_threadset:
     C = new (Context) OMPThreadsetClause();
     break;
+  case llvm::omp::OMPC_transparent:
+    C = new (Context) OMPTransparentClause();
+    break;
   case llvm::omp::OMPC_read:
     C = new (Context) OMPReadClause();
     break;
@@ -11737,6 +11740,11 @@ void 
OMPClauseReader::VisitOMPThreadsetClause(OMPThreadsetClause *C) {
   C->setThreadsetKind(TKind);
 }
 
+void OMPClauseReader::VisitOMPTransparentClause(OMPTransparentClause *C) {
+  C->setLParenLoc(Record.readSourceLocation());
+  C->setImpexTypeKind(Record.readSubExpr());
+}
+
 void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) {
   C->setProcBindKind(static_cast<llvm::omp::ProcBindKind>(Record.readInt()));
   C->setLParenLoc(Record.readSourceLocation());

diff  --git a/clang/lib/Serialization/ASTWriter.cpp 
b/clang/lib/Serialization/ASTWriter.cpp
index 39104da10d0b7..e9189f9ea5238 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -7978,6 +7978,11 @@ void 
OMPClauseWriter::VisitOMPThreadsetClause(OMPThreadsetClause *C) {
   Record.writeEnum(C->getThreadsetKind());
 }
 
+void OMPClauseWriter::VisitOMPTransparentClause(OMPTransparentClause *C) {
+  Record.AddSourceLocation(C->getLParenLoc());
+  Record.AddStmt(C->getImpexType());
+}
+
 void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) {
   Record.push_back(unsigned(C->getProcBindKind()));
   Record.AddSourceLocation(C->getLParenLoc());

diff  --git a/clang/test/OpenMP/task_ast_print.cpp 
b/clang/test/OpenMP/task_ast_print.cpp
index b059f187156ee..4c59a7c7fafa1 100644
--- a/clang/test/OpenMP/task_ast_print.cpp
+++ b/clang/test/OpenMP/task_ast_print.cpp
@@ -16,6 +16,12 @@
 typedef void *omp_depend_t;
 typedef unsigned long omp_event_handle_t;
 
+typedef void **omp_impex_t;
+extern const omp_impex_t omp_not_impex;
+extern const omp_impex_t omp_import;
+extern const omp_impex_t omp_export;
+extern const omp_impex_t omp_impex;
+
 void foo() {}
 
 struct S1 {
@@ -157,6 +163,41 @@ T tmain(T argc, T *argv) {
 
 enum Enum {};
 
+#ifdef OMP60
+typedef void **omp_impex_t;
+extern const omp_impex_t omp_not_impex;
+extern const omp_impex_t omp_import;
+extern const omp_impex_t omp_export;
+extern const omp_impex_t omp_impex;
+
+template <int C>
+void TestTaskLoopImpex() {
+#pragma omp taskloop transparent(C)
+  for (int i = 0; i < 10; ++i) {}
+}
+
+enum class TaskType {
+  TypeA,
+  TypeB,
+  TypeC
+};
+
+template <typename T>
+class TransparentTemplate {
+public:
+  void TestTaskImport() {
+    #pragma omp task transparent(omp_import)
+    {
+      T temp;
+    }
+  }
+  void TestTaskLoopImpex() {
+    #pragma omp taskloop transparent(omp_impex)
+    for (int i = 0; i < 10; ++i) {}
+  }
+};
+#endif
+
 int main(int argc, char **argv) {
   long x;
   int b = argc, c, d, e, f, g;
@@ -164,6 +205,9 @@ int main(int argc, char **argv) {
   int arr[10], arr1[argc];
   omp_depend_t y;
   omp_event_handle_t evt;
+#ifdef OMP60
+  omp_impex_t v = omp_import;
+#endif
 #pragma omp threadprivate(a)
   Enum ee;
 // CHECK: Enum ee;
@@ -205,13 +249,57 @@ int main(int argc, char **argv) {
 #pragma omp task threadset(omp_pool)
 #pragma omp task threadset(omp_team)
   foo();
+
+#pragma omp task transparent(omp_not_impex)
+#pragma omp task transparent(omp_import)
+#pragma omp task transparent(omp_export)
+#pragma omp task transparent(omp_impex)
+#pragma omp task transparent(omp_import)
+#pragma omp task transparent(v)
+#pragma omp task transparent(v ? omp_import : omp_export)
+#pragma omp task transparent(omp_import + 0)
+#pragma omp task transparent((v))
+  foo();
+
+  TestTaskLoopImpex<1>();
+
+  TaskType task = TaskType::TypeA;
+#pragma omp task transparent(task)
+  foo();
 #endif
+
+  // CHECK60: #pragma omp taskloop transparent(C)
+  // CHECK60: #pragma omp taskloop transparent(1)
+  // CHECK60: #pragma omp task transparent(omp_import)
+  // CHECK60: #pragma omp taskloop transparent(omp_impex)
+  // CHECK60: #pragma omp task transparent(omp_import)
   // CHECK60: #pragma omp task threadset(omp_pool)
   // CHECK60: #pragma omp task threadset(omp_team)
   // CHECK60-NEXT: foo();
+  // CHECK60: #pragma omp task transparent(omp_not_impex)
+  // CHECK60-NEXT: #pragma omp task transparent(omp_import)
+  // CHECK60-NEXT: #pragma omp task transparent(omp_export)
+  // CHECK60-NEXT: #pragma omp task transparent(omp_impex)
+  // CHECK60-NEXT: #pragma omp task transparent(omp_import)
+  // CHECK60-NEXT: #pragma omp task transparent(v)
+  // CHECK60-NEXT: #pragma omp task transparent(v ? omp_import : omp_export)
+  // CHECK60-NEXT: #pragma omp task transparent(omp_import + 0)
+  // CHECK60-NEXT: #pragma omp task transparent((v))
+  // CHECK60-NEXT: foo();
+  // CHECK60: #pragma omp task transparent(task)
+  // CHECK60-NEXT: foo();
+
   return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);
 }
 
+#ifdef OMP60
+void TestTaskTransparent() {
+  TransparentTemplate<int> obj;
+  obj.TestTaskImport();
+  obj.TestTaskLoopImpex();
+}
+#endif
+
 extern template int S<int>::TS;
 extern template long S<long>::TS;
 

diff  --git a/clang/test/OpenMP/task_codegen.cpp 
b/clang/test/OpenMP/task_codegen.cpp
index ba8e6945de9d0..faa9c3dfbcf61 100644
--- a/clang/test/OpenMP/task_codegen.cpp
+++ b/clang/test/OpenMP/task_codegen.cpp
@@ -62,6 +62,12 @@ enum omp_allocator_handle_t {
   KMP_ALLOCATOR_MAX_HANDLE = __UINTPTR_MAX__
 };
 
+typedef void **omp_impex_t;
+extern const omp_impex_t omp_not_impex;
+extern const omp_impex_t omp_import;
+extern const omp_impex_t omp_export;
+extern const omp_impex_t omp_impex;
+
 struct S {
   int a;
   S() : a(0) {}
@@ -231,6 +237,25 @@ void test_threadset()
   {
   }
 }
+
+void test_transparent()
+{
+#pragma omp task transparent(omp_not_impex)
+  {}
+#pragma omp task transparent(omp_import)
+  {}
+#pragma omp task transparent(omp_export)
+  {}
+#pragma omp task transparent(omp_impex)
+  {}
+  omp_impex_t v;
+#pragma omp task transparent(v)
+  {}
+#pragma omp task transparent(v ? omp_import : omp_export)
+  {}
+#pragma omp task transparent(omp_import + 0)
+  {}
+}
 #endif // OMP60
 
 #endif
@@ -10276,3 +10301,52 @@ void test_threadset()
 // CHECK6-NEXT:       call i32 @__kmpc_global_thread_num(ptr 
@[[GLOB_PTR2:[0-9]+]])
 // CHECK6-NEXT:       call i32 @__kmpc_omp_task(ptr @1, i32 
%omp_global_thread_num4, ptr %3)
 // CHECK6-NEXT:       ret void
+
+// CHECK6-LABEL: define void @_Z16test_transparentv() #1 {
+// CHECK6-NEXT:  entry:
+// CHECK6-NEXT:       [[AGG_CAPTURED:%.*]] = alloca [[STRUCT_ANON_27:%.*]], 
align 1
+// CHECK6-NEXT:       [[AGG_CAPTURED2:%.*]] = alloca [[STRUCT_ANON_29:%.*]], 
align 1
+// CHECK6-NEXT:       [[AGG_CAPTURED5:%.*]] = alloca [[STRUCT_ANON_31:%.*]], 
align 1
+// CHECK6-NEXT:       [[AGG_CAPTURED8:%.*]] = alloca [[STRUCT_ANON_33:%.*]], 
align 1
+// CHECK6-NEXT:       [[V:%.*]] = alloca ptr, align 8
+// CHECK6-NEXT:       [[AGG_CAPTURED11:%.*]] = alloca [[STRUCT_ANON_35:%.*]], 
align 1
+//CHECK6-NEXT:        [[AGG_CAPTURED14:%.*]] = alloca [[STRUCT_ANON_37:%.*]], 
align 1
+// CHECK6-NEXT:       [[AGG_CAPTURED17:%.*]] = alloca [[STRUCT_ANON_39:%.*]], 
align 1
+// CHECK6-NEXT:       [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @31)
+// CHECK6-NEXT:       [[TMP0:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, 
i32 [[OMP_GLOBAL_THREAD_NUM]], i32 257, i64 40, i64 1, ptr 
@.omp_task_entry..[[ENTRY1:[0-9]+]])
+// CHECK6-NEXT:       [[TMP1:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP0]], i32 0, i32 0
+// CHECK6-NEXT:       [[OMP_GLOBAL_THREAD_NUM1:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @31)
+// CHECK6-NEXT:       [[TMP2:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 
[[OMP_GLOBAL_THREAD_NUM1]], ptr [[TMP0]])
+// CHECK6-NEXT:       [[OMP_GLOBAL_THREAD_NUM3:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @33)
+// CHECK6-NEXT:       [[TMP3:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, 
i32 [[OMP_GLOBAL_THREAD_NUM3]], i32 257, i64 40, i64 1, ptr 
@.omp_task_entry..[[ENTRY2:[0-9]+]])
+// CHECK6-NEXT:       [[TMP4:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP3]], i32 0, i32 0
+// CHECK6-NEXT:       [[OMP_GLOBAL_THREAD_NUM4:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @33)
+// CHECK6-NEXT:       [[TMP5:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 
[[OMP_GLOBAL_THREAD_NUM4]], ptr [[TMP3]])
+// CHECK6-NEXT:       [[OMP_GLOBAL_THREAD_NUM6:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @35)
+// CHECK6-NEXT:       [[TMP6:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, 
i32 [[OMP_GLOBAL_THREAD_NUM6]], i32 257, i64 40, i64 1, ptr 
@.omp_task_entry..[[ENTRY3:[0-9]+]])
+// CHECK6-NEXT:       [[TMP7:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP6]], i32 0, i32 0
+// CHECK6-NEXT:       [[OMP_GLOBAL_THREAD_NUM7:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @35)
+// CHECK6-NEXT:       [[TMP8:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 
[[OMP_GLOBAL_THREAD_NUM7]], ptr [[TMP6]])
+// CHECK6-NEXT:       [[OMP_GLOBAL_THREAD_NUM9:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @37)
+// CHECK6-NEXT:       [[TMP9:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, 
i32 [[OMP_GLOBAL_THREAD_NUM9]], i32 257, i64 40, i64 1, ptr 
@.omp_task_entry..[[ENTRY4:[0-9]+]])
+// CHECK6-NEXT:       [[TMP10:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP9]], i32 0, i32 0
+// CHECK6-NEXT:       [[OMP_GLOBAL_THREAD_NUM10:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @37)
+// CHECK6-NEXT:       [[TMP11:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 
[[OMP_GLOBAL_THREAD_NUM10]], ptr [[TMP9]])
+// CHECK6-NEXT:  [[OMP_GLOBAL_THREAD_NUM12:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @39)
+// CHECK6-NEXT:       [[TMP12:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, 
i32 [[OMP_GLOBAL_THREAD_NUM12]], i32 257, i64 40, i64 1, ptr 
@.omp_task_entry..[[ENTRY37:[0-9]+]])
+// CHECK6-NEXT:       [[TMP13:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP12]], i32 0, i32 0
+// CHECK6-NEXT:       [[OMP_GLOBAL_THREAD_NUM13:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @39)
+// CHECK6-NEXT:        [[TMP14:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 
[[OMP_GLOBAL_THREAD_NUM13]], ptr [[TMP12]])
+
+// CHECK6-NEXT:        [[OMP_GLOBAL_THREAD_NUM15:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @41)
+// CHECK6-NEXT:        [[TMP15:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, 
i32 [[OMP_GLOBAL_THREAD_NUM15]], i32 257, i64 40, i64 1, ptr 
@.omp_task_entry..[[ENTRY39:[0-9]+]])
+// CHECK6-NEXT:        [[TMP16:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP15]], i32 0, i32 0
+// CHECK6-NEXT:        [[OMP_GLOBAL_THREAD_NUM16:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @41)
+// CHECK6-NEXT:        [[TMP17:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 
%omp_global_thread_num16, ptr [[TMP15]])
+// CHECK6-NEXT:        [[OMP_GLOBAL_THREAD_NUM18:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @43)
+ // CHECK6-NEXT:       [[TMP18:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, 
i32 [[OMP_GLOBAL_THREAD_NUM18]], i32 257, i64 40, i64 1, ptr 
@.omp_task_entry..[[ENTRY41:[0-9]+]])
+ // CHECK6-NEXT:       [[TMP19:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP18]], i32 0, i32 0
+ // CHECK6-NEXT:       [[OMP_GLOBAL_THREAD_NUM19:%.*]] = call i32 
@__kmpc_global_thread_num(ptr @43)
+ // CHECK6-NEXT:       [[TMP20:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 
[[OMP_GLOBAL_THREAD_NUM19]], ptr [[TMP18]])
+// CHECK6-NEXT:  ret void
+// CHECK6-NEXT:}

diff  --git a/clang/test/OpenMP/task_transparent_messages.cpp 
b/clang/test/OpenMP/task_transparent_messages.cpp
new file mode 100644
index 0000000000000..a58df6ba2a77b
--- /dev/null
+++ b/clang/test/OpenMP/task_transparent_messages.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -fopenmp-version=45 
-std=c++11 -ferror-limit 200 -o - %s
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 
-std=c++11 -ferror-limit 200 -o - %s
+// RUN: %clang_cc1 -verify=expected,omp51 -fopenmp -fopenmp-version=51 
-std=c++11 -ferror-limit 200 -o - %s
+// RUN: %clang_cc1 -verify=expected,omp60 -DOMP60 -fopenmp -fopenmp-version=60 
-ferror-limit 200 -o - %s
+
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -fopenmp-version=45 
-std=c++11 -ferror-limit 200 -o - %s
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 
-std=c++11 -ferror-limit 200 -o - %s
+// RUN: %clang_cc1 -verify=expected,omp51 -fopenmp-simd -fopenmp-version=51 
-std=c++11 -ferror-limit 200 -o - %s
+// RUN: %clang_cc1 -verify=expected,omp60 -DOMP60 -fopenmp-simd 
-fopenmp-version=60 -std=c++11 -ferror-limit 200 -o - %s
+
+#ifdef OMP60
+struct ComplexStruct {
+  int data[10];
+  struct InnerStruct {
+    float value;
+  } inner;
+};
+
+void TestTaskTransparentWithErrors() {
+  int x = 10;
+  int* ptr = &x;
+  int arr[5];
+#pragma omp task transparent() // expected-error{{expected expression}}
+  // expected-error@+1{{use of undeclared identifier 'omp_not_impex'}}
+#pragma omp task transparent(omp_not_impex)
+  // expected-error@+1{{use of undeclared identifier 'omp_import'}}
+#pragma omp task transparent(omp_import)
+  // expected-error@+1{{use of undeclared identifier 'omp_export'}}
+#pragma omp task transparent(omp_export)
+  // expected-error@+1{{use of undeclared identifier 'omp_impex'}}
+#pragma omp task transparent(omp_impex)
+  // expected-error@+1{{invalid value for transparent clause, expected one of: 
omp_not_impex, omp_import, omp_export, omp_impex}}
+#pragma omp task transparent(5)
+  // expected-error@+1{{transparent clause cannot be applied to type: 'int *'}}
+#pragma omp task transparent(ptr)
+  // expected-error@+1{{transparent clause cannot be applied to type: 'int *'}}
+#pragma omp task transparent(&x)
+  // expected-error@+1{{transparent clause cannot be applied to type: 
'double'}}
+#pragma omp task transparent(20.0)
+  // expected-error@+1{{transparent clause cannot be applied to type: 
'int[5]'}}
+#pragma omp task transparent(arr)
+  for (int i = 0; i < 5; ++i) {}
+}
+
+typedef void **omp_impex_t;
+extern const omp_impex_t omp_not_impex; // omp60-note {{'omp_not_impex' 
declared here}}
+extern const omp_impex_t omp_import;
+extern const omp_impex_t omp_export;
+extern const omp_impex_t omp_impex;
+
+int invalid_arg;
+void TestTaskTransparentInvalidArgs() {
+#pragma omp task transparent(omp_import, omp_not_import) // 
expected-error{{expected ')'}} // expected-note{{to match this '('}}
+  #pragma omp task transparent() // expected-error {{expected expression}}
+  {}
+}
+
+void TestTaskLoopTransparentInvalidArgs() {
+#pragma omp taskloop transparent(omp_not_import, omp_import) // 
expected-error{{expected ')'}} // expected-note{{to match this '('}}  // 
expected-error{{use of undeclared identifier 'omp_not_import'; did you mean 
'omp_not_impex'?}}
+  for (int i = 0; i < 10; ++i) {}
+  #pragma omp taskloop transparent() // expected-error {{expected expression}}
+  for (int i = 0; i < 10; ++i) {}
+}
+
+#else
+void TransparentClauseNotSupported() {
+  #pragma omp task transparent(omp_pool) // omp45-error {{unexpected OpenMP 
clause 'transparent' in directive '#pragma omp task'}} omp45-error {{use of 
undeclared identifier 'omp_pool'}} omp50-error {{unexpected OpenMP clause 
'transparent' in directive '#pragma omp task'}} omp50-error {{use of undeclared 
identifier 'omp_pool'}} omp51-error {{unexpected OpenMP clause 'transparent' in 
directive '#pragma omp task'}} omp51-error {{use of undeclared identifier 
'omp_pool'}}
+  #pragma omp task transparent(omp_team) // omp45-error {{unexpected OpenMP 
clause 'transparent' in directive '#pragma omp task'}} omp45-error {{use of 
undeclared identifier 'omp_team'}} omp50-error {{unexpected OpenMP clause 
'transparent' in directive '#pragma omp task'}} omp50-error {{use of undeclared 
identifier 'omp_team'}} omp51-error {{unexpected OpenMP clause 'transparent' in 
directive '#pragma omp task'}} omp51-error {{use of undeclared identifier 
'omp_team'}}
+  #pragma omp taskloop transparent(omp_team) // omp45-error {{unexpected 
OpenMP clause 'transparent' in directive '#pragma omp taskloop'}} omp45-error 
{{use of undeclared identifier 'omp_team'}} omp50-error {{unexpected OpenMP 
clause 'transparent' in directive '#pragma omp taskloop'}} omp50-error {{use of 
undeclared identifier 'omp_team'}} omp51-error {{unexpected OpenMP clause 
'transparent' in directive '#pragma omp taskloop'}} omp51-error {{use of 
undeclared identifier 'omp_team'}}
+  for (int i = 0; i < 10; ++i) {}
+  #pragma omp taskloop transparent(omp_pool) // omp45-error {{unexpected 
OpenMP clause 'transparent' in directive '#pragma omp taskloop'}} omp45-error 
{{use of undeclared identifier 'omp_pool'}} omp50-error {{unexpected OpenMP 
clause 'transparent' in directive '#pragma omp taskloop'}} omp50-error {{use of 
undeclared identifier 'omp_pool'}} omp51-error {{unexpected OpenMP clause 
'transparent' in directive '#pragma omp taskloop'}} omp51-error {{use of 
undeclared identifier 'omp_pool'}}
+  for (int i = 0; i < 10; ++i) {}
+}
+#endif

diff  --git a/clang/test/OpenMP/task_transparent_serialization.cpp 
b/clang/test/OpenMP/task_transparent_serialization.cpp
new file mode 100644
index 0000000000000..110bd608b41ab
--- /dev/null
+++ b/clang/test/OpenMP/task_transparent_serialization.cpp
@@ -0,0 +1,118 @@
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=60 -x c++ -std=c++11 -emit-pch -o 
%t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=60 -x c++ -std=c++11 -include-pch 
%t -ast-dump-all  %s | FileCheck %s
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+typedef void **omp_impex_t;
+extern const omp_impex_t omp_not_impex;
+extern const omp_impex_t omp_import;
+extern const omp_impex_t omp_export;
+extern const omp_impex_t omp_impex;
+
+template <typename T>
+class TransparentTemplate {
+public:
+  void TestTaskLoopImpex() {
+    #pragma omp taskloop transparent(omp_impex)
+    for (int i = 0; i < 10; ++i) {}
+  }
+};
+
+void TestTaskTransparent() {
+  int a;
+  omp_impex_t imp;
+#pragma omp task transparent(omp_not_impex)
+#pragma omp task transparent(imp)
+
+#pragma omp parallel
+  {
+#pragma omp task transparent(omp_export)
+    {
+#pragma omp taskloop transparent(omp_impex)
+      for (int i = 0; i < 5; ++i) {}
+    }
+  }
+  TransparentTemplate<int> obj;
+  obj.TestTaskLoopImpex();
+}
+#endif
+
+
+// CHECK: FunctionDecl {{.*}} TestTaskTransparent 'void ()'
+// CHECK: OMPTaskDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_not_impex' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: OMPFirstprivateClause
+// CHECK-NEXT: DeclRefExpr {{.*}} 'omp_impex_t':'void **' lvalue Var {{.*}} 
'imp' 'omp_impex_t':'void **' refers_to_enclosing_variable_or_capture
+// CHECK-NEXT: CapturedStmt
+// CHECK: OMPTaskDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'omp_impex_t':'void **' lvalue Var {{.*}} 
'imp' 'omp_impex_t':'void **' refers_to_enclosing_variable_or_capture
+// CHECK-NEXT: CapturedStmt
+// CHECK:  OMPTaskDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_export' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: CapturedStmt
+// CHECK: OMPTaskLoopDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: CapturedStmt
+// CHECK: OMPTaskLoopDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: CapturedStmt
+// CHECK: OMPTaskDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_export' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: CapturedStmt
+// CHECK: OMPTaskLoopDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: CapturedStmt
+// CHECK: OMPTaskLoopDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: CapturedStmt
+// CHECK: OMPTaskDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_export' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: CapturedStmt
+// CHECK: OMPTaskLoopDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: CapturedStmt
+// CHECK: OMPTaskLoopDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: CapturedStmt
+// CHECK: OMPTaskDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_export' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: CapturedStmt
+// CHECK: OMPTaskLoopDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: CapturedStmt
+// CHECK: OMPTaskLoopDirective
+// CHECK-NEXT: OMPTransparentClause
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue 
Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const'
+// CHECK-NEXT: CapturedStmt
+
+
+

diff  --git a/clang/test/OpenMP/taskloop_ast_print.cpp 
b/clang/test/OpenMP/taskloop_ast_print.cpp
index e4bf20af5d78e..9bca586937347 100644
--- a/clang/test/OpenMP/taskloop_ast_print.cpp
+++ b/clang/test/OpenMP/taskloop_ast_print.cpp
@@ -12,6 +12,12 @@
 #ifndef HEADER
 #define HEADER
 
+typedef void **omp_impex_t;
+extern const omp_impex_t omp_not_impex;
+extern const omp_impex_t omp_import;
+extern const omp_impex_t omp_export;
+extern const omp_impex_t omp_impex;
+
 void foo() {}
 
 template <class T, int N>
@@ -97,12 +103,34 @@ int main(int argc, char **argv) {
     foo();
   }
 }
+
+#pragma omp taskloop transparent(omp_not_impex)
+  for (int i = 0; i < 10; ++i) {
+#pragma omp task transparent(omp_import)
+    for (int i = 0; i < 10; ++i) {
+#pragma omp task transparent(omp_export)
+      for (int i = 0; i < 10; ++i) {
+#pragma omp task transparent(omp_impex)
+       foo();
+      }
+    }
+  }
 #endif
  // CHECK60: #pragma omp taskloop threadset(omp_team)
  // CHECK60-NEXT: for (int i = 0; i < 10; ++i) {
  // CHECK60: #pragma omp taskloop threadset(omp_pool)
  // CHECK60-NEXT: for (int j = 0; j < 10; ++j) {
  // CHECK60-NEXT: foo();
+
+// CHECK60: #pragma omp taskloop transparent(omp_not_impex)
+// CHECK60-NEXT: for (int i = 0; i < 10; ++i) {
+// CHECK60-NEXT: #pragma omp task transparent(omp_import)
+// CHECK60-NEXT: for (int i = 0; i < 10; ++i) {
+// CHECK60-NEXT: #pragma omp task transparent(omp_export)
+// CHECK60-NEXT: for (int i = 0; i < 10; ++i) {
+// CHECK60-NEXT: #pragma omp task transparent(omp_impex)
+// CHECK60-NEXT: foo();
+
   return (tmain<int, 5>(argc) + tmain<char, 1>(argv[0][0]));
 }
 

diff  --git a/clang/test/OpenMP/taskloop_codegen.cpp 
b/clang/test/OpenMP/taskloop_codegen.cpp
index d1197607a2684..9073a2376f5b4 100644
--- a/clang/test/OpenMP/taskloop_codegen.cpp
+++ b/clang/test/OpenMP/taskloop_codegen.cpp
@@ -15,6 +15,12 @@
 #ifndef HEADER
 #define HEADER
 
+typedef void **omp_impex_t;
+extern const omp_impex_t omp_not_impex;
+extern const omp_impex_t omp_import;
+extern const omp_impex_t omp_export;
+extern const omp_impex_t omp_impex;
+
 // CHECK-LABEL: @main
 int main(int argc, char **argv) {
 // CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(ptr [[DEFLOC:@.+]])
@@ -256,6 +262,23 @@ void test_threadset()
   for (int i = 0; i < 10; ++i) {
   }
 }
+
+void test_transparent()
+{
+#pragma omp taskloop transparent(omp_not_impex)
+  for (int i = 0; i < 10; ++i) {
+  }
+#pragma omp taskloop transparent(omp_import)
+  for (int i = 0; i < 10; ++i) {
+  }
+#pragma omp taskloop transparent(omp_export)
+  for (int i = 0; i < 10; ++i) {
+  }
+#pragma omp taskloop transparent(omp_impex)
+  for (int i = 0; i < 10; ++i) {
+  }
+}
+
 #endif // OMP60
 // CHECK6-LABEL: define void @_Z14test_threadsetv()
 // CHECK6-NEXT:  entry:
@@ -294,4 +317,74 @@ void test_threadset()
 // CHECK6-NEXT:       call void @__kmpc_end_taskgroup(ptr @1, i32 %[[TID0:.*]])
 // CHECK6-NEXT:       ret void
 
+// CHECK6: define void @_Z16test_transparentv
+// CHECK6: entry:
+// CHECK6:  [[AGG_CAPTURED:%.*]] = alloca [[STRUCT_ANON_18:%.*]], align 1
+// CHECK6:  [[TMP:%.*]] = alloca i32, align 4
+// CHECK6:  [[AGG_CAPTURED1:%.*]] = alloca [[STRUCT_ANON_20:%.*]], align 1
+// CHECK6:  [[TMP2:%.*]] = alloca i32, align 4
+// CHECK6:  [[AGG_CAPTURED3:%.*]] = alloca [[STRUCT_ANON_22:%.*]], align 1
+// CHECK6:  [[TMP4:%.*]] = alloca i32, align 4
+// CHECK6:  [[AGG_CAPTURED5:%.*]] = alloca [[STRUCT_ANON_24:%.*]], align 1
+// CHECK6:  [[TMP6:%.*]] = alloca i32, align 4
+// CHECK6:  [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK6:  call void @__kmpc_taskgroup(ptr @1, i32 [[TMP0]])
+// CHECK6:  [[TMP1:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 
[[TMP0]], i32 257, i64 80, i64 1, ptr @.omp_task_entry..[[ENTRY1:[0-9]+]])
+// CHECK6:  [[TMP2:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP1]], i32 0, i32 0
+// CHECK6:  [[TMP3:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP2]], i32 0, i32 5
+// CHECK6:  store i64 0, ptr [[TMP3]], align 8
+// CHECK6:  [[TMP4:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP2]], i32 0, i32 6
+// CHECK6:  store i64 9, ptr [[TMP4]], align 8
+// CHECK6:  [[TMP5:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP2]], i32 0, i32 7
+// CHECK6:  store i64 1, ptr [[TMP5]], align 8
+// CHECK6:  [[TMP6:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP2]], i32 0, i32 9
+// CHECK6:  call void @llvm.memset.p0.i64(ptr align 8 [[TMP6]], i8 0, i64 8, 
i1 false)
+// CHECK6:  [[TMP7:%.*]] = load i64, ptr [[TMP5]], align 8
+// CHECK6:  call void @__kmpc_taskloop(ptr @1, i32 [[TMP0]], ptr [[TMP1]], i32 
1, ptr [[TMP3]], ptr [[TMP4]], i64 [[TMP7]], i32 1, i32 0, i64 0, ptr null)
+// CHECK6:  call void @__kmpc_end_taskgroup(ptr @1, i32 [[TMP0]])
+// CHECK6:  call void @__kmpc_taskgroup(ptr @1, i32 [[TMP0]])
+// CHECK6:  [[TMP8:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 
[[TMP0]], i32 257, i64 80, i64 1, ptr @.omp_task_entry..[[ENTRY2:[0-9]+]])
+// CHECK6:  [[TMP9:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP8]], i32 0, i32 0
+// CHECK6:  [[TMP10:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP9]], i32 0, i32 5
+// CHECK6:  store i64 0, ptr [[TMP10]], align 8
+// CHECK6:  [[TMP11:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP9]], i32 0, i32 6
+// CHECK6:  store i64 9, ptr [[TMP11]], align 8
+// CHECK6:  [[TMP12:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP9]], i32 0, i32 7
+// CHECK6:  store i64 1, ptr [[TMP12]], align 8
+// CHECK6:  [[TMP13:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP9]], i32 0, i32 9
+// CHECK6:  call void @llvm.memset.p0.i64(ptr align 8 [[TMP13]], i8 0, i64 8, 
i1 false)
+// CHECK6:  [[TMP14:%.*]] = load i64, ptr [[TMP12]], align 8
+// CHECK6:  call void @__kmpc_taskloop(ptr @1, i32 [[TMP0]], ptr [[TMP8]], i32 
1, ptr [[TMP10]], ptr [[TMP11]], i64 [[TMP14]], i32 1, i32 0, i64 0, ptr null)
+// CHECK6:  call void @__kmpc_end_taskgroup(ptr @1, i32 [[TMP0]])
+// CHECK6:  call void @__kmpc_taskgroup(ptr @1, i32 [[TMP0]])
+// CHECK6:  [[TMP15:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 
[[TMP0]], i32 257, i64 80, i64 1, ptr @.omp_task_entry..22)
+// CHECK6:  [[TMP16:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP15]], i32 0, i32 0
+// CHECK6:  [[TMP17:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP16]], i32 0, i32 5
+// CHECK6:  store i64 0, ptr [[TMP17]], align 8
+// CHECK6:  [[TMP18:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP16]], i32 0, i32 6
+// CHECK6:  store i64 9, ptr [[TMP18]], align 8
+// CHECK6:  [[TMP19:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP16]], i32 0, i32 7
+// CHECK6:  store i64 1, ptr [[TMP19]], align 8
+// CHECK6:  [[TMP20:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP16]], i32 0, i32 9
+// CHECK6:  call void @llvm.memset.p0.i64(ptr align 8 [[TMP20]], i8 0, i64 8, 
i1 false)
+// CHECK6:  [[TMP21:%.*]] = load i64, ptr [[TMP19]], align 8
+// CHECK6:  call void @__kmpc_taskloop(ptr @1, i32 [[TMP0]], ptr [[TMP15]], 
i32 1, ptr [[TMP17]], ptr [[TMP18]], i64 [[TMP21]], i32 1, i32 0, i64 0, ptr 
null)
+// CHECK6:  call void @__kmpc_end_taskgroup(ptr @1, i32 [[TMP0]])
+// CHECK6:  call void @__kmpc_taskgroup(ptr @1, i32 [[TMP0]])
+// CHECK6:  [[TMP22:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 
[[TMP0]], i32 257, i64 80, i64 1, ptr @.omp_task_entry..24)
+// CHECK6:  [[TMP23:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP22]], i32 0, i32 0
+// CHECK6:  [[TMP24:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP23]], i32 0, i32 5
+// CHECK6:  store i64 0, ptr [[TMP24]], align 8
+// CHECK6:  [[TMP25:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP23]], i32 0, i32 6
+// CHECK6:  store i64 9, ptr [[TMP25]], align 8
+// CHECK6:  [[TMP26:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP23]], i32 0, i32 7
+// CHECK6:  store i64 1, ptr [[TMP26]], align 8
+// CHECK6:  [[TMP27:%.*]] = getelementptr inbounds nuw 
%struct.kmp_task_t{{.*}}, ptr [[TMP23]], i32 0, i32 9
+// CHECK6:  call void @llvm.memset.p0.i64(ptr align 8 [[TMP27]], i8 0, i64 8, 
i1 false)
+// CHECK6:  [[TMP28:%.*]] = load i64, ptr [[TMP26]], align 8
+// CHECK6:  call void @__kmpc_taskloop(ptr @1, i32 [[TMP0]], ptr [[TMP22]], 
i32 1, ptr [[TMP24]], ptr [[TMP25]], i64 [[TMP28]], i32 1, i32 0, i64 0, ptr 
null)
+// CHECK6:  call void @__kmpc_end_taskgroup(ptr @1, i32 [[TMP0]])
+// CHECK6:  ret void
+// CHECK6:}
+
 #endif

diff  --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 32e84248c1b27..15eec87652451 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -2409,6 +2409,11 @@ void OMPClauseEnqueue::VisitOMPFailClause(const 
OMPFailClause *) {}
 
 void OMPClauseEnqueue::VisitOMPThreadsetClause(const OMPThreadsetClause *) {}
 
+void OMPClauseEnqueue::VisitOMPTransparentClause(
+    const OMPTransparentClause *C) {
+  Visitor->AddStmt(C->getImpexType());
+}
+
 void OMPClauseEnqueue::VisitOMPAbsentClause(const OMPAbsentClause *) {}
 
 void OMPClauseEnqueue::VisitOMPHoldsClause(const OMPHoldsClause *) {}

diff  --git a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h 
b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
index 898961499c473..05ee1ae36a23d 100644
--- a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
+++ b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
@@ -1264,7 +1264,7 @@ struct ToT {
   std::tuple<OPT(Expectation), OPT(Mappers), OPT(Iterator), LocatorList> t;
 };
 
-// [6.0:440-441] `transparent` clause
+// [6.0:510:25] `transparent` clause
 template <typename T, typename I, typename E> //
 struct TransparentT {
   using IncompleteTrait = std::true_type;

diff  --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td 
b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 391cddaa54676..b5d262aec63d0 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -581,6 +581,7 @@ def OMPC_To : Clause<[Spelling<"to">]> {
   let flangClass = "OmpToClause";
 }
 def OMPC_Transparent : Clause<[Spelling<"transparent">]> {
+  let clangClass = "OMPTransparentClause";
   let flangClass = "OmpTransparentClause";
   let isValueOptional = true;
 }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to