lildmh updated this revision to Diff 183615.
lildmh added a comment.

Address review comments and rebase


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D56326/new/

https://reviews.llvm.org/D56326

Files:
  include/clang/AST/DeclBase.h
  include/clang/AST/DeclCXX.h
  include/clang/AST/DeclOpenMP.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/Basic/DeclNodes.td
  include/clang/Basic/DiagnosticParseKinds.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/OpenMPKinds.def
  include/clang/Parse/Parser.h
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ASTDumper.cpp
  lib/AST/CXXInheritance.cpp
  lib/AST/DeclBase.cpp
  lib/AST/DeclOpenMP.cpp
  lib/AST/DeclPrinter.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/MicrosoftMangle.cpp
  lib/Basic/OpenMPKinds.cpp
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CGOpenMPRuntime.cpp
  lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
  lib/CodeGen/CodeGenModule.cpp
  lib/CodeGen/CodeGenModule.h
  lib/Parse/ParseOpenMP.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaLookup.cpp
  lib/Sema/SemaOpenMP.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  lib/Serialization/ASTCommon.cpp
  lib/Serialization/ASTReader.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.cpp
  test/OpenMP/declare_mapper_ast_print.c
  test/OpenMP/declare_mapper_ast_print.cpp
  test/OpenMP/declare_mapper_messages.c
  test/OpenMP/declare_mapper_messages.cpp
  tools/libclang/CIndex.cpp

Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -6228,6 +6228,7 @@
   case Decl::Import:
   case Decl::OMPThreadPrivate:
   case Decl::OMPDeclareReduction:
+  case Decl::OMPDeclareMapper:
   case Decl::OMPRequires:
   case Decl::ObjCTypeParam:
   case Decl::BuiltinTemplate:
Index: test/OpenMP/declare_mapper_messages.cpp
===================================================================
--- /dev/null
+++ test/OpenMP/declare_mapper_messages.cpp
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++98 %s
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++11 %s
+
+// RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 %s
+// RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 -std=c++98 %s
+// RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 -std=c++11 %s
+
+int temp; // expected-note {{'temp' declared here}}
+
+class vec {                                                             // expected-note {{definition of 'vec' is not complete until the closing '}'}}
+private:
+  int p;                                                                // expected-note {{declared private here}}
+public:
+  int len;
+#pragma omp declare mapper(id: vec v) map(v.len)                        // expected-error {{member access into incomplete type 'vec'}}
+  double *data;
+};
+
+#pragma omp declare mapper                                              // expected-error {{expected '(' after 'declare mapper'}}
+#pragma omp declare mapper {                                            // expected-error {{expected '(' after 'declare mapper'}}
+#pragma omp declare mapper(                                             // expected-error {{expected a type}} expected-error {{expected declarator on 'omp declare mapper' directive}}
+#pragma omp declare mapper(#                                            // expected-error {{expected a type}} expected-error {{expected declarator on 'omp declare mapper' directive}}
+#pragma omp declare mapper(v                                            // expected-error {{unknown type name 'v'}} expected-error {{expected declarator on 'omp declare mapper' directive}}
+#pragma omp declare mapper(vec                                          // expected-error {{expected declarator on 'omp declare mapper' directive}}
+#pragma omp declare mapper(S v                                          // expected-error {{unknown type name 'S'}}
+#pragma omp declare mapper(vec v                                        // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma omp declare mapper(aa: vec v)                                   // expected-error {{expected at least one clause on '#pragma omp declare mapper' directive}}
+#pragma omp declare mapper(bb: vec v) private(v)                        // expected-error {{expected at least one clause on '#pragma omp declare mapper' directive}} // expected-error {{unexpected OpenMP clause 'private' in directive '#pragma omp declare mapper'}}
+#pragma omp declare mapper(cc: vec v) map(v) (                          // expected-warning {{extra tokens at the end of '#pragma omp declare mapper' are ignored}}
+
+#pragma omp declare mapper(++: vec v) map(v.len)                        // expected-error {{illegal identifier on 'omp declare mapper' directive}}
+#pragma omp declare mapper(id1: vec v) map(v.len, temp)                 // expected-error {{only variable v is allowed in map clauses of this 'omp declare mapper' directive}}
+#pragma omp declare mapper(default : vec kk) map(kk.data[0:2])          // expected-note {{previous definition is here}}
+#pragma omp declare mapper(vec v) map(v.len)                            // expected-error {{redefinition of user-defined mapper for type 'vec' with name 'default'}}
+#pragma omp declare mapper(int v) map(v)                                // expected-error {{mapper type must be of struct, union or class type}}
+#pragma omp declare mapper(id2: vec v) map(v.len, v.p)                  // expected-error {{'p' is a private member of 'vec'}}
+
+namespace N1 {
+template <class T>
+class stack {                                                           // expected-note {{template is declared here}}
+public:
+  int len;
+  T *data;
+#pragma omp declare mapper(id: vec v) map(v.len)                        // expected-note {{previous definition is here}}
+#pragma omp declare mapper(id: vec v) map(v.len)                        // expected-error {{redefinition of user-defined mapper for type 'vec' with name 'id'}}
+};
+};
+
+#pragma omp declare mapper(default : N1::stack s) map(s.len)            // expected-error {{use of class template 'N1::stack' requires template arguments}}
+#pragma omp declare mapper(id1: N1::stack<int> s) map(s.data)
+#pragma omp declare mapper(default : S<int> s) map(s.len)               // expected-error {{no template named 'S'}}
+
+template <class T>
+T foo(T a) {
+#pragma omp declare mapper(id: vec v) map(v.len)                        // expected-note {{previous definition is here}}
+#pragma omp declare mapper(id: vec v) map(v.len)                        // expected-error {{redefinition of user-defined mapper for type 'vec' with name 'id'}}
+}
+
+int fun(int arg) {
+#pragma omp declare mapper(id: vec v) map(v.len)
+  {
+#pragma omp declare mapper(id: vec v) map(v.len)                        // expected-note {{previous definition is here}}
+    {
+#pragma omp declare mapper(id: vec v) map(v.len)
+    }
+#pragma omp declare mapper(id: vec v) map(v.len)                        // expected-error {{redefinition of user-defined mapper for type 'vec' with name 'id'}}
+  }
+  return arg;
+}
Index: test/OpenMP/declare_mapper_messages.c
===================================================================
--- /dev/null
+++ test/OpenMP/declare_mapper_messages.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+// RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 %s
+
+int temp; // expected-note {{'temp' declared here}}
+
+struct vec {                                                            // expected-note {{definition of 'struct vec' is not complete until the closing '}'}}
+  int len;
+#pragma omp declare mapper(id: struct vec v) map(v.len)                 // expected-error {{incomplete definition of type 'struct vec'}}
+  double *data;
+};
+
+#pragma omp declare mapper                                              // expected-error {{expected '(' after 'declare mapper'}}
+#pragma omp declare mapper {                                            // expected-error {{expected '(' after 'declare mapper'}}
+#pragma omp declare mapper(                                             // expected-error {{expected a type}} expected-error {{expected declarator on 'omp declare mapper' directive}}
+#pragma omp declare mapper(#                                            // expected-error {{expected a type}} expected-error {{expected declarator on 'omp declare mapper' directive}}
+#pragma omp declare mapper(struct v                                     // expected-error {{expected declarator on 'omp declare mapper' directive}}
+#pragma omp declare mapper(struct vec                                   // expected-error {{expected declarator on 'omp declare mapper' directive}}
+#pragma omp declare mapper(S v                                          // expected-error {{unknown type name 'S'}}
+#pragma omp declare mapper(struct vec v                                 // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma omp declare mapper(aa:struct vec v)                             // expected-error {{expected at least one clause on '#pragma omp declare mapper' directive}}
+#pragma omp declare mapper(bb:struct vec v) private(v)                  // expected-error {{expected at least one clause on '#pragma omp declare mapper' directive}} // expected-error {{unexpected OpenMP clause 'private' in directive '#pragma omp declare mapper'}}
+#pragma omp declare mapper(cc:struct vec v) map(v) (                    // expected-warning {{extra tokens at the end of '#pragma omp declare mapper' are ignored}}
+
+#pragma omp declare mapper(++: struct vec v) map(v.len)                 // expected-error {{illegal identifier on 'omp declare mapper' directive}}
+#pragma omp declare mapper(id1: struct vec v) map(v.len, temp)          // expected-error {{only variable v is allowed in map clauses of this 'omp declare mapper' directive}}
+#pragma omp declare mapper(default : struct vec kk) map(kk.data[0:2])   // expected-note {{previous definition is here}}
+#pragma omp declare mapper(struct vec v) map(v.len)                     // expected-error {{redefinition of user-defined mapper for type 'struct vec' with name 'default'}}
+#pragma omp declare mapper(int v) map(v)                                // expected-error {{mapper type must be of struct, union or class type}}
+
+int fun(int arg) {
+#pragma omp declare mapper(id: struct vec v) map(v.len)
+  {
+#pragma omp declare mapper(id: struct vec v) map(v.len)                 // expected-note {{previous definition is here}}
+#pragma omp declare mapper(id: struct vec v) map(v.len)                 // expected-error {{redefinition of user-defined mapper for type 'struct vec' with name 'id'}}
+    {
+#pragma omp declare mapper(id: struct vec v) map(v.len)
+    }
+  }
+  return arg;
+}
Index: test/OpenMP/declare_mapper_ast_print.cpp
===================================================================
--- /dev/null
+++ test/OpenMP/declare_mapper_ast_print.cpp
@@ -0,0 +1,97 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+
+// RUN: %clang_cc1 -verify -fopenmp-simd -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp-simd -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+// CHECK: namespace N1 {
+namespace N1
+{
+// CHECK: class vec {
+class vec {
+public:
+  int len;
+  double *data;
+};
+// CHECK: };
+
+#pragma omp declare mapper(id: vec v) map(v.len)
+// CHECK: #pragma omp declare mapper (id : N1::vec v) map(tofrom: v.len){{$}}
+};
+// CHECK: }
+// CHECK: ;
+
+template <class T>
+class dat {
+public:
+  class datin {
+  public:
+    T in;
+  };
+  int i;
+  T d;
+#pragma omp declare mapper(id: N1::vec v) map(v.len)
+#pragma omp declare mapper(id: datin v) map(v.in)
+};
+
+// CHECK: template <class T> class dat {
+// CHECK: #pragma omp declare mapper (id : N1::vec v) map(tofrom: v.len){{$}}
+// CHECK: #pragma omp declare mapper (id : dat::datin v) map(tofrom: v.in){{$}}
+// CHECK: };
+// CHECK: template<> class dat<double> {
+// CHECK: #pragma omp declare mapper (id : N1::vec v) map(tofrom: v.len){{$}}
+// CHECK: #pragma omp declare mapper (id : dat<double>::datin v) map(tofrom: v.in){{$}}
+// CHECK: };
+
+#pragma omp declare mapper(default : N1::vec kk) map(kk.len) map(kk.data[0:2])
+// CHECK: #pragma omp declare mapper (default : N1::vec kk) map(tofrom: kk.len) map(tofrom: kk.data[0:2]){{$}}
+#pragma omp declare mapper(dat<double> d) map(to: d.d)
+// CHECK: #pragma omp declare mapper (default : dat<double> d) map(to: d.d){{$}}
+
+template <typename T>
+T foo(T a) {
+  struct foodat {
+    T a;
+  };
+#pragma omp declare mapper(struct foodat v) map(v.a)
+#pragma omp declare mapper(id: N1::vec v) map(v.len)
+  {
+#pragma omp declare mapper(id: N1::vec v) map(v.len)
+  }
+  return 0;
+}
+
+// CHECK: template <typename T> T foo(T a) {
+// CHECK: #pragma omp declare mapper (default : struct foodat v) map(tofrom: v.a)
+// CHECK: #pragma omp declare mapper (id : N1::vec v) map(tofrom: v.len)
+// CHECK: {
+// CHECK: #pragma omp declare mapper (id : N1::vec v) map(tofrom: v.len)
+// CHECK: }
+// CHECK: }
+// CHECK: template<> int foo<int>(int a) {
+// CHECK: #pragma omp declare mapper (default : struct foodat v) map(tofrom: v.a)
+// CHECK: #pragma omp declare mapper (id : N1::vec v) map(tofrom: v.len)
+// CHECK: {
+// CHECK: #pragma omp declare mapper (id : N1::vec v) map(tofrom: v.len)
+// CHECK: }
+// CHECK: }
+
+// CHECK: int main() {
+int main() {
+#pragma omp declare mapper(id: N1::vec v) map(v.len)
+// CHECK: #pragma omp declare mapper (id : N1::vec v) map(tofrom: v.len)
+  {
+#pragma omp declare mapper(id: N1::vec v) map(v.len)
+// CHECK: #pragma omp declare mapper (id : N1::vec v) map(tofrom: v.len)
+  }
+  return foo<int>(0);
+}
+// CHECK: }
+
+#endif
Index: test/OpenMP/declare_mapper_ast_print.c
===================================================================
--- /dev/null
+++ test/OpenMP/declare_mapper_ast_print.c
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+
+// RUN: %clang_cc1 -verify -fopenmp-simd -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp-simd -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp-simd -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+// CHECK: struct vec {
+struct vec {
+  int len;
+  double *data;
+};
+// CHECK: };
+
+// CHECK: struct dat {
+struct dat {
+  int i;
+  double d;
+#pragma omp declare mapper(id: struct vec v) map(v.len)
+// CHECK: #pragma omp declare mapper (id : struct vec v) map(tofrom: v.len){{$}}
+};
+// CHECK: };
+
+#pragma omp declare mapper(id: struct vec v) map(v.len)
+// CHECK: #pragma omp declare mapper (id : struct vec v) map(tofrom: v.len){{$}}
+#pragma omp declare mapper(default : struct vec kk) map(kk.len) map(kk.data[0:2])
+// CHECK: #pragma omp declare mapper (default : struct vec kk) map(tofrom: kk.len) map(tofrom: kk.data[0:2]){{$}}
+#pragma omp declare mapper(struct dat d) map(to: d.d)
+// CHECK: #pragma omp declare mapper (default : struct dat d) map(to: d.d){{$}}
+
+// CHECK: int main() {
+int main() {
+#pragma omp declare mapper(id: struct vec v) map(v.len)
+// CHECK: #pragma omp declare mapper (id : struct vec v) map(tofrom: v.len)
+  {
+#pragma omp declare mapper(id: struct vec v) map(v.len)
+// CHECK: #pragma omp declare mapper (id : struct vec v) map(tofrom: v.len)
+  }
+  return 0;
+}
+// CHECK: }
+
+#endif
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -146,6 +146,7 @@
     void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
     void VisitOMPRequiresDecl(OMPRequiresDecl *D);
     void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
+    void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D);
     void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
 
     /// Add an Objective-C type parameter list to the given record.
@@ -1765,6 +1766,19 @@
   Code = serialization::DECL_OMP_DECLARE_REDUCTION;
 }
 
+void ASTDeclWriter::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
+  Record.push_back(D->clauselist_size());
+  VisitValueDecl(D);
+  Record.AddSourceLocation(D->getBeginLoc());
+  Record.AddStmt(D->getMapperVarRef());
+  Record.AddDeclarationName(D->getVarName());
+  Record.AddDeclRef(D->getPrevDeclInScope());
+  OMPClauseWriter ClauseWriter(Record);
+  for (OMPClause *C : D->clauselists())
+    ClauseWriter.writeClause(C);
+  Code = serialization::DECL_OMP_DECLARE_MAPPER;
+}
+
 void ASTDeclWriter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
   VisitVarDecl(D);
   Code = serialization::DECL_OMP_CAPTUREDEXPR;
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -445,6 +445,7 @@
     void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
     void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
     void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
+    void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D);
     void VisitOMPRequiresDecl(OMPRequiresDecl *D);
     void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
   };
@@ -2659,6 +2660,22 @@
   D->PrevDeclInScope = ReadDeclID();
 }
 
+void ASTDeclReader::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
+  VisitValueDecl(D);
+  D->setLocation(ReadSourceLocation());
+  Expr *MapperVarRefE = Record.readExpr();
+  D->setMapperVarRef(MapperVarRefE);
+  D->VarName = Record.readDeclarationName();
+  D->PrevDeclInScope = ReadDeclID();
+  unsigned NumClauses = D->clauselist_size();
+  SmallVector<OMPClause *, 8> Clauses;
+  Clauses.reserve(NumClauses);
+  OMPClauseReader ClauseReader(Record);
+  for (unsigned I = 0; I != NumClauses; ++I)
+    Clauses.push_back(ClauseReader.readClause());
+  D->setClauses(Clauses);
+}
+
 void ASTDeclReader::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
   VisitVarDecl(D);
 }
@@ -2776,7 +2793,8 @@
       isa<PragmaCommentDecl>(D) ||
       isa<PragmaDetectMismatchDecl>(D))
     return true;
-  if (isa<OMPThreadPrivateDecl>(D) || isa<OMPDeclareReductionDecl>(D))
+  if (isa<OMPThreadPrivateDecl>(D) || isa<OMPDeclareReductionDecl>(D) ||
+      isa<OMPDeclareMapperDecl>(D))
     return !D->getDeclContext()->isFunctionOrMethod();
   if (const auto *Var = dyn_cast<VarDecl>(D))
     return Var->isFileVarDecl() &&
@@ -3853,6 +3871,9 @@
   case DECL_OMP_DECLARE_REDUCTION:
     D = OMPDeclareReductionDecl::CreateDeserialized(Context, ID);
     break;
+  case DECL_OMP_DECLARE_MAPPER:
+    D = OMPDeclareMapperDecl::CreateDeserialized(Context, ID, Record.readInt());
+    break;
   case DECL_OMP_CAPTUREDEXPR:
     D = OMPCapturedExprDecl::CreateDeserialized(Context, ID);
     break;
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -12300,7 +12300,7 @@
   SmallVector<Expr *, 16> Vars;
   Vars.reserve(NumVars);
   for (unsigned i = 0; i != NumVars; ++i)
-    Vars.push_back(Record.readSubExpr());
+    Vars.push_back(Record.readExpr());
   C->setVarRefs(Vars);
 
   SmallVector<ValueDecl *, 16> Decls;
@@ -12324,7 +12324,7 @@
   SmallVector<OMPClauseMappableExprCommon::MappableComponent, 32> Components;
   Components.reserve(TotalComponents);
   for (unsigned i = 0; i < TotalComponents; ++i) {
-    Expr *AssociatedExpr = Record.readSubExpr();
+    Expr *AssociatedExpr = Record.readExpr();
     auto *AssociatedDecl = Record.readDeclAs<ValueDecl>();
     Components.push_back(OMPClauseMappableExprCommon::MappableComponent(
         AssociatedExpr, AssociatedDecl));
Index: lib/Serialization/ASTCommon.cpp
===================================================================
--- lib/Serialization/ASTCommon.cpp
+++ lib/Serialization/ASTCommon.cpp
@@ -390,6 +390,7 @@
   case Decl::OMPRequires:
   case Decl::OMPCapturedExpr:
   case Decl::OMPDeclareReduction:
+  case Decl::OMPDeclareMapper:
   case Decl::BuiltinTemplate:
   case Decl::Decomposition:
   case Decl::Binding:
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2924,6 +2924,87 @@
   return NewDRD;
 }
 
+Decl *
+TemplateDeclInstantiator::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
+  // Instantiate type and check if it is allowed.
+  const bool RequiresInstantiation =
+      D->getType()->isDependentType() ||
+      D->getType()->isInstantiationDependentType() ||
+      D->getType()->containsUnexpandedParameterPack();
+  QualType SubstMapperTy;
+  DeclarationName VN = D->getVarName();
+  if (RequiresInstantiation) {
+    SubstMapperTy = SemaRef.ActOnOpenMPDeclareMapperType(
+        D->getLocation(),
+        ParsedType::make(SemaRef.SubstType(D->getType(), TemplateArgs,
+                                           D->getLocation(), VN)));
+  } else {
+    SubstMapperTy = D->getType();
+  }
+  if (SubstMapperTy.isNull())
+    return nullptr;
+  // Create an instantiated copy of mapper.
+  auto *PrevDeclInScope = D->getPrevDeclInScope();
+  if (PrevDeclInScope && !PrevDeclInScope->isInvalidDecl()) {
+    PrevDeclInScope = cast<OMPDeclareMapperDecl>(
+        SemaRef.CurrentInstantiationScope->findInstantiationOf(PrevDeclInScope)
+            ->get<Decl *>());
+  }
+  OMPDeclareMapperDecl *NewDMD = SemaRef.ActOnOpenMPDeclareMapperDirectiveStart(
+      /*S=*/nullptr, Owner, D->getDeclName(), SubstMapperTy, D->getLocation(),
+      VN, D->getAccess(), PrevDeclInScope);
+  SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDMD);
+  SmallVector<OMPClause *, 6> Clauses;
+  bool IsCorrect = true;
+  if (!RequiresInstantiation) {
+    // Copy the mapper variable.
+    NewDMD->setMapperVarRef(D->getMapperVarRef());
+    // Copy map clauses from the original mapper.
+    for (OMPClause *C : D->clauselists())
+      Clauses.push_back(C);
+  } else {
+    // Instantiate the mapper variable.
+    DeclarationNameInfo DirName;
+    SemaRef.StartOpenMPDSABlock(OMPD_declare_mapper, DirName, /*S=*/nullptr,
+                                (*D->clauselist_begin())->getBeginLoc());
+    SemaRef.ActOnOpenMPDeclareMapperDirectiveVarDecl(
+        NewDMD, /*S=*/nullptr, SubstMapperTy, D->getLocation(), VN);
+    SemaRef.CurrentInstantiationScope->InstantiatedLocal(
+        cast<DeclRefExpr>(D->getMapperVarRef())->getDecl(),
+        cast<DeclRefExpr>(NewDMD->getMapperVarRef())->getDecl());
+    auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner);
+    Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, Qualifiers(),
+                                     ThisContext);
+    // Instantiate map clauses.
+    for (OMPClause *C : D->clauselists()) {
+      auto *OldC = cast<OMPMapClause>(C);
+      SmallVector<Expr *, 4> NewVars;
+      for (Expr *OE : OldC->varlists()) {
+        Expr *NE = SemaRef.SubstExpr(OE, TemplateArgs).get();
+        if (!NE) {
+          IsCorrect = false;
+          break;
+        }
+        NewVars.push_back(NE);
+      }
+      if (!IsCorrect)
+        break;
+      OMPClause *NewC = SemaRef.ActOnOpenMPMapClause(
+          OldC->getMapTypeModifiers(), OldC->getMapTypeModifiersLoc(),
+          OldC->getMapType(), OldC->isImplicitMapType(), OldC->getMapLoc(),
+          OldC->getColonLoc(), NewVars, OldC->getBeginLoc(),
+          OldC->getLParenLoc(), OldC->getEndLoc());
+      Clauses.push_back(NewC);
+    }
+    SemaRef.EndOpenMPDSABlock(nullptr);
+  }
+  (void)SemaRef.ActOnOpenMPDeclareMapperDirectiveEnd(NewDMD, /*S=*/nullptr,
+                                                     Clauses);
+  if (!IsCorrect)
+    return nullptr;
+  return NewDMD;
+}
+
 Decl *TemplateDeclInstantiator::VisitOMPCapturedExprDecl(
     OMPCapturedExprDecl * /*D*/) {
   llvm_unreachable("Should not be met in templates");
@@ -5005,7 +5086,8 @@
   if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
       isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
       ((ParentDC->isFunctionOrMethod() ||
-        isa<OMPDeclareReductionDecl>(ParentDC)) &&
+        isa<OMPDeclareReductionDecl>(ParentDC) ||
+        isa<OMPDeclareMapperDecl>(ParentDC)) &&
        ParentDC->isDependentContext()) ||
       (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda())) {
     // D is a local of some kind. Look into the map of local
Index: lib/Sema/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -2808,6 +2808,7 @@
   case OMPD_cancel:
   case OMPD_flush:
   case OMPD_declare_reduction:
+  case OMPD_declare_mapper:
   case OMPD_declare_simd:
   case OMPD_declare_target:
   case OMPD_end_declare_target:
@@ -3656,6 +3657,7 @@
   case OMPD_end_declare_target:
   case OMPD_threadprivate:
   case OMPD_declare_reduction:
+  case OMPD_declare_mapper:
   case OMPD_declare_simd:
   case OMPD_requires:
     llvm_unreachable("OpenMP Directive is not allowed");
@@ -8370,6 +8372,7 @@
     case OMPD_cancellation_point:
     case OMPD_flush:
     case OMPD_declare_reduction:
+    case OMPD_declare_mapper:
     case OMPD_declare_simd:
     case OMPD_declare_target:
     case OMPD_end_declare_target:
@@ -8436,6 +8439,7 @@
     case OMPD_cancellation_point:
     case OMPD_flush:
     case OMPD_declare_reduction:
+    case OMPD_declare_mapper:
     case OMPD_declare_simd:
     case OMPD_declare_target:
     case OMPD_end_declare_target:
@@ -8503,6 +8507,7 @@
     case OMPD_cancellation_point:
     case OMPD_flush:
     case OMPD_declare_reduction:
+    case OMPD_declare_mapper:
     case OMPD_declare_simd:
     case OMPD_declare_target:
     case OMPD_end_declare_target:
@@ -8567,6 +8572,7 @@
     case OMPD_cancellation_point:
     case OMPD_flush:
     case OMPD_declare_reduction:
+    case OMPD_declare_mapper:
     case OMPD_declare_simd:
     case OMPD_declare_target:
     case OMPD_end_declare_target:
@@ -8632,6 +8638,7 @@
     case OMPD_cancellation_point:
     case OMPD_flush:
     case OMPD_declare_reduction:
+    case OMPD_declare_mapper:
     case OMPD_declare_simd:
     case OMPD_declare_target:
     case OMPD_end_declare_target:
@@ -8696,6 +8703,7 @@
     case OMPD_cancellation_point:
     case OMPD_flush:
     case OMPD_declare_reduction:
+    case OMPD_declare_mapper:
     case OMPD_declare_simd:
     case OMPD_declare_target:
     case OMPD_end_declare_target:
@@ -8759,6 +8767,7 @@
     case OMPD_cancellation_point:
     case OMPD_flush:
     case OMPD_declare_reduction:
+    case OMPD_declare_mapper:
     case OMPD_declare_simd:
     case OMPD_declare_target:
     case OMPD_end_declare_target:
@@ -13399,6 +13408,143 @@
   return DeclReductions;
 }
 
