From a100391cc47d7e9db05cc239b1919b958da71cb0 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Mon, 31 Mar 2014 03:36:38 +0000 Subject: [PATCH] [OPENMP] Implemented 'copyin' clause git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205164 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DataRecursiveASTVisitor.h | 6 ++ include/clang/AST/OpenMPClause.h | 61 ++++++++++++- include/clang/AST/RecursiveASTVisitor.h | 6 ++ include/clang/Basic/DiagnosticSemaKinds.td | 2 + include/clang/Basic/OpenMPKinds.def | 2 + include/clang/Sema/Sema.h | 5 ++ lib/AST/Stmt.cpp | 22 +++++ lib/AST/StmtPrinter.cpp | 20 ++++- lib/AST/StmtProfile.cpp | 3 + lib/Basic/OpenMPKinds.cpp | 2 + lib/Parse/ParseOpenMP.cpp | 1 + lib/Sema/SemaOpenMP.cpp | 98 ++++++++++++++++++++- lib/Sema/TreeTransform.h | 31 +++++++ lib/Serialization/ASTReaderStmt.cpp | 13 +++ lib/Serialization/ASTWriterStmt.cpp | 9 ++ test/OpenMP/parallel_ast_print.cpp | 29 ++++-- test/OpenMP/parallel_copyin_messages.cpp | 67 ++++++++++++++ tools/libclang/CIndex.cpp | 3 + 18 files changed, 367 insertions(+), 13 deletions(-) create mode 100644 test/OpenMP/parallel_copyin_messages.cpp diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h index 01934ce26d..d10258e6f9 100644 --- a/include/clang/AST/DataRecursiveASTVisitor.h +++ b/include/clang/AST/DataRecursiveASTVisitor.h @@ -2405,6 +2405,12 @@ bool DataRecursiveASTVisitor::VisitOMPSharedClause(OMPSharedClause *C) return true; } +template +bool DataRecursiveASTVisitor::VisitOMPCopyinClause(OMPCopyinClause *C) { + VisitOMPClauseList(C); + return true; +} + // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods // returning decls or qualtypes or nestednamespecifier -- though I'm diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h index 97c4869b98..64b5ce4c5b 100644 --- a/include/clang/AST/OpenMPClause.h +++ b/include/clang/AST/OpenMPClause.h @@ -95,7 +95,7 @@ protected: llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf()))); } - /// \brief Build clause with number of variables \a N. + /// \brief Build a clause with \a N variables /// /// \param K Kind of the clause. /// \param StartLoc Starting location of the clause (the clause keyword). @@ -553,6 +553,65 @@ public: } }; +/// \brief This represents clause 'copyin' in the '#pragma omp ...' directives. +/// +/// \code +/// #pragma omp parallel copyin(a,b) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'copyin' +/// with the variables 'a' and 'b'. +/// +class OMPCopyinClause : 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. + /// + OMPCopyinClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause(OMPC_copyin, StartLoc, LParenLoc, + EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPCopyinClause(unsigned N) + : OMPVarListClause(OMPC_copyin, 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 OMPCopyinClause *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 OMPCopyinClause *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_copyin; + } +}; + } // end namespace clang #endif diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 9541b66487..1a2ce44556 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -2442,6 +2442,12 @@ bool RecursiveASTVisitor::VisitOMPSharedClause(OMPSharedClause *C) { return true; } +template +bool RecursiveASTVisitor::VisitOMPCopyinClause(OMPCopyinClause *C) { + VisitOMPClauseList(C); + return true; +} + // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods // returning decls or qualtypes or nestednamespecifier -- though I'm diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b89073fc11..1a6784bef9 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -6915,6 +6915,8 @@ def note_omp_conversion_here : Note< def err_omp_ambiguous_conversion : Error< "ambiguous conversion from type %0 to an integral or unscoped " "enumeration type">; +def err_omp_required_access : Error< + "%0 variable must be %1">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def index c753f0c422..348f40f416 100644 --- a/include/clang/Basic/OpenMPKinds.def +++ b/include/clang/Basic/OpenMPKinds.def @@ -42,6 +42,7 @@ OPENMP_CLAUSE(default, OMPDefaultClause) OPENMP_CLAUSE(private, OMPPrivateClause) OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause) OPENMP_CLAUSE(shared, OMPSharedClause) +OPENMP_CLAUSE(copyin, OMPCopyinClause) // Clauses allowed for OpenMP directive 'parallel'. OPENMP_PARALLEL_CLAUSE(if) @@ -50,6 +51,7 @@ OPENMP_PARALLEL_CLAUSE(default) OPENMP_PARALLEL_CLAUSE(private) OPENMP_PARALLEL_CLAUSE(firstprivate) OPENMP_PARALLEL_CLAUSE(shared) +OPENMP_PARALLEL_CLAUSE(copyin) // FIXME: more clauses allowed for directive 'omp simd'. OPENMP_SIMD_CLAUSE(private) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 2492c06ad5..fea0956d6f 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -7210,6 +7210,11 @@ public: SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'copyin' clause. + OMPClause *ActOnOpenMPCopyinClause(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 8da7956aed..a03ef00ce7 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -1192,6 +1192,28 @@ OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPSharedClause(N); } +OMPCopyinClause *OMPCopyinClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef VL) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause), + llvm::alignOf()) + + sizeof(Expr *) * VL.size()); + OMPCopyinClause *Clause = new (Mem) OMPCopyinClause(StartLoc, LParenLoc, + EndLoc, VL.size()); + Clause->setVarRefs(VL); + return Clause; +} + +OMPCopyinClause *OMPCopyinClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause), + llvm::alignOf()) + + sizeof(Expr *) * N); + return new (Mem) OMPCopyinClause(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 2371b93fe4..7ad5491005 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -629,9 +629,15 @@ template void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) { for (typename T::varlist_iterator I = Node->varlist_begin(), E = Node->varlist_end(); - I != E; ++I) - OS << (I == Node->varlist_begin() ? StartSym : ',') - << *cast(cast(*I)->getDecl()); + I != E; ++I) { + if (DeclRefExpr *DRE = dyn_cast(*I)) { + OS << (I == Node->varlist_begin() ? StartSym : ','); + cast(DRE->getDecl())->printQualifiedName(OS); + } else { + OS << (I == Node->varlist_begin() ? StartSym : ','); + (*I)->printPretty(OS, 0, Policy, 0); + } + } } void OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) { @@ -658,6 +664,14 @@ void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) { } } +void OMPClausePrinter::VisitOMPCopyinClause(OMPCopyinClause *Node) { + if (!Node->varlist_empty()) { + OS << "copyin"; + VisitOMPClauseList(Node, '('); + OS << ")"; + } +} + } //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 9fc4c77e2c..07ed86a91c 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -297,6 +297,9 @@ void OMPClauseProfiler::VisitOMPFirstprivateClause( void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) { VisitOMPClauseList(C); } +void OMPClauseProfiler::VisitOMPCopyinClause(const OMPCopyinClause *C) { + VisitOMPClauseList(C); +} } void diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp index a5147a2136..ec09de1eb3 100644 --- a/lib/Basic/OpenMPKinds.cpp +++ b/lib/Basic/OpenMPKinds.cpp @@ -83,6 +83,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_private: case OMPC_firstprivate: case OMPC_shared: + case OMPC_copyin: case NUM_OPENMP_CLAUSES: break; } @@ -109,6 +110,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_private: case OMPC_firstprivate: case OMPC_shared: + case OMPC_copyin: case NUM_OPENMP_CLAUSES: break; } diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index fa55b44da7..f1b61077b3 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -301,6 +301,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_private: case OMPC_firstprivate: case OMPC_shared: + case OMPC_copyin: Clause = ParseOpenMPVarListClause(CKind); break; case OMPC_unknown: diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index dc2a68d418..78f73c0c26 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -111,7 +111,6 @@ public: DSAVarData hasDSA(VarDecl *D, OpenMPClauseKind CKind, OpenMPDirectiveKind DKind = OMPD_unknown); - /// \brief Returns currently analyzed directive. OpenMPDirectiveKind getCurrentDirective() const { return Stack.back().Directive; @@ -126,6 +125,13 @@ public: return Stack.back().DefaultAttr; } + /// \brief Checks if the spewcified variable is threadprivate. + bool isThreadPrivate(VarDecl *D) { + DSAVarData DVar = getTopDSA(D); + return (DVar.CKind == OMPC_threadprivate || DVar.CKind == OMPC_copyin); + } + + Scope *getCurScope() const { return Stack.back().CurScope; } Scope *getCurScope() { return Stack.back().CurScope; } }; } // end anonymous namespace. @@ -245,7 +251,8 @@ void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) { } } -bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { +bool +DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { if (Stack.size() > 2) { reverse_iterator I = Iter, E = Stack.rend() - 1; Scope *TopScope = 0; @@ -611,7 +618,7 @@ public: DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD); if (DVar.CKind != OMPC_unknown) { if (DKind == OMPD_task && DVar.CKind != OMPC_shared && - DVar.CKind != OMPC_threadprivate && !DVar.RefExpr) + !Stack->isThreadPrivate(VD) && !DVar.RefExpr) ImplicitFirstprivate.push_back(DVar.RefExpr); return; } @@ -768,6 +775,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, case OMPC_private: case OMPC_firstprivate: case OMPC_shared: + case OMPC_copyin: case OMPC_threadprivate: case OMPC_unknown: case NUM_OPENMP_CLAUSES: @@ -922,6 +930,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, case OMPC_private: case OMPC_firstprivate: case OMPC_shared: + case OMPC_copyin: case OMPC_threadprivate: case OMPC_unknown: case NUM_OPENMP_CLAUSES: @@ -992,6 +1001,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, case OMPC_shared: Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc); break; + case OMPC_copyin: + Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_num_threads: case OMPC_safelen: @@ -1371,4 +1383,84 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef VarList, return OMPSharedClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); } +OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector Vars; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "NULL expr in OpenMP copyin clause."); + if (isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + continue; + } + + SourceLocation ELoc = (*I)->getExprLoc(); + // OpenMP [2.1, C/C++] + // A list item is a variable name. + // OpenMP [2.14.4.1, Restrictions, p.1] + // A list item that appears in a copyin clause must be threadprivate. + DeclRefExpr *DE = dyn_cast(*I); + if (!DE || !isa(DE->getDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name) + << (*I)->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.1, Restrictions, C/C++, p.1] + // A list item that appears in a copyin clause must be threadprivate. + if (!DSAStack->isThreadPrivate(VD)) { + Diag(ELoc, diag::err_omp_required_access) + << getOpenMPClauseName(OMPC_copyin) + << getOpenMPDirectiveName(OMPD_threadprivate); + 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 accesible, unambiguous copy assignment + // operator for the class type. + Type = Context.getBaseElementType(Type); + CXXRecordDecl *RD = getLangOpts().CPlusPlus ? + Type->getAsCXXRecordDecl() : 0; + if (RD) { + CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0); + DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess()); + if (!MD || + CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible || + MD->isDeleted()) { + Diag(ELoc, diag::err_omp_required_method) + << getOpenMPClauseName(OMPC_copyin) << 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); + } + + DSAStack->addDSA(VD, DE, OMPC_copyin); + Vars.push_back(DE); + } + + if (Vars.empty()) return 0; + + return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); +} + #undef DSAStack diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index a8ec18c740..2c7328983a 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1382,6 +1382,18 @@ public: EndLoc); } + /// \brief Build a new OpenMP 'copyin' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPCopyinClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + /// \brief Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -6422,6 +6434,25 @@ TreeTransform::TransformOMPSharedClause(OMPSharedClause *C) { C->getLocEnd()); } +template +OMPClause * +TreeTransform::TransformOMPCopyinClause(OMPCopyinClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPCopyinClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPCopyinClause(Vars, + C->getLocStart(), + C->getLParenLoc(), + C->getLocEnd()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 594d029e0e..9a201d0f69 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1692,6 +1692,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_shared: C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]); break; + case OMPC_copyin: + C = OMPCopyinClause::CreateEmpty(Context, Record[Idx++]); + break; } Visit(C); C->setLocStart(Reader->ReadSourceLocation(Record, Idx)); @@ -1752,6 +1755,16 @@ void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) { C->setVarRefs(Vars); } +void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *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 866b738d74..42b1dfb367 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1716,6 +1716,15 @@ void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) { Writer->Writer.AddStmt(I); } +void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) { + Record.push_back(C->varlist_size()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); + for (OMPCopyinClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer->Writer.AddStmt(*I); +} + //===----------------------------------------------------------------------===// // OpenMP Directives. //===----------------------------------------------------------------------===// diff --git a/test/OpenMP/parallel_ast_print.cpp b/test/OpenMP/parallel_ast_print.cpp index beb29ec15a..c12c5b8dec 100644 --- a/test/OpenMP/parallel_ast_print.cpp +++ b/test/OpenMP/parallel_ast_print.cpp @@ -11,8 +11,23 @@ void foo() {} template struct S { operator T() {return T();} + static T TS; + #pragma omp threadprivate(TS) }; +// CHECK: template struct S { +// CHECK: static int TS; +// CHECK-NEXT: #pragma omp threadprivate(S::TS) +// CHECK-NEXT: } +// CHECK: template struct S { +// CHECK: static long TS; +// CHECK-NEXT: #pragma omp threadprivate(S::TS) +// CHECK-NEXT: } +// CHECK: template struct S { +// CHECK: static T TS; +// CHECK-NEXT: #pragma omp threadprivate(S::TS) +// CHECK: }; + template T tmain(T argc, T *argv) { T b = argc, c, d, e, f, g; @@ -20,19 +35,20 @@ T tmain(T argc, T *argv) { S s; #pragma omp parallel a=2; -#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (argc > 0) num_threads(C) +#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (argc > 0) num_threads(C) copyin(S::TS) foo(); #pragma omp parallel if (C) num_threads(s) foo(); return 0; } + // CHECK: template int tmain(int argc, int *argv) { // CHECK-NEXT: int b = argc, c, d, e, f, g; // CHECK-NEXT: static int a; // CHECK-NEXT: S s; // CHECK-NEXT: #pragma omp parallel // CHECK-NEXT: a = 2; -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(5) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(5) copyin(S::TS) // CHECK-NEXT: foo() // CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) // CHECK-NEXT: foo() @@ -42,7 +58,7 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: S s; // CHECK-NEXT: #pragma omp parallel // CHECK-NEXT: a = 2; -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(1) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(1) copyin(S::TS) // CHECK-NEXT: foo() // CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) // CHECK-NEXT: foo() @@ -52,7 +68,7 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: S s; // CHECK-NEXT: #pragma omp parallel // CHECK-NEXT: a = 2; -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(C) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(C) copyin(S::TS) // CHECK-NEXT: foo() // CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) // CHECK-NEXT: foo() @@ -63,14 +79,15 @@ int main (int argc, char **argv) { long x; int b = argc, c, d, e, f, g; static int a; + #pragma omp threadprivate(a) Enum ee; // CHECK: Enum ee; #pragma omp parallel // CHECK-NEXT: #pragma omp parallel a=2; // CHECK-NEXT: a = 2; -#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (argc > 0) num_threads(ee) -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(argc > 0) num_threads(ee) +#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (argc > 0) num_threads(ee) copyin(a) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(argc > 0) num_threads(ee) copyin(a) foo(); // CHECK-NEXT: foo(); return tmain(b, &b) + tmain(x, &x); diff --git a/test/OpenMP/parallel_copyin_messages.cpp b/test/OpenMP/parallel_copyin_messages.cpp new file mode 100644 index 0000000000..c1ce363b47 --- /dev/null +++ b/test/OpenMP/parallel_copyin_messages.cpp @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{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 {{'S4' declared here}} + int a; + S4(); + S4 &operator =(const S4 &s4); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} + S5 &operator =(const S5 &s5) { return *this; } +public: + S5(int v):a(v) { } +}; +template +class ST { +public: + static T s; +}; + + +S2 k; +S3 h; +S4 l(3); // expected-note {{'l' defined here}} +S5 m(4); // expected-note {{'m' defined here}} +#pragma omp threadprivate(h, k, l, m) + +int main(int argc, char **argv) { + int i; + #pragma omp parallel copyin // expected-error {{expected '(' after 'copyin'}} + #pragma omp parallel copyin ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel copyin () // expected-error {{expected expression}} + #pragma omp parallel copyin (k // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel copyin (h, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel copyin (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp parallel copyin (l) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}} + #pragma omp parallel copyin (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp parallel copyin (argv[1]) // expected-error {{expected variable name}} + #pragma omp parallel copyin(i) // expected-error {{copyin variable must be threadprivate}} + #pragma omp parallel copyin(m) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}} + #pragma omp parallel copyin(ST::s) // expected-error {{copyin variable must be threadprivate}} + foo(); + + return 0; +} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index e3de44675f..04797a98d3 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1954,6 +1954,9 @@ void OMPClauseEnqueue::VisitOMPFirstprivateClause( void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) { VisitOMPClauseList(C); } +void OMPClauseEnqueue::VisitOMPCopyinClause(const OMPCopyinClause *C) { + VisitOMPClauseList(C); +} } void EnqueueVisitor::EnqueueChildren(const OMPClause *S) { -- 2.40.0