summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DataRecursiveASTVisitor.h7
-rw-r--r--include/clang/AST/OpenMPClause.h60
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h7
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--include/clang/Basic/OpenMPKinds.def2
-rw-r--r--include/clang/Sema/Sema.h12
-rw-r--r--lib/AST/Stmt.cpp22
-rw-r--r--lib/AST/StmtPrinter.cpp8
-rw-r--r--lib/AST/StmtProfile.cpp4
-rw-r--r--lib/Basic/OpenMPKinds.cpp6
-rw-r--r--lib/Parse/ParseOpenMP.cpp8
-rw-r--r--lib/Sema/SemaOpenMP.cpp196
-rw-r--r--lib/Sema/TreeTransform.h45
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp13
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp7
-rw-r--r--test/OpenMP/single_ast_print.cpp16
-rw-r--r--test/OpenMP/single_copyprivate_messages.cpp157
-rw-r--r--tools/libclang/CIndex.cpp4
18 files changed, 525 insertions, 51 deletions
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
@@ -2434,6 +2434,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPCopyprivateClause(
+ OMPCopyprivateClause *C) {
+ VisitOMPClauseList(C);
+ return true;
+}
+
+template <typename Derived>
bool
RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
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<OMPCopyprivateClause> {
+ /// \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<OMPCopyprivateClause>(OMPC_copyprivate, StartLoc,
+ LParenLoc, EndLoc, N) {}
+
+ /// \brief Build an empty clause.
+ ///
+ /// \param N Number of variables.
+ ///
+ explicit OMPCopyprivateClause(unsigned N)
+ : OMPVarListClause<OMPCopyprivateClause>(
+ 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<Expr *> 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<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(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
@@ -2456,6 +2456,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPCopyprivateClause(
+ OMPCopyprivateClause *C) {
+ VisitOMPClauseList(C);
+ return true;
+}
+
+template <typename Derived>
bool
RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
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<Expr *> 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<OMPClause *> Clauses,
Stmt *AStmt,
@@ -7460,6 +7459,11 @@ public:
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
+ /// \brief Called on well-formed 'copyprivate' clause.
+ OMPClause *ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> 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<Expr *> VL) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause),
+ llvm::alignOf<Expr *>()) +
+ 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<Expr *>()) +
+ sizeof(Expr *) * N);
+ return new (Mem) OMPCopyprivateClause(N);
+}
+
void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> 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<SharingMapTy, 64> 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<Expr *> VarList,
return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
}
+OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP copyprivate clause.");
+ if (isa<DependentScopeDeclRefExpr>(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<DeclRefExpr>(RefExpr);
+ if (!DE || !isa<VarDecl>(DE->getDecl())) {
+ Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ continue;
+ }
+
+ Decl *D = DE->getDecl();
+ VarDecl *VD = cast<VarDecl>(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<Expr *> 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 <typename Derived>
StmtResult
TreeTransform<Derived>::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 <typename Derived>
StmtResult
TreeTransform<Derived>::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 <typename Derived>
StmtResult
TreeTransform<Derived>::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 <typename Derived>
StmtResult
TreeTransform<Derived>::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 <typename Derived>
StmtResult
TreeTransform<Derived>::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 <typename Derived>
StmtResult
TreeTransform<Derived>::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<Derived>::TransformOMPCopyinClause(OMPCopyinClause *C) {
C->getLParenLoc(), C->getLocEnd());
}
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPCopyprivateClause(OMPCopyprivateClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(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<Expr *, 16> 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<int, 5>(argc) + tmain<char, 1>(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 <class T, class C>
+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<int, char>' 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) {