+TypeResult Sema::ActOnOpenMPDeclareMapperVarDecl(Scope *S, Declarator &D) {
+  TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
+  QualType T = TInfo->getType();
+  if (D.isInvalidType())
+    return true;
+
+  if (getLangOpts().CPlusPlus) {
+    // Check that there are no default arguments (C++ only).
+    CheckExtraCXXDefaultArguments(D);
+  }
+
+  return CreateParsedType(T, TInfo);
+}
+
+QualType Sema::ActOnOpenMPDeclareMapperType(SourceLocation TyLoc,
+                                            TypeResult ParsedType) {
+  assert(ParsedType.isUsable() && "Expect usable parsed mapper type");
+
+  QualType MapperType = GetTypeFromParser(ParsedType.get());
+  assert(!MapperType.isNull() && "Expect valid mapper type");
+
+  // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
+  //  The type must be of struct, union or class type in C and C++
+  if (!MapperType->isStructureOrClassType() && !MapperType->isUnionType()) {
+    Diag(TyLoc, diag::err_omp_mapper_wrong_type);
+    return QualType();
+  }
+  return MapperType;
+}
+
+OMPDeclareMapperDecl *Sema::ActOnOpenMPDeclareMapperDirectiveStart(
+    Scope *S, DeclContext *DC, DeclarationName Name, QualType MapperType,
+    SourceLocation StartLoc, DeclarationName VN, AccessSpecifier AS,
+    Decl *PrevDeclInScope) {
+  LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPMapperName,
+                      forRedeclarationInCurContext());
+  // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
+  //  A mapper-identifier may not be redeclared in the current scope for the
+  //  same type or for a type that is compatible according to the base language
+  //  rules.
+  llvm::DenseMap<QualType, SourceLocation> PreviousRedeclTypes;
+  OMPDeclareMapperDecl *PrevDMD = nullptr;
+  bool InCompoundScope = true;
+  if (S != nullptr) {
+    // Find previous declaration with the same name not referenced in other
+    // declarations.
+    FunctionScopeInfo *ParentFn = getEnclosingFunction();
+    InCompoundScope =
+        (ParentFn != nullptr) && !ParentFn->CompoundScopes.empty();
+    LookupName(Lookup, S);
+    FilterLookupForScope(Lookup, DC, S, /*ConsiderLinkage=*/false,
+                         /*AllowInlineNamespace=*/false);
+    llvm::DenseMap<OMPDeclareMapperDecl *, bool> UsedAsPrevious;
+    LookupResult::Filter Filter = Lookup.makeFilter();
+    while (Filter.hasNext()) {
+      auto *PrevDecl = cast<OMPDeclareMapperDecl>(Filter.next());
+      if (InCompoundScope) {
+        auto I = UsedAsPrevious.find(PrevDecl);
+        if (I == UsedAsPrevious.end())
+          UsedAsPrevious[PrevDecl] = false;
+        if (OMPDeclareMapperDecl *D = PrevDecl->getPrevDeclInScope())
+          UsedAsPrevious[D] = true;
+      }
+      PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] =
+          PrevDecl->getLocation();
+    }
+    Filter.done();
+    if (InCompoundScope) {
+      for (const auto &PrevData : UsedAsPrevious) {
+        if (!PrevData.second) {
+          PrevDMD = PrevData.first;
+          break;
+        }
+      }
+    }
+  } else if (PrevDeclInScope) {
+    auto *PrevDMDInScope = PrevDMD =
+        cast<OMPDeclareMapperDecl>(PrevDeclInScope);
+    do {
+      PreviousRedeclTypes[PrevDMDInScope->getType().getCanonicalType()] =
+          PrevDMDInScope->getLocation();
+      PrevDMDInScope = PrevDMDInScope->getPrevDeclInScope();
+    } while (PrevDMDInScope != nullptr);
+  }
+  const auto I = PreviousRedeclTypes.find(MapperType.getCanonicalType());
+  bool Invalid = false;
+  if (I != PreviousRedeclTypes.end()) {
+    Diag(StartLoc, diag::err_omp_declare_mapper_redefinition)
+        << MapperType << Name;
+    Diag(I->second, diag::note_previous_definition);
+    Invalid = true;
+  }
+  auto *DMD = OMPDeclareMapperDecl::Create(Context, DC, StartLoc, Name,
+                                           MapperType, VN, PrevDMD);
+  DC->addDecl(DMD);
+  DMD->setAccess(AS);
+  if (Invalid)
+    DMD->setInvalidDecl();
+
+  // Enter new function scope.
+  PushFunctionScope();
+  setFunctionHasBranchProtectedScope();
+
+  CurContext = DMD;
+
+  return DMD;
+}
+
+void Sema::ActOnOpenMPDeclareMapperDirectiveVarDecl(OMPDeclareMapperDecl *DMD,
+                                                    Scope *S,
+                                                    QualType MapperType,
+                                                    SourceLocation StartLoc,
+                                                    DeclarationName VN) {
+  VarDecl *VD = buildVarDecl(*this, StartLoc, MapperType, VN.getAsString());
+  if (S)
+    PushOnScopeChains(VD, S);
+  else
+    DMD->addDecl(VD);
+  Expr *MapperVarRefExpr = buildDeclRefExpr(*this, VD, MapperType, StartLoc);
+  DMD->setMapperVarRef(MapperVarRefExpr);
+}
+
+Sema::DeclGroupPtrTy
+Sema::ActOnOpenMPDeclareMapperDirectiveEnd(OMPDeclareMapperDecl *D, Scope *S,
+                                           ArrayRef<OMPClause *> ClauseList) {
+  PopDeclContext();
+  PopFunctionScopeInfo();
+
+  if (D) {
+    if (S)
+      PushOnScopeChains(D, S, /*AddToContext=*/false);
+    D->CreateClauses(Context, ClauseList);
+  }
+
+  return DeclGroupPtrTy::make(DeclGroupRef(D));
+}
+
 OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
                                            SourceLocation StartLoc,
                                            SourceLocation LParenLoc,
Index: lib/Sema/SemaLookup.cpp
===================================================================
--- lib/Sema/SemaLookup.cpp
+++ lib/Sema/SemaLookup.cpp
@@ -278,6 +278,10 @@
     IDNS = Decl::IDNS_OMPReduction;
     break;
 
+  case Sema::LookupOMPMapperName:
+    IDNS = Decl::IDNS_OMPMapper;
+    break;
+
   case Sema::LookupAnyName:
     IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member
       | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol
@@ -2103,6 +2107,10 @@
       BaseCallback = &CXXRecordDecl::FindOMPReductionMember;
       break;
 
+    case LookupOMPMapperName:
+      BaseCallback = &CXXRecordDecl::FindOMPMapperMember;
+      break;
+
     case LookupUsingDeclName:
       // This lookup is for redeclarations only.
 
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -310,6 +310,19 @@
     return true;
   }
 
+  // [OpenMP 5.0], 2.19.7.3. declare mapper Directive, Restrictions
+  //  List-items in map clauses on this construct may only refer to the declared
+  //  variable var and entities that could be referenced by a procedure defined
+  //  at the same location
+  auto *DMD = dyn_cast<OMPDeclareMapperDecl>(CurContext);
+  if (LangOpts.OpenMP && DMD && !CurContext->containsDecl(D) &&
+      isa<VarDecl>(D)) {
+    Diag(Loc, diag::err_omp_declare_mapper_wrong_var)
+        << DMD->getVarName().getAsString();
+    Diag(D->getLocation(), diag::note_entity_declared_at) << D;
+    return true;
+  }
+
   DiagnoseAvailabilityOfDecl(D, Locs, UnknownObjCClass, ObjCPropertyAccess,
                              AvoidPartialAvailabilityChecks, ClassReceiver);
 
@@ -3001,6 +3014,7 @@
     case Decl::EnumConstant:
     case Decl::UnresolvedUsingValue:
     case Decl::OMPDeclareReduction:
+    case Decl::OMPDeclareMapper:
       valueKind = VK_RValue;
       break;
 
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -6192,7 +6192,8 @@
 
 static bool shouldConsiderLinkage(const VarDecl *VD) {
   const DeclContext *DC = VD->getDeclContext()->getRedeclContext();
-  if (DC->isFunctionOrMethod() || isa<OMPDeclareReductionDecl>(DC))
+  if (DC->isFunctionOrMethod() || isa<OMPDeclareReductionDecl>(DC) ||
+      isa<OMPDeclareMapperDecl>(DC))
     return VD->hasExternalStorage();
   if (DC->isFileContext())
     return true;
@@ -6204,7 +6205,7 @@
 static bool shouldConsiderLinkage(const FunctionDecl *FD) {
   const DeclContext *DC = FD->getDeclContext()->getRedeclContext();
   if (DC->isFileContext() || DC->isFunctionOrMethod() ||
-      isa<OMPDeclareReductionDecl>(DC))
+      isa<OMPDeclareReductionDecl>(DC) || isa<OMPDeclareMapperDecl>(DC))
     return true;
   if (DC->isRecord())
     return false;
Index: lib/Parse/ParseOpenMP.cpp
===================================================================
--- lib/Parse/ParseOpenMP.cpp
+++ lib/Parse/ParseOpenMP.cpp
@@ -40,7 +40,8 @@
   OMPD_update,
   OMPD_distribute_parallel,
   OMPD_teams_distribute_parallel,
-  OMPD_target_teams_distribute_parallel
+  OMPD_target_teams_distribute_parallel,
+  OMPD_mapper,
 };
 
 class ThreadprivateListParserHelper final {
@@ -76,6 +77,7 @@
       .Case("point", OMPD_point)
       .Case("reduction", OMPD_reduction)
       .Case("update", OMPD_update)
+      .Case("mapper", OMPD_mapper)
       .Default(OMPD_unknown);
 }
 
@@ -86,6 +88,7 @@
   static const unsigned F[][3] = {
       {OMPD_cancellation, OMPD_point, OMPD_cancellation_point},
       {OMPD_declare, OMPD_reduction, OMPD_declare_reduction},
+      {OMPD_declare, OMPD_mapper, OMPD_declare_mapper},
       {OMPD_declare, OMPD_simd, OMPD_declare_simd},
       {OMPD_declare, OMPD_target, OMPD_declare_target},
       {OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel},
@@ -469,6 +472,141 @@
   }
 }
 
+/// Parses 'omp declare mapper' directive.
+///
+///       declare-mapper-directive:
+///         annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifier> ':']
+///         <type> <var> ')' [<clause>[[,] <clause>] ... ]
+///         annot_pragma_openmp_end
+/// <mapper-identifier> and <var> are base language identifiers.
+///
+Parser::DeclGroupPtrTy
+Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) {
+  bool IsCorrect = true;
+  // Parse '('
+  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+  if (T.expectAndConsume(diag::err_expected_lparen_after,
+                         getOpenMPDirectiveName(OMPD_declare_mapper))) {
+    SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+    return DeclGroupPtrTy();
+  }
+
+  // Parse <mapper-identifier>
+  auto &DeclNames = Actions.getASTContext().DeclarationNames;
+  DeclarationName MapperId;
+  if (PP.LookAhead(0).is(tok::colon)) {
+    if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) {
+      Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier);
+      IsCorrect = false;
+    } else {
+      MapperId = DeclNames.getIdentifier(Tok.getIdentifierInfo());
+    }
+    ConsumeToken();
+    // Consume ':'.
+    ExpectAndConsume(tok::colon);
+  } else {
+    // If no mapper identifier is provided, its name is "default" by default
+    MapperId =
+        DeclNames.getIdentifier(&Actions.getASTContext().Idents.get("default"));
+  }
+
+  if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))
+    return DeclGroupPtrTy();
+
+  // Parse <type> <var>
+  DeclarationName VName;
+  QualType MapperType;
+  SourceRange Range;
+  TypeResult ParsedType = parseOpenMPDeclareMapperVarDecl(Range, VName, AS);
+  if (ParsedType.isUsable())
+    MapperType =
+        Actions.ActOnOpenMPDeclareMapperType(Range.getBegin(), ParsedType);
+  if (MapperType.isNull())
+    IsCorrect = false;
+  if (!IsCorrect) {
+    SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch);
+    return DeclGroupPtrTy();
+  }
+
+  // Consume ')'.
+  IsCorrect &= !T.consumeClose();
+  if (!IsCorrect) {
+    SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch);
+    return DeclGroupPtrTy();
+  }
+
+  // Enter scope.
+  OMPDeclareMapperDecl *DMD = Actions.ActOnOpenMPDeclareMapperDirectiveStart(
+      getCurScope(), Actions.getCurLexicalContext(), MapperId, MapperType,
+      Range.getBegin(), VName, AS);
+  DeclarationNameInfo DirName;
+  SourceLocation Loc = Tok.getLocation();
+  unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
+                        Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;
+  ParseScope OMPDirectiveScope(this, ScopeFlags);
+  Actions.StartOpenMPDSABlock(OMPD_declare_mapper, DirName, getCurScope(), Loc);
+
+  // Add the mapper variable declaration.
+  Actions.ActOnOpenMPDeclareMapperDirectiveVarDecl(
+      DMD, getCurScope(), MapperType, Range.getBegin(), VName);
+
+  // Parse map clauses.
+  SmallVector<OMPClause *, 6> Clauses;
+  while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+    OpenMPClauseKind CKind = Tok.isAnnotation()
+                                 ? OMPC_unknown
+                                 : getOpenMPClauseKind(PP.getSpelling(Tok));
+    Actions.StartOpenMPClause(CKind);
+    OMPClause *Clause =
+        ParseOpenMPClause(OMPD_declare_mapper, CKind, Clauses.size() == 0);
+    if (Clause)
+      Clauses.push_back(Clause);
+    else
+      IsCorrect = false;
+    // Skip ',' if any.
+    if (Tok.is(tok::comma))
+      ConsumeToken();
+    Actions.EndOpenMPClause();
+  }
+  if (Clauses.empty()) {
+    Diag(Tok, diag::err_omp_expected_clause)
+        << getOpenMPDirectiveName(OMPD_declare_mapper);
+    IsCorrect = false;
+  }
+
+  // Exit scope.
+  Actions.EndOpenMPDSABlock(nullptr);
+  OMPDirectiveScope.Exit();
+
+  DeclGroupPtrTy DGP =
+      Actions.ActOnOpenMPDeclareMapperDirectiveEnd(DMD, getCurScope(), Clauses);
+  if (!IsCorrect)
+    return DeclGroupPtrTy();
+  return DGP;
+}
+
+TypeResult Parser::parseOpenMPDeclareMapperVarDecl(SourceRange &Range,
+                                                   DeclarationName &Name,
+                                                   AccessSpecifier AS) {
+  // Parse the common declaration-specifiers piece.
+  Parser::DeclSpecContext DSC = Parser::DeclSpecContext::DSC_type_specifier;
+  DeclSpec DS(AttrFactory);
+  ParseSpecifierQualifierList(DS, AS, DSC);
+
+  // Parse the declarator.
+  DeclaratorContext Context = DeclaratorContext::PrototypeContext;
+  Declarator DeclaratorInfo(DS, Context);
+  ParseDeclarator(DeclaratorInfo);
+  Range = DeclaratorInfo.getSourceRange();
+  if (DeclaratorInfo.getIdentifier() == nullptr) {
+    Diag(Tok.getLocation(), diag::err_omp_mapper_expected_declarator);
+    return true;
+  }
+  Name = Actions.GetNameForDeclarator(DeclaratorInfo).getName();
+
+  return Actions.ActOnOpenMPDeclareMapperVarDecl(getCurScope(), DeclaratorInfo);
+}
+
 namespace {
 /// RAII that recreates function context for correct parsing of clauses of
 /// 'declare simd' construct.
@@ -707,6 +845,11 @@
 ///        annot_pragma_openmp 'declare' 'reduction' [...]
 ///        annot_pragma_openmp_end
 ///
+///       declare-mapper-directive:
+///         annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifer> ':']
+///         <type> <var> ')' [<clause>[[,] <clause>] ... ]
+///         annot_pragma_openmp_end
+///
 ///       declare-simd-directive:
 ///         annot_pragma_openmp 'declare simd' {<clause> [,]}
 ///         annot_pragma_openmp_end
@@ -800,6 +943,15 @@
       return Res;
     }
     break;
+  case OMPD_declare_mapper: {
+    ConsumeToken();
+    if (DeclGroupPtrTy Res = ParseOpenMPDeclareMapperDirective(AS)) {
+      // Skip the last annot_pragma_openmp_end.
+      ConsumeAnnotationToken();
+      return Res;
+    }
+    break;
+  }
   case OMPD_declare_simd: {
     // The syntax is:
     // { #pragma omp declare simd }
@@ -954,6 +1106,11 @@
 ///         ('omp_priv' '=' <expression>|<function_call>) ')']
 ///         annot_pragma_openmp_end
 ///
+///       declare-mapper-directive:
+///         annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifer> ':']
+///         <type> <var> ')' [<clause>[[,] <clause>] ... ]
+///         annot_pragma_openmp_end
+///
 ///       executable-directive:
 ///         annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
 ///         'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |
@@ -1034,6 +1191,18 @@
       SkipUntil(tok::annot_pragma_openmp_end);
     }
     break;
+  case OMPD_declare_mapper: {
+    ConsumeToken();
+    if (DeclGroupPtrTy Res =
+            ParseOpenMPDeclareMapperDirective(/*AS=*/AS_none)) {
+      // Skip the last annot_pragma_openmp_end.
+      ConsumeAnnotationToken();
+      Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
+    } else {
+      SkipUntil(tok::annot_pragma_openmp_end);
+    }
+    break;
+  }
   case OMPD_flush:
     if (PP.LookAhead(0).is(tok::l_paren)) {
       FlushHasClause = true;
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -1243,6 +1243,10 @@
   void EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D,
                                CodeGenFunction *CGF = nullptr);
 
+  /// Emit a code for declare mapper construct.
+  void EmitOMPDeclareMapper(const OMPDeclareMapperDecl *D,
+                            CodeGenFunction *CGF = nullptr);
+
   /// Emit a code for requires directive.
   /// \param D Requires declaration
   void EmitOMPRequiresDecl(const OMPRequiresDecl *D);
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -2190,6 +2190,10 @@
       if (MustBeEmitted(Global))
         EmitOMPDeclareReduction(DRD);
       return;
+    } else if (auto *DMD = dyn_cast<OMPDeclareMapperDecl>(Global)) {
+      if (MustBeEmitted(Global))
+        EmitOMPDeclareMapper(DMD);
+      return;
     }
   }
 
@@ -5052,6 +5056,10 @@
     EmitOMPDeclareReduction(cast<OMPDeclareReductionDecl>(D));
     break;
 
+  case Decl::OMPDeclareMapper:
+    EmitOMPDeclareMapper(cast<OMPDeclareMapperDecl>(D));
+    break;
+
   case Decl::OMPRequires:
     EmitOMPRequiresDecl(cast<OMPRequiresDecl>(D));
     break;
Index: lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
===================================================================
--- lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
+++ lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
@@ -858,6 +858,7 @@
     case OMPD_declare_target:
     case OMPD_end_declare_target:
     case OMPD_declare_reduction:
+    case OMPD_declare_mapper:
     case OMPD_taskloop:
     case OMPD_taskloop_simd:
     case OMPD_requires:
@@ -926,6 +927,7 @@
   case OMPD_declare_target:
   case OMPD_end_declare_target:
   case OMPD_declare_reduction:
+  case OMPD_declare_mapper:
   case OMPD_taskloop:
   case OMPD_taskloop_simd:
   case OMPD_requires:
@@ -1076,6 +1078,7 @@
     case OMPD_declare_target:
     case OMPD_end_declare_target:
     case OMPD_declare_reduction:
+    case OMPD_declare_mapper:
     case OMPD_taskloop:
     case OMPD_taskloop_simd:
     case OMPD_requires:
@@ -1149,6 +1152,7 @@
   case OMPD_declare_target:
   case OMPD_end_declare_target:
   case OMPD_declare_reduction:
+  case OMPD_declare_mapper:
   case OMPD_taskloop:
   case OMPD_taskloop_simd:
   case OMPD_requires:
Index: lib/CodeGen/CGOpenMPRuntime.cpp
===================================================================
--- lib/CodeGen/CGOpenMPRuntime.cpp
+++ lib/CodeGen/CGOpenMPRuntime.cpp
@@ -8231,6 +8231,7 @@
     case OMPD_declare_target:
     case OMPD_end_declare_target:
     case OMPD_declare_reduction:
+    case OMPD_declare_mapper:
     case OMPD_taskloop:
     case OMPD_taskloop_simd:
     case OMPD_requires:
@@ -8653,6 +8654,7 @@
     case OMPD_declare_target:
     case OMPD_end_declare_target:
     case OMPD_declare_reduction:
+    case OMPD_declare_mapper:
     case OMPD_taskloop:
     case OMPD_taskloop_simd:
     case OMPD_requires:
@@ -9133,6 +9135,7 @@
     case OMPD_declare_target:
     case OMPD_end_declare_target:
     case OMPD_declare_reduction:
+    case OMPD_declare_mapper:
     case OMPD_taskloop:
     case OMPD_taskloop_simd:
     case OMPD_target:
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -141,6 +141,9 @@
   case Decl::OMPDeclareReduction:
     return CGM.EmitOMPDeclareReduction(cast<OMPDeclareReductionDecl>(&D), this);
 
+  case Decl::OMPDeclareMapper:
+    return CGM.EmitOMPDeclareMapper(cast<OMPDeclareMapperDecl>(&D), this);
+
   case Decl::Typedef:      // typedef int X;
   case Decl::TypeAlias: {  // using X = int; [C++0x]
     const TypedefNameDecl &TD = cast<TypedefNameDecl>(D);
@@ -2416,6 +2419,13 @@
   getOpenMPRuntime().emitUserDefinedReduction(CGF, D);
 }
 
+void CodeGenModule::EmitOMPDeclareMapper(const OMPDeclareMapperDecl *D,
+                                            CodeGenFunction *CGF) {
+  if (!LangOpts.OpenMP || (!LangOpts.EmitAllDecls && !D->isUsed()))
+    return;
+  // FIXME: need to implement mapper code generation
+}
+
 void CodeGenModule::EmitOMPRequiresDecl(const OMPRequiresDecl *D) {
   getOpenMPRuntime().checkArchForUnifiedAddressing(*this, D);
 }
Index: lib/Basic/OpenMPKinds.cpp
===================================================================
--- lib/Basic/OpenMPKinds.cpp
+++ lib/Basic/OpenMPKinds.cpp
@@ -764,6 +764,16 @@
       break;
     }
     break;
+  case OMPD_declare_mapper:
+    switch (CKind) {
+#define OPENMP_DECLARE_MAPPER_CLAUSE(Name)                                     \
+  case OMPC_##Name:                                                            \
+    return true;
+#include "clang/Basic/OpenMPKinds.def"
+    default:
+      break;
+    }
+    break;
   case OMPD_declare_target:
   case OMPD_end_declare_target:
   case OMPD_unknown:
@@ -998,6 +1008,7 @@
   case OMPD_cancel:
   case OMPD_flush:
   case OMPD_declare_reduction:
+  case OMPD_declare_mapper:
   case OMPD_declare_simd:
   case OMPD_declare_target:
   case OMPD_end_declare_target:
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -96,7 +96,8 @@
   }
 
   const DeclContext *DC = D->getDeclContext();
-  if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC)) {
+  if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC) ||
+      isa<OMPDeclareMapperDecl>(DC)) {
     return getEffectiveDeclContext(cast<Decl>(DC));
   }
 
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -60,7 +60,8 @@
   }
 
   const DeclContext *DC = D->getDeclContext();
-  if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC)) {
+  if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC) ||
+      isa<OMPDeclareMapperDecl>(DC)) {
     return getEffectiveDeclContext(cast<Decl>(DC));
   }
 
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -101,6 +101,7 @@
     void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
     void VisitOMPRequiresDecl(OMPRequiresDecl *D);
     void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
+    void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D);
     void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
 
     void printTemplateParameters(const TemplateParameterList *Params);
@@ -423,7 +424,7 @@
     // FIXME: Need to be able to tell the DeclPrinter when
     const char *Terminator = nullptr;
     if (isa<OMPThreadPrivateDecl>(*D) || isa<OMPDeclareReductionDecl>(*D) ||
-        isa<OMPRequiresDecl>(*D))
+        isa<OMPDeclareMapperDecl>(*D) || isa<OMPRequiresDecl>(*D))
       Terminator = nullptr;
     else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->hasBody())
       Terminator = nullptr;
@@ -1597,6 +1598,25 @@
   }
 }
 
+void DeclPrinter::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
+  if (!D->isInvalidDecl()) {
+    Out << "#pragma omp declare mapper (";
+    D->printName(Out);
+    Out << " : ";
+    D->getType().print(Out, Policy);
+    Out << " ";
+    Out << D->getVarName();
+    Out << ")";
+    if (!D->clauselist_empty()) {
+      OMPClausePrinter Printer(Out, Policy);
+      for (auto *C : D->clauselists()) {
+        Out << " ";
+        Printer.Visit(C);
+      }
+    }
+  }
+}
+
 void DeclPrinter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
   D->getInit()->printPretty(Out, nullptr, Policy, Indentation);
 }
Index: lib/AST/DeclOpenMP.cpp
===================================================================
--- lib/AST/DeclOpenMP.cpp
+++ lib/AST/DeclOpenMP.cpp
@@ -123,6 +123,56 @@
 }
 
 //===----------------------------------------------------------------------===//
+// OMPDeclareMapperDecl Implementation.
+//===----------------------------------------------------------------------===//
+
+void OMPDeclareMapperDecl::anchor() {}
+
+OMPDeclareMapperDecl *
+OMPDeclareMapperDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+                             DeclarationName Name, QualType T,
+                             DeclarationName VarName,
+                             OMPDeclareMapperDecl *PrevDeclInScope) {
+  return new (C, DC) OMPDeclareMapperDecl(OMPDeclareMapper, DC, L, Name, T,
+                                          VarName, PrevDeclInScope);
+}
+
+OMPDeclareMapperDecl *OMPDeclareMapperDecl::CreateDeserialized(ASTContext &C,
+                                                               unsigned ID,
+                                                               unsigned N) {
+  auto *D = new (C, ID)
+      OMPDeclareMapperDecl(OMPDeclareMapper, /*DC=*/nullptr, SourceLocation(),
+                           DeclarationName(), QualType(), DeclarationName(),
+                           /*PrevDeclInScope=*/nullptr);
+  if (N) {
+    auto **ClauseStorage = C.Allocate<OMPClause *>(N);
+    D->Clauses = llvm::makeMutableArrayRef<OMPClause *>(ClauseStorage, N);
+  }
+  return D;
+}
+
+/// Creates an array of clauses to this mapper declaration and intializes
+/// them. The space used to store clause pointers is dynamically allocated,
+/// because we do not know the number of clauses when creating
+/// OMPDeclareMapperDecl
+void OMPDeclareMapperDecl::CreateClauses(ASTContext &C,
+                                         ArrayRef<OMPClause *> CL) {
+  assert(Clauses.empty() && "Number of clauses should be 0 on initialization");
+  size_t NumClauses = CL.size();
+  if (NumClauses) {
+    auto **ClauseStorage = C.Allocate<OMPClause *>(NumClauses);
+    Clauses = llvm::makeMutableArrayRef<OMPClause *>(ClauseStorage, NumClauses);
+    setClauses(CL);
+  }
+}
+
+void OMPDeclareMapperDecl::setClauses(ArrayRef<OMPClause *> CL) {
+  assert(CL.size() == Clauses.size() &&
+         "Number of clauses is not the same as the preallocated buffer");
+  std::uninitialized_copy(CL.begin(), CL.end(), Clauses.data());
+}
+
+//===----------------------------------------------------------------------===//
 // OMPCapturedExprDecl Implementation.
 //===----------------------------------------------------------------------===//
 
