Index: include/clang/AST/DeclBase.h =================================================================== --- include/clang/AST/DeclBase.h +++ include/clang/AST/DeclBase.h @@ -176,7 +176,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 @@ -324,7 +327,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. @@ -1252,6 +1255,7 @@ /// NamespaceDecl /// TagDecl /// OMPDeclareReductionDecl +/// OMPDeclareMapperDecl /// FunctionDecl /// ObjCMethodDecl /// ObjCContainerDecl Index: include/clang/AST/DeclCXX.h =================================================================== --- include/clang/AST/DeclCXX.h +++ include/clang/AST/DeclCXX.h @@ -1829,6 +1829,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/DeclOpenMP.h =================================================================== --- include/clang/AST/DeclOpenMP.h +++ include/clang/AST/DeclOpenMP.h @@ -207,6 +207,126 @@ } }; +/// 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 + OMPClause **Clauses = nullptr; + + // Number of clauses associated with this mapper declaration + unsigned NumClauses = 0; + + /// Mapper variable + Expr *MapperVar = 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) {} + + /// Returns an array of immutable clauses associated with this mapper + /// declaration + ArrayRef getClauses() const { + return llvm::makeArrayRef(Clauses, NumClauses); + } + + /// Returns an array of clauses associated with this mapper declaration + MutableArrayRef getClauses() { + return MutableArrayRef(Clauses, NumClauses); + } + + void setPrevDeclInScope(OMPDeclareMapperDecl *Prev) { + PrevDeclInScope = Prev; + } + + /// Sets an array of clauses to this mapper declaration + void setClauses(ArrayRef 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 CL); + + using clauselist_iterator = MutableArrayRef::iterator; + using clauselist_const_iterator = ArrayRef::iterator; + using clauselist_range = llvm::iterator_range; + using clauselist_const_range = + llvm::iterator_range; + + unsigned clauselist_size() const { return NumClauses; } + bool clauselist_empty() const { return NumClauses == 0; } + + 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 getClauses().begin(); } + clauselist_iterator clauselist_end() { return getClauses().end(); } + clauselist_const_iterator clauselist_begin() const { + return getClauses().begin(); + } + clauselist_const_iterator clauselist_end() const { + return getClauses().end(); + } + + /// Get the variable declared in the mapper + Expr *getMapperVar() { return MapperVar; } + const Expr *getMapperVar() const { return MapperVar; } + /// Set the variable declared in the mapper + void setMapperVar(Expr *MapperVarE) { MapperVar = MapperVarE; } + + /// Get the name of the variable declared in the mapper + DeclarationName getVarName() { return VarName; } + + /// Get reference to previous declare reduction construct in the same + /// scope with the same name. + OMPDeclareMapperDecl *getPrevDeclInScope() { + return cast_or_null( + PrevDeclInScope.get(getASTContext().getExternalSource())); + } + const OMPDeclareMapperDecl *getPrevDeclInScope() const { + return cast_or_null( + 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(const_cast(D)); + } + static OMPDeclareMapperDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast(const_cast(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/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -1600,7 +1600,7 @@ TRY_TO(TraverseStmt(I)); } }) - + DEF_TRAVERSE_DECL(OMPRequiresDecl, { for (auto *C : D->clauselists()) { TRY_TO(TraverseOMPClause(C)); @@ -1615,6 +1615,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/Basic/DeclNodes.td =================================================================== --- include/clang/Basic/DeclNodes.td +++ include/clang/Basic/DeclNodes.td @@ -41,6 +41,7 @@ def IndirectField : DDecl; def Binding : DDecl; def OMPDeclareReduction : DDecl, DeclContext; + def OMPDeclareMapper : DDecl, DeclContext; def Declarator : DDecl; def Field : DDecl; def ObjCIvar : DDecl; Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -1177,6 +1177,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/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -8940,6 +8940,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/OpenMPKinds.def =================================================================== --- include/clang/Basic/OpenMPKinds.def +++ include/clang/Basic/OpenMPKinds.def @@ -180,6 +180,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) @@ -215,6 +218,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") @@ -889,6 +893,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/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -2797,6 +2797,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/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3087,6 +3087,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 }; @@ -8802,6 +8804,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 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/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -1538,6 +1538,9 @@ /// A PragmaDetectMismatchDecl record. DECL_PRAGMA_DETECT_MISMATCH, + /// An OMPDeclareMapperDecl record. + DECL_OMP_DECLARE_MAPPER, + /// An OMPDeclareReductionDecl record. DECL_OMP_DECLARE_REDUCTION, Index: lib/AST/ASTDumper.cpp =================================================================== --- lib/AST/ASTDumper.cpp +++ lib/AST/ASTDumper.cpp @@ -316,6 +316,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); @@ -1072,6 +1073,31 @@ dumpStmt(Initializer); } +void ASTDumper::VisitOMPDeclareMapperDecl(const OMPDeclareMapperDecl *D) { + NodeDumper.dumpName(D); + for (auto *C : D->clauselists()) { + dumpChild([=] { + if (!C) { + ColorScope Color(OS, ShowColors, NullColor); + OS << "<<>> 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 << " "; + for (auto *S : C->children()) + dumpStmt(S); + }); + } +} + void ASTDumper::VisitOMPRequiresDecl(const OMPRequiresDecl *D) { for (auto *C : D->clauselists()) { dumpChild([=] { Index: lib/AST/CXXInheritance.cpp =================================================================== --- lib/AST/CXXInheritance.cpp +++ lib/AST/CXXInheritance.cpp @@ -487,6 +487,21 @@ return false; } +bool CXXRecordDecl::FindOMPMapperMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + DeclarationName Name) { + RecordDecl *BaseRecord = + Specifier->getType()->castAs()->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/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -781,6 +781,9 @@ case OMPDeclareReduction: return IDNS_OMPReduction; + case OMPDeclareMapper: + return IDNS_OMPMapper; + // Never have names. case Friend: case FriendTemplate: @@ -1164,6 +1167,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/DeclOpenMP.cpp =================================================================== --- lib/AST/DeclOpenMP.cpp +++ lib/AST/DeclOpenMP.cpp @@ -124,6 +124,55 @@ } //===----------------------------------------------------------------------===// +// OMPDeclareMapperDecl Implementation. +//===----------------------------------------------------------------------===// + +void OMPDeclareMapperDecl::anchor() {} + +OMPDeclareMapperDecl * +OMPDeclareMapperDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + DeclarationName Name, QualType T, + DeclarationName VarName, + OMPDeclareMapperDecl *PrevDeclInScope) { + OMPDeclareMapperDecl *D = new (C, DC) OMPDeclareMapperDecl( + OMPDeclareMapper, DC, L, Name, T, VarName, PrevDeclInScope); + return D; +} + +OMPDeclareMapperDecl *OMPDeclareMapperDecl::CreateDeserialized(ASTContext &C, + unsigned ID, + unsigned N) { + OMPDeclareMapperDecl *D = new (C, ID) + OMPDeclareMapperDecl(OMPDeclareMapper, /*DC=*/nullptr, SourceLocation(), + DeclarationName(), QualType(), DeclarationName(), + /*PrevDeclInScope=*/nullptr); + D->NumClauses = N; + if (N) + D->Clauses = (OMPClause **)C.Allocate(sizeof(OMPClause *) * 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 CL) { + assert(NumClauses == 0 && "Number of clauses should be 0 on initialization"); + NumClauses = CL.size(); + if (NumClauses) { + Clauses = (OMPClause **)C.Allocate(sizeof(OMPClause *) * NumClauses); + setClauses(CL); + } +} + +void OMPDeclareMapperDecl::setClauses(ArrayRef CL) { + assert(CL.size() == NumClauses && + "Number of clauses is not the same as the preallocated buffer"); + std::uninitialized_copy(CL.begin(), CL.end(), Clauses); +} + +//===----------------------------------------------------------------------===// // OMPCapturedExprDecl Implementation. //===----------------------------------------------------------------------===// Index: lib/AST/DeclPrinter.cpp =================================================================== --- lib/AST/DeclPrinter.cpp +++ lib/AST/DeclPrinter.cpp @@ -102,6 +102,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); @@ -424,7 +425,7 @@ // FIXME: Need to be able to tell the DeclPrinter when const char *Terminator = nullptr; if (isa(*D) || isa(*D) || - isa(*D)) + isa(*D) || isa(*D)) Terminator = nullptr; else if (isa(*D) && cast(*D)->hasBody()) Terminator = nullptr; @@ -1598,6 +1599,26 @@ } } +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 I = D->clauselist_begin(), E = D->clauselist_end(); I != E; + ++I) { + Out << " "; + Printer.Visit(*I); + } + } + } +} + void DeclPrinter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) { D->getInit()->printPretty(Out, nullptr, Policy, Indentation); } Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -61,7 +61,8 @@ } const DeclContext *DC = D->getDeclContext(); - if (isa(DC) || isa(DC)) { + if (isa(DC) || isa(DC) || + isa(DC)) { return getEffectiveDeclContext(cast(DC)); } Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -97,7 +97,8 @@ } const DeclContext *DC = D->getDeclContext(); - if (isa(DC) || isa(DC)) { + if (isa(DC) || isa(DC) || + isa(DC)) { return getEffectiveDeclContext(cast(DC)); } Index: lib/Basic/OpenMPKinds.cpp =================================================================== --- lib/Basic/OpenMPKinds.cpp +++ lib/Basic/OpenMPKinds.cpp @@ -765,6 +765,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: @@ -999,6 +1009,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/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -142,6 +142,9 @@ case Decl::OMPDeclareReduction: return CGM.EmitOMPDeclareReduction(cast(&D), this); + case Decl::OMPDeclareMapper: + return CGM.EmitOMPDeclareMapper(cast(&D), this); + case Decl::Typedef: // typedef int X; case Decl::TypeAlias: { // using X = int; [C++0x] const TypedefNameDecl &TD = cast(D); @@ -2415,6 +2418,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/CodeGen/CGOpenMPRuntime.cpp =================================================================== --- lib/CodeGen/CGOpenMPRuntime.cpp +++ lib/CodeGen/CGOpenMPRuntime.cpp @@ -8433,6 +8433,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: @@ -8913,6 +8914,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/CGOpenMPRuntimeNVPTX.cpp =================================================================== --- lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp +++ lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp @@ -859,6 +859,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: @@ -927,6 +928,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: @@ -1077,6 +1079,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: @@ -1150,6 +1153,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/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -1244,6 +1244,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 @@ -2165,6 +2165,10 @@ if (MustBeEmitted(Global)) EmitOMPDeclareReduction(DRD); return; + } else if (auto *DMD = dyn_cast(Global)) { + if (MustBeEmitted(Global)) + EmitOMPDeclareMapper(DMD); + return; } } @@ -5017,6 +5021,10 @@ EmitOMPDeclareReduction(cast(D)); break; + case Decl::OMPDeclareMapper: + EmitOMPDeclareMapper(cast(D)); + break; + case Decl::OMPRequires: EmitOMPRequiresDecl(cast(D)); break; Index: lib/Parse/ParseOpenMP.cpp =================================================================== --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -41,7 +41,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 { @@ -77,6 +78,7 @@ .Case("point", OMPD_point) .Case("reduction", OMPD_reduction) .Case("update", OMPD_update) + .Case("mapper", OMPD_mapper) .Default(OMPD_unknown); } @@ -87,6 +89,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}, @@ -470,6 +473,142 @@ } } +/// Parses 'omp declare mapper' directive. +/// +/// declare-mapper-directive: +/// annot_pragma_openmp 'declare' 'mapper' '(' [ ':'] +/// ')' [[[,] ] ... ] +/// annot_pragma_openmp_end +/// and 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 + 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 + 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); + + Actions.ActOnOpenMPDeclareMapperDirectiveVarDecl( + DMD, getCurScope(), MapperType, Range.getBegin(), VName); + + // Parse map clauses + SmallVector 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.size() == 0) { + 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. @@ -708,6 +847,11 @@ /// annot_pragma_openmp 'declare' 'reduction' [...] /// annot_pragma_openmp_end /// +/// declare-mapper-directive: +/// annot_pragma_openmp 'declare' 'mapper' '(' [ ':'] +/// ')' [[[,] ] ... ] +/// annot_pragma_openmp_end +/// /// declare-simd-directive: /// annot_pragma_openmp 'declare simd' { [,]} /// annot_pragma_openmp_end @@ -801,6 +945,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 } @@ -955,6 +1108,11 @@ /// ('omp_priv' '=' |) ')'] /// annot_pragma_openmp_end /// +/// declare-mapper-directive: +/// annot_pragma_openmp 'declare' 'mapper' '(' [ ':'] +/// ')' [[[,] ] ... ] +/// annot_pragma_openmp_end +/// /// executable-directive: /// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' | /// 'section' | 'single' | 'master' | 'critical' [ '(' ')' ] | @@ -1035,6 +1193,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/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -6199,7 +6199,8 @@ static bool shouldConsiderLinkage(const VarDecl *VD) { const DeclContext *DC = VD->getDeclContext()->getRedeclContext(); - if (DC->isFunctionOrMethod() || isa(DC)) + if (DC->isFunctionOrMethod() || isa(DC) || + isa(DC)) return VD->hasExternalStorage(); if (DC->isFileContext()) return true; @@ -6211,7 +6212,7 @@ static bool shouldConsiderLinkage(const FunctionDecl *FD) { const DeclContext *DC = FD->getDeclContext()->getRedeclContext(); if (DC->isFileContext() || DC->isFunctionOrMethod() || - isa(DC)) + isa(DC) || isa(DC)) return true; if (DC->isRecord()) return false; Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -311,6 +311,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(CurContext); + if (LangOpts.OpenMP && DMD && !CurContext->containsDecl(D) && + isa(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); @@ -2913,6 +2926,7 @@ case Decl::EnumConstant: case Decl::UnresolvedUsingValue: case Decl::OMPDeclareReduction: + case Decl::OMPDeclareMapper: valueKind = VK_RValue; break; Index: lib/Sema/SemaLookup.cpp =================================================================== --- lib/Sema/SemaLookup.cpp +++ lib/Sema/SemaLookup.cpp @@ -279,6 +279,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 @@ -2104,6 +2108,10 @@ BaseCallback = &CXXRecordDecl::FindOMPReductionMember; break; + case LookupOMPMapperName: + BaseCallback = &CXXRecordDecl::FindOMPMapperMember; + break; + case LookupUsingDeclName: // This lookup is for redeclarations only. Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -2766,6 +2766,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: @@ -3611,6 +3612,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"); @@ -8312,6 +8314,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: @@ -8378,6 +8381,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: @@ -8445,6 +8449,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: @@ -8509,6 +8514,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: @@ -8574,6 +8580,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: @@ -8638,6 +8645,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: @@ -8701,6 +8709,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: @@ -13335,6 +13344,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()); + + QualType MapperType = GetTypeFromParser(ParsedType.get()); + assert(!MapperType.isNull()); + + // [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 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 UsedAsPrevious; + LookupResult::Filter Filter = Lookup.makeFilter(); + while (Filter.hasNext()) { + auto *PrevDecl = cast(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(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 *MapperVarExpr = buildDeclRefExpr(*this, VD, MapperType, StartLoc); + DMD->setMapperVar(MapperVarExpr); +} + +Sema::DeclGroupPtrTy +Sema::ActOnOpenMPDeclareMapperDirectiveEnd(OMPDeclareMapperDecl *D, Scope *S, + ArrayRef 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/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2863,6 +2863,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( + SemaRef.CurrentInstantiationScope->findInstantiationOf(PrevDeclInScope) + ->get()); + } + OMPDeclareMapperDecl *NewDMD = SemaRef.ActOnOpenMPDeclareMapperDirectiveStart( + /*S=*/nullptr, Owner, D->getDeclName(), SubstMapperTy, D->getLocation(), + VN, D->getAccess(), PrevDeclInScope); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDMD); + SmallVector Clauses; + bool IsCorrect = true; + if (!RequiresInstantiation) { + // Copy the mapper variable. + NewDMD->setMapperVar(D->getMapperVar()); + // 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(D->getMapperVar())->getDecl(), + cast(NewDMD->getMapperVar())->getDecl()); + auto *ThisContext = dyn_cast_or_null(Owner); + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, Qualifiers(), + ThisContext); + // Instantiate map clauses. + for (OMPClause *C : D->clauselists()) { + auto *OldC = cast(C); + SmallVector 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"); @@ -4944,7 +5025,8 @@ if (isa(D) || isa(D) || isa(D) || isa(D) || ((ParentDC->isFunctionOrMethod() || - isa(ParentDC)) && + isa(ParentDC) || + isa(ParentDC)) && ParentDC->isDependentContext()) || (isa(D) && cast(D)->isLambda())) { // D is a local of some kind. Look into the map of local Index: lib/Serialization/ASTCommon.cpp =================================================================== --- lib/Serialization/ASTCommon.cpp +++ lib/Serialization/ASTCommon.cpp @@ -391,6 +391,7 @@ case Decl::OMPRequires: case Decl::OMPCapturedExpr: case Decl::OMPDeclareReduction: + case Decl::OMPDeclareMapper: case Decl::BuiltinTemplate: case Decl::Decomposition: case Decl::Binding: Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -12301,7 +12301,7 @@ SmallVector 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 Decls; @@ -12325,7 +12325,7 @@ SmallVector Components; Components.reserve(TotalComponents); for (unsigned i = 0; i < TotalComponents; ++i) { - Expr *AssociatedExpr = Record.readSubExpr(); + Expr *AssociatedExpr = Record.readExpr(); auto *AssociatedDecl = Record.readDeclAs(); Components.push_back(OMPClauseMappableExprCommon::MappableComponent( AssociatedExpr, AssociatedDecl)); Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -446,6 +446,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); }; @@ -2660,6 +2661,22 @@ D->PrevDeclInScope = ReadDeclID(); } +void ASTDeclReader::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) { + VisitValueDecl(D); + D->setLocation(ReadSourceLocation()); + Expr *MapperVarE = Record.readExpr(); + D->setMapperVar(MapperVarE); + D->VarName = Record.readDeclarationName(); + D->PrevDeclInScope = ReadDeclID(); + unsigned NumClauses = D->clauselist_size(); + SmallVector 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); } @@ -2777,7 +2794,8 @@ isa(D) || isa(D)) return true; - if (isa(D) || isa(D)) + if (isa(D) || isa(D) || + isa(D)) return !D->getDeclContext()->isFunctionOrMethod(); if (const auto *Var = dyn_cast(D)) return Var->isFileVarDecl() && @@ -3854,6 +3872,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/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -147,6 +147,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. @@ -1766,6 +1767,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->getMapperVar()); + 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: 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: 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 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 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 { +// 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: }; + +#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 d) map(to: d.d) +// CHECK: #pragma omp declare mapper (default : dat d) map(to: d.d){{$}} + +template +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 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 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(0); +} +// CHECK: } + +#endif 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_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 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 s) map(s.data) +#pragma omp declare mapper(default : S s) map(s.len) // expected-error {{no template named 'S'}} + +template +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: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -6230,6 +6230,7 @@ case Decl::Import: case Decl::OMPThreadPrivate: case Decl::OMPDeclareReduction: + case Decl::OMPDeclareMapper: case Decl::OMPRequires: case Decl::ObjCTypeParam: case Decl::BuiltinTemplate: