From 3b54d86f4f0bedfffb6305b6f12283f9c62682db Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Fri, 27 Jun 2014 10:37:06 +0000 Subject: [OPENMP] Parsing and sema analysis for 'copyprivate' clause. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211886 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DataRecursiveASTVisitor.h | 7 + include/clang/AST/OpenMPClause.h | 60 +++++++++ include/clang/AST/RecursiveASTVisitor.h | 7 + include/clang/Basic/DiagnosticSemaKinds.td | 2 + include/clang/Basic/OpenMPKinds.def | 2 + include/clang/Sema/Sema.h | 12 +- lib/AST/Stmt.cpp | 22 ++++ lib/AST/StmtPrinter.cpp | 8 ++ lib/AST/StmtProfile.cpp | 4 + lib/Basic/OpenMPKinds.cpp | 6 +- lib/Parse/ParseOpenMP.cpp | 8 +- lib/Sema/SemaOpenMP.cpp | 196 ++++++++++++++++++++++++---- lib/Sema/TreeTransform.h | 45 ++++++- lib/Serialization/ASTReaderStmt.cpp | 13 ++ lib/Serialization/ASTWriterStmt.cpp | 7 + test/OpenMP/single_ast_print.cpp | 16 +-- test/OpenMP/single_copyprivate_messages.cpp | 157 ++++++++++++++++++++++ tools/libclang/CIndex.cpp | 4 + 18 files changed, 525 insertions(+), 51 deletions(-) create mode 100644 test/OpenMP/single_copyprivate_messages.cpp diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h index 86d6ca8667..f35d4f2f85 100644 --- a/include/clang/AST/DataRecursiveASTVisitor.h +++ b/include/clang/AST/DataRecursiveASTVisitor.h @@ -2433,6 +2433,13 @@ bool RecursiveASTVisitor::VisitOMPCopyinClause(OMPCopyinClause *C) { return true; } +template +bool RecursiveASTVisitor::VisitOMPCopyprivateClause( + OMPCopyprivateClause *C) { + VisitOMPClauseList(C); + return true; +} + template bool RecursiveASTVisitor::VisitOMPReductionClause(OMPReductionClause *C) { diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h index 46fc4207c9..0b1aaffcf3 100644 --- a/include/clang/AST/OpenMPClause.h +++ b/include/clang/AST/OpenMPClause.h @@ -1218,6 +1218,66 @@ public: } }; +/// \brief This represents clause 'copyprivate' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp single copyprivate(a,b) +/// \endcode +/// In this example directive '#pragma omp single' has clause 'copyprivate' +/// with the variables 'a' and 'b'. +/// +class OMPCopyprivateClause : public OMPVarListClause { + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPCopyprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause(OMPC_copyprivate, StartLoc, + LParenLoc, EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPCopyprivateClause(unsigned N) + : OMPVarListClause( + OMPC_copyprivate, SourceLocation(), SourceLocation(), + SourceLocation(), N) {} + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPCopyprivateClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef VL); + /// \brief Creates an empty clause with \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPCopyprivateClause *CreateEmpty(const ASTContext &C, unsigned N); + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_copyprivate; + } +}; + } // end namespace clang #endif diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 14a957e1cf..cde5adedbd 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -2455,6 +2455,13 @@ bool RecursiveASTVisitor::VisitOMPCopyinClause(OMPCopyinClause *C) { return true; } +template +bool RecursiveASTVisitor::VisitOMPCopyprivateClause( + OMPCopyprivateClause *C) { + VisitOMPClauseList(C); + return true; +} + template bool RecursiveASTVisitor::VisitOMPReductionClause(OMPReductionClause *C) { diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 04923dae02..6f671f4d39 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -7026,6 +7026,8 @@ def note_omp_predetermined_dsa : Note< "global variable is predetermined as shared|" "variable with automatic storage duration is predetermined as private}0" "%select{|; perhaps you forget to enclose 'omp %2' directive into a parallel or another task region?}1">; +def note_omp_implicit_dsa : Note< + "implicitly determined as %0">; def err_omp_loop_var_dsa : Error< "loop iteration variable may not be %0">; def err_omp_not_for : Error< diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def index 67ce712ed5..5eaf15e311 100644 --- a/include/clang/Basic/OpenMPKinds.def +++ b/include/clang/Basic/OpenMPKinds.def @@ -67,6 +67,7 @@ OPENMP_CLAUSE(reduction, OMPReductionClause) OPENMP_CLAUSE(linear, OMPLinearClause) OPENMP_CLAUSE(aligned, OMPAlignedClause) OPENMP_CLAUSE(copyin, OMPCopyinClause) +OPENMP_CLAUSE(copyprivate, OMPCopyprivateClause) OPENMP_CLAUSE(proc_bind, OMPProcBindClause) OPENMP_CLAUSE(schedule, OMPScheduleClause) OPENMP_CLAUSE(ordered, OMPOrderedClause) @@ -111,6 +112,7 @@ OPENMP_SECTIONS_CLAUSE(nowait) // TODO more clauses allowed for directive 'omp single'. OPENMP_SINGLE_CLAUSE(private) OPENMP_SINGLE_CLAUSE(firstprivate) +OPENMP_SINGLE_CLAUSE(copyprivate) OPENMP_SINGLE_CLAUSE(nowait) // Static attributes for 'default' clause. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index e87a3e6a45..ce3024ec04 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -7279,8 +7279,8 @@ public: Expr *Op); /// \brief Called on start of new data sharing attribute block. void StartOpenMPDSABlock(OpenMPDirectiveKind K, - const DeclarationNameInfo &DirName, - Scope *CurScope); + const DeclarationNameInfo &DirName, Scope *CurScope, + SourceLocation Loc); /// \brief Called on end of data sharing attribute block. void EndOpenMPDSABlock(Stmt *CurDirective); @@ -7300,8 +7300,7 @@ public: ArrayRef VarList); // brief Initialization of captured region for OpenMP region. - void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, SourceLocation Loc, - Scope *CurScope); + void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope); StmtResult ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, ArrayRef Clauses, Stmt *AStmt, @@ -7460,6 +7459,11 @@ public: SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'copyprivate' clause. + OMPClause *ActOnOpenMPCopyprivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); /// \brief The kind of conversion being performed. enum CheckedConversionKind { diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 5245944e85..102d14b475 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -1280,6 +1280,28 @@ OMPCopyinClause *OMPCopyinClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPCopyinClause(N); } +OMPCopyprivateClause *OMPCopyprivateClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef VL) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause), + llvm::alignOf()) + + sizeof(Expr *) * VL.size()); + OMPCopyprivateClause *Clause = + new (Mem) OMPCopyprivateClause(StartLoc, LParenLoc, EndLoc, VL.size()); + Clause->setVarRefs(VL); + return Clause; +} + +OMPCopyprivateClause *OMPCopyprivateClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause), + llvm::alignOf()) + + sizeof(Expr *) * N); + return new (Mem) OMPCopyprivateClause(N); +} + void OMPExecutableDirective::setClauses(ArrayRef Clauses) { assert(Clauses.size() == getNumClauses() && "Number of clauses is not the same as the preallocated buffer"); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 4a46063df3..28ce174207 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -748,6 +748,14 @@ void OMPClausePrinter::VisitOMPCopyinClause(OMPCopyinClause *Node) { } } +void OMPClausePrinter::VisitOMPCopyprivateClause(OMPCopyprivateClause *Node) { + if (!Node->varlist_empty()) { + OS << "copyprivate"; + VisitOMPClauseList(Node, '('); + OS << ")"; + } +} + } //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index f3f3c7ba8e..f562ed6aa7 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -335,6 +335,10 @@ void OMPClauseProfiler::VisitOMPAlignedClause(const OMPAlignedClause *C) { void OMPClauseProfiler::VisitOMPCopyinClause(const OMPCopyinClause *C) { VisitOMPClauseList(C); } +void +OMPClauseProfiler::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) { + VisitOMPClauseList(C); +} } void diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp index 623af2df60..07121215e7 100644 --- a/lib/Basic/OpenMPKinds.cpp +++ b/lib/Basic/OpenMPKinds.cpp @@ -95,6 +95,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_linear: case OMPC_aligned: case OMPC_copyin: + case OMPC_copyprivate: case OMPC_ordered: case OMPC_nowait: break; @@ -149,6 +150,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_linear: case OMPC_aligned: case OMPC_copyin: + case OMPC_copyprivate: case OMPC_ordered: case OMPC_nowait: break; @@ -193,7 +195,7 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, break; case OMPD_sections: switch (CKind) { -#define OPENMP_SECTIONS_CLAUSE(Name) \ +#define OPENMP_SECTIONS_CLAUSE(Name) \ case OMPC_##Name: \ return true; #include "clang/Basic/OpenMPKinds.def" @@ -203,7 +205,7 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, break; case OMPD_single: switch (CKind) { -#define OPENMP_SINGLE_CLAUSE(Name) \ +#define OPENMP_SINGLE_CLAUSE(Name) \ case OMPC_##Name: \ return true; #include "clang/Basic/OpenMPKinds.def" diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index 102cab36e9..b35082e6c4 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -131,7 +131,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() { if (isOpenMPSimdDirective(DKind)) ScopeFlags |= Scope::OpenMPSimdDirectiveScope; ParseScope OMPDirectiveScope(this, ScopeFlags); - Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope()); + Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc); while (Tok.isNot(tok::annot_pragma_openmp_end)) { OpenMPClauseKind CKind = Tok.isAnnotation() @@ -159,7 +159,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() { { // The body is a block scope like in Lambdas and Blocks. Sema::CompoundScopeRAII CompoundScope(Actions); - Actions.ActOnOpenMPRegionStart(DKind, Loc, getCurScope()); + Actions.ActOnOpenMPRegionStart(DKind, getCurScope()); Actions.ActOnStartOfCompoundStmt(); // Parse statement AssociatedStmt = ParseStatement(); @@ -269,7 +269,8 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, /// if-clause | num_threads-clause | safelen-clause | default-clause | /// private-clause | firstprivate-clause | shared-clause | linear-clause | /// aligned-clause | collapse-clause | lastprivate-clause | -/// reduction-clause | proc_bind-clause | schedule-clause +/// reduction-clause | proc_bind-clause | schedule-clause | +/// copyin-clause | copyprivate-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -345,6 +346,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_linear: case OMPC_aligned: case OMPC_copyin: + case OMPC_copyprivate: Clause = ParseOpenMPVarListClause(CKind); break; case OMPC_unknown: diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 7f3560fc01..6ff617fc17 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -68,7 +68,10 @@ public: OpenMPDirectiveKind DKind; OpenMPClauseKind CKind; DeclRefExpr *RefExpr; - DSAVarData() : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(nullptr) {} + SourceLocation ImplicitDSALoc; + DSAVarData() + : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(nullptr), + ImplicitDSALoc() {} }; private: @@ -83,17 +86,20 @@ private: DeclSAMapTy SharingMap; AlignedMapTy AlignedMap; DefaultDataSharingAttributes DefaultAttr; + SourceLocation DefaultAttrLoc; OpenMPDirectiveKind Directive; DeclarationNameInfo DirectiveName; Scope *CurScope; + SourceLocation ConstructLoc; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, - Scope *CurScope) + Scope *CurScope, SourceLocation Loc) : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified), - Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope) { - } + Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope), + ConstructLoc(Loc) {} SharingMapTy() : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified), - Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr) {} + Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr), + ConstructLoc() {} }; typedef SmallVector StackTy; @@ -113,8 +119,9 @@ public: explicit DSAStackTy(Sema &S) : Stack(1), SemaRef(S) {} void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, - Scope *CurScope) { - Stack.push_back(SharingMapTy(DKind, DirName, CurScope)); + Scope *CurScope, SourceLocation Loc) { + Stack.push_back(SharingMapTy(DKind, DirName, CurScope, Loc)); + Stack.back().DefaultAttrLoc = Loc; } void pop() { @@ -160,13 +167,22 @@ public: } /// \brief Set default data sharing attribute to none. - void setDefaultDSANone() { Stack.back().DefaultAttr = DSA_none; } + void setDefaultDSANone(SourceLocation Loc) { + Stack.back().DefaultAttr = DSA_none; + Stack.back().DefaultAttrLoc = Loc; + } /// \brief Set default data sharing attribute to shared. - void setDefaultDSAShared() { Stack.back().DefaultAttr = DSA_shared; } + void setDefaultDSAShared(SourceLocation Loc) { + Stack.back().DefaultAttr = DSA_shared; + Stack.back().DefaultAttrLoc = Loc; + } DefaultDataSharingAttributes getDefaultDSA() const { return Stack.back().DefaultAttr; } + SourceLocation getDefaultDSALocation() const { + return Stack.back().DefaultAttrLoc; + } /// \brief Checks if the specified variable is a threadprivate. bool isThreadPrivate(VarDecl *D) { @@ -176,6 +192,7 @@ public: Scope *getCurScope() const { return Stack.back().CurScope; } Scope *getCurScope() { return Stack.back().CurScope; } + SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; } }; } // namespace @@ -227,6 +244,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, switch (Iter->DefaultAttr) { case DSA_shared: DVar.CKind = OMPC_shared; + DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; return DVar; case DSA_none: return DVar; @@ -235,6 +253,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // in a Construct, implicitly determined, p.2] // In a parallel construct, if no default clause is present, these // variables are shared. + DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; if (isOpenMPParallelDirective(DVar.DKind)) { DVar.CKind = OMPC_shared; return DVar; @@ -456,8 +475,8 @@ void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, - Scope *CurScope) { - DSAStack->push(DKind, DirName, CurScope); + Scope *CurScope, SourceLocation Loc) { + DSAStack->push(DKind, DirName, CurScope, Loc); PushExpressionEvaluationContext(PotentiallyEvaluated); } @@ -776,8 +795,9 @@ static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, PDSA_LoopIterVarLastprivate, PDSA_ConstVarShared, PDSA_GlobalVarShared, - PDSA_LocalVarPrivate - } Reason; + PDSA_LocalVarPrivate, + PDSA_Implicit + } Reason = PDSA_Implicit; bool ReportHint = false; if (IsLoopIterVar) { if (DVar.CKind == OMPC_private) @@ -794,14 +814,18 @@ static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, Reason = PDSA_GlobalVarShared; else if (VD->getType().isConstant(SemaRef.getASTContext())) Reason = PDSA_ConstVarShared; - else { + else if (VD->isLocalVarDecl() && DVar.CKind == OMPC_private) { ReportHint = true; Reason = PDSA_LocalVarPrivate; } - - SemaRef.Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) - << Reason << ReportHint - << getOpenMPDirectiveName(Stack->getCurrentDirective()); + if (Reason != PDSA_Implicit) { + SemaRef.Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) + << Reason << ReportHint + << getOpenMPDirectiveName(Stack->getCurrentDirective()); + } else if (DVar.ImplicitDSALoc.isValid()) { + SemaRef.Diag(DVar.ImplicitDSALoc, diag::note_omp_implicit_dsa) + << getOpenMPClauseName(DVar.CKind); + } } namespace { @@ -882,8 +906,7 @@ public: }; } // namespace -void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, SourceLocation Loc, - Scope *CurScope) { +void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { switch (DKind) { case OMPD_parallel: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); @@ -893,42 +916,48 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, SourceLocation Loc, std::make_pair(".bound_tid.", KmpInt32PtrTy), std::make_pair(StringRef(), QualType()) // __context with shared vars }; - ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, Params); + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); break; } case OMPD_simd: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; - ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, Params); + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); break; } case OMPD_for: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; - ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, Params); + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); break; } case OMPD_sections: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; - ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, Params); + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); break; } case OMPD_section: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; - ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, Params); + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); break; } case OMPD_single: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; - ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, Params); + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); break; } case OMPD_threadprivate: @@ -1695,6 +1724,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_linear: case OMPC_aligned: case OMPC_copyin: + case OMPC_copyprivate: case OMPC_ordered: case OMPC_nowait: case OMPC_threadprivate: @@ -1874,6 +1904,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_linear: case OMPC_aligned: case OMPC_copyin: + case OMPC_copyprivate: case OMPC_ordered: case OMPC_nowait: case OMPC_threadprivate: @@ -1914,10 +1945,10 @@ OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, } switch (Kind) { case OMPC_DEFAULT_none: - DSAStack->setDefaultDSANone(); + DSAStack->setDefaultDSANone(KindKwLoc); break; case OMPC_DEFAULT_shared: - DSAStack->setDefaultDSAShared(); + DSAStack->setDefaultDSAShared(KindKwLoc); break; case OMPC_DEFAULT_unknown: llvm_unreachable("Clause kind is not allowed."); @@ -1984,6 +2015,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_linear: case OMPC_aligned: case OMPC_copyin: + case OMPC_copyprivate: case OMPC_ordered: case OMPC_nowait: case OMPC_threadprivate: @@ -2073,6 +2105,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_linear: case OMPC_aligned: case OMPC_copyin: + case OMPC_copyprivate: case OMPC_default: case OMPC_proc_bind: case OMPC_threadprivate: @@ -2126,6 +2159,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_copyin: Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc); break; + case OMPC_copyprivate: + Res = ActOnOpenMPCopyprivateClause(VarList, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_num_threads: case OMPC_safelen: @@ -3281,4 +3317,108 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef VarList, return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); } +OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector Vars; + for (auto &RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP copyprivate clause."); + if (isa(RefExpr)) { + // It will be analyzed later. + Vars.push_back(RefExpr); + continue; + } + + SourceLocation ELoc = RefExpr->getExprLoc(); + // OpenMP [2.1, C/C++] + // A list item is a variable name. + // OpenMP [2.14.4.1, Restrictions, p.1] + // A list item that appears in a copyin clause must be threadprivate. + DeclRefExpr *DE = dyn_cast(RefExpr); + if (!DE || !isa(DE->getDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + continue; + } + + Decl *D = DE->getDecl(); + VarDecl *VD = cast(D); + + QualType Type = VD->getType(); + if (Type->isDependentType() || Type->isInstantiationDependentType()) { + // It will be analyzed later. + Vars.push_back(DE); + continue; + } + + // OpenMP [2.14.4.2, Restrictions, p.2] + // A list item that appears in a copyprivate clause may not appear in a + // private or firstprivate clause on the single construct. + if (!DSAStack->isThreadPrivate(VD)) { + auto DVar = DSAStack->getTopDSA(VD); + if (DVar.CKind != OMPC_copyprivate && DVar.CKind != OMPC_unknown && + !(DVar.CKind == OMPC_private && !DVar.RefExpr)) { + Diag(ELoc, diag::err_omp_wrong_dsa) + << getOpenMPClauseName(DVar.CKind) + << getOpenMPClauseName(OMPC_copyprivate); + ReportOriginalDSA(*this, DSAStack, VD, DVar); + continue; + } + + // OpenMP [2.11.4.2, Restrictions, p.1] + // All list items that appear in a copyprivate clause must be either + // threadprivate or private in the enclosing context. + if (DVar.CKind == OMPC_unknown) { + DVar = DSAStack->getImplicitDSA(VD); + if (DVar.CKind == OMPC_shared) { + Diag(ELoc, diag::err_omp_required_access) + << getOpenMPClauseName(OMPC_copyprivate) + << "threadprivate or private in the enclosing context"; + ReportOriginalDSA(*this, DSAStack, VD, DVar); + continue; + } + } + } + + // OpenMP [2.14.4.1, Restrictions, C/C++, p.2] + // A variable of class type (or array thereof) that appears in a + // copyin clause requires an accessible, unambiguous copy assignment + // operator for the class type. + Type = Context.getBaseElementType(Type); + CXXRecordDecl *RD = + getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr; + // FIXME This code must be replaced by actual assignment of the + // threadprivate variable. + if (RD) { + CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0); + DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess()); + if (MD) { + if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible || + MD->isDeleted()) { + Diag(ELoc, diag::err_omp_required_method) + << getOpenMPClauseName(OMPC_copyprivate) << 2; + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + Diag(RD->getLocation(), diag::note_previous_decl) << RD; + continue; + } + MarkFunctionReferenced(ELoc, MD); + DiagnoseUseOfDecl(MD, ELoc); + } + } + + // No need to mark vars as copyprivate, they are already threadprivate or + // implicitly private. + Vars.push_back(DE); + } + + if (Vars.empty()) + return nullptr; + + return OMPCopyprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); +} + #undef DSAStack diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 974f5e061b..175c4e6502 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1494,6 +1494,18 @@ public: EndLoc); } + /// \brief Build a new OpenMP 'copyprivate' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPCopyprivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPCopyprivateClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + /// \brief Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -6403,7 +6415,8 @@ template StmtResult TreeTransform::TransformOMPParallelDirective(OMPParallelDirective *D) { DeclarationNameInfo DirName; - getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, nullptr); + getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, nullptr, + D->getLocStart()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; @@ -6413,7 +6426,8 @@ template StmtResult TreeTransform::TransformOMPSimdDirective(OMPSimdDirective *D) { DeclarationNameInfo DirName; - getDerived().getSema().StartOpenMPDSABlock(OMPD_simd, DirName, nullptr); + getDerived().getSema().StartOpenMPDSABlock(OMPD_simd, DirName, nullptr, + D->getLocStart()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; @@ -6423,7 +6437,8 @@ template StmtResult TreeTransform::TransformOMPForDirective(OMPForDirective *D) { DeclarationNameInfo DirName; - getDerived().getSema().StartOpenMPDSABlock(OMPD_for, DirName, nullptr); + getDerived().getSema().StartOpenMPDSABlock(OMPD_for, DirName, nullptr, + D->getLocStart()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; @@ -6433,7 +6448,8 @@ template StmtResult TreeTransform::TransformOMPSectionsDirective(OMPSectionsDirective *D) { DeclarationNameInfo DirName; - getDerived().getSema().StartOpenMPDSABlock(OMPD_sections, DirName, nullptr); + getDerived().getSema().StartOpenMPDSABlock(OMPD_sections, DirName, nullptr, + D->getLocStart()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; @@ -6443,7 +6459,8 @@ template StmtResult TreeTransform::TransformOMPSectionDirective(OMPSectionDirective *D) { DeclarationNameInfo DirName; - getDerived().getSema().StartOpenMPDSABlock(OMPD_section, DirName, nullptr); + getDerived().getSema().StartOpenMPDSABlock(OMPD_section, DirName, nullptr, + D->getLocStart()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; @@ -6453,7 +6470,8 @@ template StmtResult TreeTransform::TransformOMPSingleDirective(OMPSingleDirective *D) { DeclarationNameInfo DirName; - getDerived().getSema().StartOpenMPDSABlock(OMPD_single, DirName, nullptr); + getDerived().getSema().StartOpenMPDSABlock(OMPD_single, DirName, nullptr, + D->getLocStart()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; @@ -6680,6 +6698,21 @@ TreeTransform::TransformOMPCopyinClause(OMPCopyinClause *C) { C->getLParenLoc(), C->getLocEnd()); } +template +OMPClause * +TreeTransform::TransformOMPCopyprivateClause(OMPCopyprivateClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPCopyprivateClause( + Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index ea8d0f3ac9..c94c43578f 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1724,6 +1724,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_copyin: C = OMPCopyinClause::CreateEmpty(Context, Record[Idx++]); break; + case OMPC_copyprivate: + C = OMPCopyprivateClause::CreateEmpty(Context, Record[Idx++]); + break; } Visit(C); C->setLocStart(Reader->ReadSourceLocation(Record, Idx)); @@ -1871,6 +1874,16 @@ void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *C) { C->setVarRefs(Vars); } +void OMPClauseReader::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) { + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader->Reader.ReadSubExpr()); + C->setVarRefs(Vars); +} + //===----------------------------------------------------------------------===// // OpenMP Directives. //===----------------------------------------------------------------------===// diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 1292ec8aa8..8655bc67ed 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1782,6 +1782,13 @@ void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) { Writer->Writer.AddStmt(VE); } +void OMPClauseWriter::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) { + Record.push_back(C->varlist_size()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); + for (auto *VE : C->varlists()) + Writer->Writer.AddStmt(VE); +} + //===----------------------------------------------------------------------===// // OpenMP Directives. //===----------------------------------------------------------------------===// diff --git a/test/OpenMP/single_ast_print.cpp b/test/OpenMP/single_ast_print.cpp index eaae114960..65a007e271 100644 --- a/test/OpenMP/single_ast_print.cpp +++ b/test/OpenMP/single_ast_print.cpp @@ -13,11 +13,11 @@ T tmain(T argc) { T b = argc, c, d, e, f, g; static T a; // CHECK: static T a; -#pragma omp parallel -#pragma omp single private(argc, b), firstprivate(c, d), nowait +#pragma omp parallel private(g) +#pragma omp single private(argc, b), firstprivate(c, d), nowait copyprivate(g) foo(); - // CHECK-NEXT: #pragma omp parallel - // CHECK-NEXT: #pragma omp single private(argc,b) firstprivate(c,d) nowait + // CHECK-NEXT: #pragma omp parallel private(g) + // CHECK-NEXT: #pragma omp single private(argc,b) firstprivate(c,d) nowait copyprivate(g) // CHECK-NEXT: foo(); return T(); } @@ -26,11 +26,11 @@ int main(int argc, char **argv) { int b = argc, c, d, e, f, g; static int a; // CHECK: static int a; -#pragma omp parallel -#pragma omp single private(argc, b), firstprivate(argv, c), nowait +#pragma omp parallel private(g) +#pragma omp single private(argc, b), firstprivate(argv, c), nowait copyprivate(g) foo(); - // CHECK-NEXT: #pragma omp parallel - // CHECK-NEXT: #pragma omp single private(argc,b) firstprivate(argv,c) nowait + // CHECK-NEXT: #pragma omp parallel private(g) + // CHECK-NEXT: #pragma omp single private(argc,b) firstprivate(argv,c) nowait copyprivate(g) // CHECK-NEXT: foo(); return (tmain(argc) + tmain(argv[0][0])); } diff --git a/test/OpenMP/single_copyprivate_messages.cpp b/test/OpenMP/single_copyprivate_messages.cpp new file mode 100644 index 0000000000..f07ab12bfb --- /dev/null +++ b/test/OpenMP/single_copyprivate_messages.cpp @@ -0,0 +1,157 @@ +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s + +void foo() { +} + +struct S1; // expected-note 2 {{declared here}} +class S2 { + mutable int a; + +public: + S2() : a(0) {} + S2 &operator=(S2 &s2) { return *this; } +}; +class S3 { + int a; + +public: + S3() : a(0) {} + S3 &operator=(S3 &s3) { return *this; } +}; +class S4 { // expected-note 2 {{'S4' declared here}} + int a; + S4(); + S4 &operator=(const S4 &s4); + +public: + S4(int v) : a(v) {} +}; +class S5 { // expected-note 2 {{'S5' declared here}} + int a; + S5() : a(0) {} + S5 &operator=(const S5 &s5) { return *this; } + +public: + S5(int v) : a(v) {} +}; + +S2 k; +S3 h; +S4 l(3); // expected-note 2 {{'l' defined here}} +S5 m(4); // expected-note 2 {{'m' defined here}} +#pragma omp threadprivate(h, k, l, m) + +template +T tmain(T argc, C **argv) { + T i; +#pragma omp parallel +#pragma omp single copyprivate // expected-error {{expected '(' after 'copyprivate'}} +#pragma omp parallel +#pragma omp single copyprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp parallel +#pragma omp single copyprivate() // expected-error {{expected expression}} +#pragma omp parallel +#pragma omp single copyprivate(k // expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp parallel +#pragma omp single copyprivate(h, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp parallel +#pragma omp single copyprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} +#pragma omp parallel +#pragma omp single copyprivate(l) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}} +#pragma omp parallel +#pragma omp single copyprivate(S1) // expected-error {{'S1' does not refer to a value}} +#pragma omp parallel +#pragma omp single copyprivate(argv[1]) // expected-error {{expected variable name}} +#pragma omp parallel // expected-note {{implicitly determined as shared}} +#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} +#pragma omp parallel +#pragma omp single copyprivate(m) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}} + foo(); +#pragma omp parallel private(i) + { +#pragma omp single copyprivate(i) + foo(); + } +#pragma omp parallel shared(i) // expected-note {{defined as shared}} + { +#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} + foo(); + } +#pragma omp parallel private(i) +#pragma omp parallel default(shared) // expected-note {{implicitly determined as shared}} + { +#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} + foo(); + } +#pragma omp parallel private(i) +#pragma omp parallel // expected-note {{implicitly determined as shared}} + { +#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} + foo(); + } +#pragma omp parallel +#pragma omp single private(i) copyprivate(i) // expected-error {{private variable cannot be copyprivate}} expected-note {{defined as private}} + foo(); +#pragma omp parallel +#pragma omp single firstprivate(i) copyprivate(i) // expected-error {{firstprivate variable cannot be copyprivate}} expected-note {{defined as firstprivate}} + foo(); + + return T(); +} + +int main(int argc, char **argv) { + int i; +#pragma omp parallel +#pragma omp single copyprivate // expected-error {{expected '(' after 'copyprivate'}} +#pragma omp parallel +#pragma omp single copyprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp parallel +#pragma omp single copyprivate() // expected-error {{expected expression}} +#pragma omp parallel +#pragma omp single copyprivate(k // expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp parallel +#pragma omp single copyprivate(h, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp parallel +#pragma omp single copyprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} +#pragma omp parallel +#pragma omp single copyprivate(l) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}} +#pragma omp parallel +#pragma omp single copyprivate(S1) // expected-error {{'S1' does not refer to a value}} +#pragma omp parallel +#pragma omp single copyprivate(argv[1]) // expected-error {{expected variable name}} +#pragma omp parallel // expected-note {{implicitly determined as shared}} +#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} +#pragma omp parallel +#pragma omp single copyprivate(m) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}} + foo(); +#pragma omp parallel private(i) + { +#pragma omp single copyprivate(i) + foo(); + } +#pragma omp parallel shared(i) // expected-note {{defined as shared}} + { +#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} + foo(); + } +#pragma omp parallel private(i) +#pragma omp parallel default(shared) // expected-note {{implicitly determined as shared}} + { +#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} + foo(); + } +#pragma omp parallel private(i) +#pragma omp parallel // expected-note {{implicitly determined as shared}} + { +#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} + foo(); + } +#pragma omp parallel +#pragma omp single private(i) copyprivate(i) // expected-error {{private variable cannot be copyprivate}} expected-note {{defined as private}} + foo(); +#pragma omp parallel +#pragma omp single firstprivate(i) copyprivate(i) // expected-error {{firstprivate variable cannot be copyprivate}} expected-note {{defined as firstprivate}} + foo(); + + return tmain(argc, argv); // expected-note {{in instantiation of function template specialization 'tmain' requested here}} +} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 93cb0500df..78144d50e5 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1989,6 +1989,10 @@ void OMPClauseEnqueue::VisitOMPAlignedClause(const OMPAlignedClause *C) { void OMPClauseEnqueue::VisitOMPCopyinClause(const OMPCopyinClause *C) { VisitOMPClauseList(C); } +void +OMPClauseEnqueue::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) { + VisitOMPClauseList(C); +} } void EnqueueVisitor::EnqueueChildren(const OMPClause *S) { -- cgit v1.2.3