Index: lib/AST/DeclBase.cpp
===================================================================
--- lib/AST/DeclBase.cpp
+++ lib/AST/DeclBase.cpp
@@ -780,6 +780,9 @@
     case OMPDeclareReduction:
       return IDNS_OMPReduction;
 
+    case OMPDeclareMapper:
+      return IDNS_OMPMapper;
+
     // Never have names.
     case Friend:
     case FriendTemplate:
@@ -1163,6 +1166,7 @@
   case Decl::Block:
   case Decl::Captured:
   case Decl::OMPDeclareReduction:
+  case Decl::OMPDeclareMapper:
     // There is only one DeclContext for these entities.
     return this;
 
Index: lib/AST/CXXInheritance.cpp
===================================================================
--- lib/AST/CXXInheritance.cpp
+++ lib/AST/CXXInheritance.cpp
@@ -486,6 +486,21 @@
   return false;
 }
 
+bool CXXRecordDecl::FindOMPMapperMember(const CXXBaseSpecifier *Specifier,
+                                        CXXBasePath &Path,
+                                        DeclarationName Name) {
+  RecordDecl *BaseRecord =
+      Specifier->getType()->castAs<RecordType>()->getDecl();
+
+  for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty();
+       Path.Decls = Path.Decls.slice(1)) {
+    if (Path.Decls.front()->isInIdentifierNamespace(IDNS_OMPMapper))
+      return true;
+  }
+
+  return false;
+}
+
 bool CXXRecordDecl::
 FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
                               CXXBasePath &Path,
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -231,6 +231,7 @@
     // OpenMP decls
     void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D);
     void VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D);
+    void VisitOMPDeclareMapperDecl(const OMPDeclareMapperDecl *D);
     void VisitOMPRequiresDecl(const OMPRequiresDecl *D);
     void VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D);
 
@@ -763,6 +764,31 @@
     dumpStmt(Initializer);
 }
 
+void ASTDumper::VisitOMPDeclareMapperDecl(const OMPDeclareMapperDecl *D) {
+  NodeDumper.dumpName(D);
+  for (const auto *C : D->clauselists()) {
+    dumpChild([=] {
+      if (!C) {
+        ColorScope Color(OS, ShowColors, NullColor);
+        OS << "<<<NULL>>> OMPClause";
+        return;
+      }
+      {
+        ColorScope Color(OS, ShowColors, AttrColor);
+        StringRef ClauseName(getOpenMPClauseName(C->getClauseKind()));
+        OS << "OMP" << ClauseName.substr(/*Start=*/0, /*N=*/1).upper()
+           << ClauseName.drop_front() << "Clause";
+      }
+      NodeDumper.dumpPointer(C);
+      NodeDumper.dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc()));
+      if (C->isImplicit())
+        OS << " <implicit>";
+      for (const auto *S : C->children())
+        dumpStmt(S);
+    });
+  }
+}
+
 void ASTDumper::VisitOMPRequiresDecl(const OMPRequiresDecl *D) {
   for (const auto *C : D->clauselists()) {
     dumpChild([=] {
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1537,6 +1537,9 @@
       /// A PragmaDetectMismatchDecl record.
       DECL_PRAGMA_DETECT_MISMATCH,
 
+      /// An OMPDeclareMapperDecl record.
+      DECL_OMP_DECLARE_MAPPER,
+
       /// An OMPDeclareReductionDecl record.
       DECL_OMP_DECLARE_REDUCTION,
 
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -3120,6 +3120,8 @@
     LookupObjCImplicitSelfParam,
     /// Look up the name of an OpenMP user-defined reduction operation.
     LookupOMPReductionName,
+    /// Look up the name of an OpenMP user-defined mapper.
+    LookupOMPMapperName,
     /// Look up any declaration with any name.
     LookupAnyName
   };
@@ -8835,6 +8837,27 @@
   DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd(
       Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid);
 
+  /// Check variable declaration in 'omp declare mapper' construct.
+  TypeResult ActOnOpenMPDeclareMapperVarDecl(Scope *S, Declarator &D);
+  /// Check if the specified type is allowed to be used in 'omp declare
+  /// mapper' construct.
+  QualType ActOnOpenMPDeclareMapperType(SourceLocation TyLoc,
+                                        TypeResult ParsedType);
+  /// Called on start of '#pragma omp declare mapper'.
+  OMPDeclareMapperDecl *ActOnOpenMPDeclareMapperDirectiveStart(
+      Scope *S, DeclContext *DC, DeclarationName Name, QualType MapperType,
+      SourceLocation StartLoc, DeclarationName VN, AccessSpecifier AS,
+      Decl *PrevDeclInScope = nullptr);
+  /// Build the mapper variable of '#pragma omp declare mapper'.
+  void ActOnOpenMPDeclareMapperDirectiveVarDecl(OMPDeclareMapperDecl *DMD,
+                                                Scope *S, QualType MapperType,
+                                                SourceLocation StartLoc,
+                                                DeclarationName VN);
+  /// Called at the end of '#pragma omp declare mapper'.
+  DeclGroupPtrTy
+  ActOnOpenMPDeclareMapperDirectiveEnd(OMPDeclareMapperDecl *D, Scope *S,
+                                       ArrayRef<OMPClause *> ClauseList);
+
   /// Called on the start of target region i.e. '#pragma omp declare target'.
   bool ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc);
   /// Called at the end of target region i.e. '#pragme omp end declare target'.
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -2796,6 +2796,13 @@
   /// initializer.
   void ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm);
 
+  /// Parses 'omp declare mapper' directive.
+  DeclGroupPtrTy ParseOpenMPDeclareMapperDirective(AccessSpecifier AS);
+  /// Parses variable declaration in 'omp declare mapper' directive.
+  TypeResult parseOpenMPDeclareMapperVarDecl(SourceRange &Range,
+                                             DeclarationName &Name,
+                                             AccessSpecifier AS = AS_none);
+
   /// Parses simple list of variables.
   ///
   /// \param Kind Kind of the directive.
Index: include/clang/Basic/OpenMPKinds.def
===================================================================
--- include/clang/Basic/OpenMPKinds.def
+++ include/clang/Basic/OpenMPKinds.def
@@ -179,6 +179,9 @@
 #ifndef OPENMP_TASKGROUP_CLAUSE
 #define OPENMP_TASKGROUP_CLAUSE(Name)
 #endif
+#ifndef OPENMP_DECLARE_MAPPER_CLAUSE
+#define OPENMP_DECLARE_MAPPER_CLAUSE(Name)
+#endif
 
 // OpenMP directives.
 OPENMP_DIRECTIVE(threadprivate)
@@ -214,6 +217,7 @@
 OPENMP_DIRECTIVE_EXT(for_simd, "for simd")
 OPENMP_DIRECTIVE_EXT(cancellation_point, "cancellation point")
 OPENMP_DIRECTIVE_EXT(declare_reduction, "declare reduction")
+OPENMP_DIRECTIVE_EXT(declare_mapper, "declare mapper")
 OPENMP_DIRECTIVE_EXT(declare_simd, "declare simd")
 OPENMP_DIRECTIVE(taskloop)
 OPENMP_DIRECTIVE_EXT(taskloop_simd, "taskloop simd")
@@ -888,6 +892,10 @@
 // Clauses allowed for OpenMP directive 'taskgroup'.
 OPENMP_TASKGROUP_CLAUSE(task_reduction)
 
+// Clauses allowed for OpenMP directive 'declare mapper'.
+OPENMP_DECLARE_MAPPER_CLAUSE(map)
+
+#undef OPENMP_DECLARE_MAPPER_CLAUSE
 #undef OPENMP_TASKGROUP_CLAUSE
 #undef OPENMP_TASKLOOP_SIMD_CLAUSE
 #undef OPENMP_TASKLOOP_CLAUSE
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -8977,6 +8977,12 @@
 def err_omp_reduction_wrong_type : Error<"reduction type cannot be %select{qualified with 'const', 'volatile' or 'restrict'|a function|a reference|an array}0 type">;
 def err_omp_wrong_var_in_declare_reduction : Error<"only %select{'omp_priv' or 'omp_orig'|'omp_in' or 'omp_out'}0 variables are allowed in %select{initializer|combiner}0 expression">;
 def err_omp_declare_reduction_redefinition : Error<"redefinition of user-defined reduction for type %0">;
+def err_omp_mapper_wrong_type : Error<
+  "mapper type must be of struct, union or class type">;
+def err_omp_declare_mapper_wrong_var : Error<
+  "only variable %0 is allowed in map clauses of this 'omp declare mapper' directive">;
+def err_omp_declare_mapper_redefinition : Error<
+  "redefinition of user-defined mapper for type %0 with name %1">;
 def err_omp_array_section_use : Error<"OpenMP array section is not allowed here">;
 def err_omp_typecheck_section_value : Error<
   "subscripted value is not an array or pointer">;
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -1176,6 +1176,10 @@
   "unexpected '%0' clause, only 'to' or 'link' clauses expected">;
 def err_omp_expected_clause: Error<
   "expected at least one clause on '#pragma omp %0' directive">;
+def err_omp_mapper_illegal_identifier : Error<
+  "illegal identifier on 'omp declare mapper' directive">;
+def err_omp_mapper_expected_declarator : Error<
+  "expected declarator on 'omp declare mapper' directive">;
 
 // Pragma loop support.
 def err_pragma_loop_missing_argument : Error<
Index: include/clang/Basic/DeclNodes.td
===================================================================
--- include/clang/Basic/DeclNodes.td
+++ include/clang/Basic/DeclNodes.td
@@ -41,6 +41,7 @@
     def IndirectField : DDecl<Value>;
     def Binding : DDecl<Value>;
     def OMPDeclareReduction : DDecl<Value>, DeclContext;
+    def OMPDeclareMapper : DDecl<Value>, DeclContext;
     def Declarator : DDecl<Value, "declarators", 1>;
       def Field : DDecl<Declarator, "non-static data members">;
         def ObjCIvar : DDecl<Field>;
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -1589,7 +1589,7 @@
     TRY_TO(TraverseStmt(I));
   }
  })
- 
+
 DEF_TRAVERSE_DECL(OMPRequiresDecl, {
   for (auto *C : D->clauselists()) {
     TRY_TO(TraverseOMPClause(C));
@@ -1604,6 +1604,13 @@
   return true;
 })
 
+DEF_TRAVERSE_DECL(OMPDeclareMapperDecl, {
+  for (auto *C : D->clauselists())
+    TRY_TO(TraverseOMPClause(C));
+  TRY_TO(TraverseType(D->getType()));
+  return true;
+})
+
 DEF_TRAVERSE_DECL(OMPCapturedExprDecl, { TRY_TO(TraverseVarHelper(D)); })
 
 // A helper method for TemplateDecl's children.
Index: include/clang/AST/DeclOpenMP.h
===================================================================
--- include/clang/AST/DeclOpenMP.h
+++ include/clang/AST/DeclOpenMP.h
@@ -206,6 +206,108 @@
   }
 };
 
+/// This represents '#pragma omp declare mapper ...' directive. Map clauses are
+/// allowed to use with this directive. The following example declares a user
+/// defined mapper for the type 'struct vec'. This example instructs the fields
+/// 'len' and 'data' should be mapped when mapping instances of 'struct vec'.
+///
+/// \code
+/// #pragma omp declare mapper(mid: struct vec v) map(v.len, v.data[0:N])
+/// \endcode
+class OMPDeclareMapperDecl final : public ValueDecl, public DeclContext {
+  friend class ASTDeclReader;
+
+  /// Clauses assoicated with this mapper declaration
+  MutableArrayRef<OMPClause *> Clauses;
+
+  /// Mapper variable, which is 'v' in the example above
+  Expr *MapperVarRef = nullptr;
+
+  /// Name of the mapper variable
+  DeclarationName VarName;
+
+  LazyDeclPtr PrevDeclInScope;
+
+  virtual void anchor();
+
+  OMPDeclareMapperDecl(Kind DK, DeclContext *DC, SourceLocation L,
+                       DeclarationName Name, QualType Ty,
+                       DeclarationName VarName,
+                       OMPDeclareMapperDecl *PrevDeclInScope)
+      : ValueDecl(DK, DC, L, Name, Ty), DeclContext(DK), VarName(VarName),
+        PrevDeclInScope(PrevDeclInScope) {}
+
+  void setPrevDeclInScope(OMPDeclareMapperDecl *Prev) {
+    PrevDeclInScope = Prev;
+  }
+
+  /// Sets an array of clauses to this mapper declaration
+  void setClauses(ArrayRef<OMPClause *> CL);
+
+public:
+  /// Creates declare mapper node.
+  static OMPDeclareMapperDecl *Create(ASTContext &C, DeclContext *DC,
+                                      SourceLocation L, DeclarationName Name,
+                                      QualType T, DeclarationName VarName,
+                                      OMPDeclareMapperDecl *PrevDeclInScope);
+  /// Creates deserialized declare mapper node.
+  static OMPDeclareMapperDecl *CreateDeserialized(ASTContext &C, unsigned ID,
+                                                  unsigned N);
+
+  /// Creates an array of clauses to this mapper declaration and intializes
+  /// them.
+  void CreateClauses(ASTContext &C, ArrayRef<OMPClause *> CL);
+
+  using clauselist_iterator = MutableArrayRef<OMPClause *>::iterator;
+  using clauselist_const_iterator = ArrayRef<const OMPClause *>::iterator;
+  using clauselist_range = llvm::iterator_range<clauselist_iterator>;
+  using clauselist_const_range =
+      llvm::iterator_range<clauselist_const_iterator>;
+
+  unsigned clauselist_size() const { return Clauses.size(); }
+  bool clauselist_empty() const { return Clauses.empty(); }
+
+  clauselist_range clauselists() {
+    return clauselist_range(clauselist_begin(), clauselist_end());
+  }
+  clauselist_const_range clauselists() const {
+    return clauselist_const_range(clauselist_begin(), clauselist_end());
+  }
+  clauselist_iterator clauselist_begin() { return Clauses.begin(); }
+  clauselist_iterator clauselist_end() { return Clauses.end(); }
+  clauselist_const_iterator clauselist_begin() const { return Clauses.begin(); }
+  clauselist_const_iterator clauselist_end() const { return Clauses.end(); }
+
+  /// Get the variable declared in the mapper
+  Expr *getMapperVarRef() { return MapperVarRef; }
+  const Expr *getMapperVarRef() const { return MapperVarRef; }
+  /// Set the variable declared in the mapper
+  void setMapperVarRef(Expr *MapperVarRefE) { MapperVarRef = MapperVarRefE; }
+
+  /// Get the name of the variable declared in the mapper
+  DeclarationName getVarName() { return VarName; }
+
+  /// Get reference to previous declare mapper construct in the same
+  /// scope with the same name.
+  OMPDeclareMapperDecl *getPrevDeclInScope() {
+    return cast_or_null<OMPDeclareMapperDecl>(
+        PrevDeclInScope.get(getASTContext().getExternalSource()));
+  }
+  const OMPDeclareMapperDecl *getPrevDeclInScope() const {
+    return cast_or_null<OMPDeclareMapperDecl>(
+        PrevDeclInScope.get(getASTContext().getExternalSource()));
+  }
+
+  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+  static bool classofKind(Kind K) { return K == OMPDeclareMapper; }
+  static DeclContext *castToDeclContext(const OMPDeclareMapperDecl *D) {
+    return static_cast<DeclContext *>(const_cast<OMPDeclareMapperDecl *>(D));
+  }
+  static OMPDeclareMapperDecl *castFromDeclContext(const DeclContext *DC) {
+    return static_cast<OMPDeclareMapperDecl *>(const_cast<DeclContext *>(DC));
+  }
+};
+
 /// Pseudo declaration for capturing expressions. Also is used for capturing of
 /// non-static data members in non-static member functions.
 ///
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -1828,6 +1828,14 @@
                                      CXXBasePath &Path, DeclarationName Name);
 
   /// Base-class lookup callback that determines whether there exists
+  /// an OpenMP declare mapper member with the given name.
+  ///
+  /// This callback can be used with \c lookupInBases() to find members
+  /// of the given name within a C++ class hierarchy.
+  static bool FindOMPMapperMember(const CXXBaseSpecifier *Specifier,
+                                  CXXBasePath &Path, DeclarationName Name);
+
+  /// Base-class lookup callback that determines whether there exists
   /// a member with the given name that can be used in a nested-name-specifier.
   ///
   /// This callback can be used with \c lookupInBases() to find members of
Index: include/clang/AST/DeclBase.h
===================================================================
--- include/clang/AST/DeclBase.h
+++ include/clang/AST/DeclBase.h
@@ -175,7 +175,10 @@
     IDNS_LocalExtern         = 0x0800,
 
     /// This declaration is an OpenMP user defined reduction construction.
-    IDNS_OMPReduction        = 0x1000
+    IDNS_OMPReduction        = 0x1000,
+
+    /// This declaration is an OpenMP user defined mapper.
+    IDNS_OMPMapper           = 0x2000,
   };
 
   /// ObjCDeclQualifier - 'Qualifiers' written next to the return and
@@ -323,7 +326,7 @@
   unsigned FromASTFile : 1;
 
   /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
-  unsigned IdentifierNamespace : 13;
+  unsigned IdentifierNamespace : 14;
 
   /// If 0, we have not computed the linkage of this declaration.
   /// Otherwise, it is the linkage + 1.
@@ -1251,6 +1254,7 @@
 ///   NamespaceDecl
 ///   TagDecl
 ///   OMPDeclareReductionDecl
+///   OMPDeclareMapperDecl
 ///   FunctionDecl
 ///   ObjCMethodDecl
 ///   ObjCContainerDecl
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to