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.h5
-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.cpp2
-rw-r--r--lib/Parse/ParseOpenMP.cpp7
-rw-r--r--lib/Sema/SemaOpenMP.cpp183
-rw-r--r--lib/Sema/TreeTransform.h27
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp13
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp7
-rw-r--r--test/OpenMP/simd_ast_print.cpp8
-rw-r--r--test/OpenMP/simd_lastprivate_messages.cpp160
-rw-r--r--test/OpenMP/simd_loop_messages.cpp3
-rw-r--r--test/OpenMP/simd_misc_messages.c45
-rw-r--r--tools/libclang/CIndex.cpp4
20 files changed, 565 insertions, 11 deletions
diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h
index d754e70bd1..829f6c9c77 100644
--- a/include/clang/AST/DataRecursiveASTVisitor.h
+++ b/include/clang/AST/DataRecursiveASTVisitor.h
@@ -2354,6 +2354,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPLastprivateClause(
+ OMPLastprivateClause *C) {
+ VisitOMPClauseList(C);
+ return true;
+}
+
+template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
VisitOMPClauseList(C);
return true;
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index c4717c8ea0..74a6a9eedc 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -620,6 +620,66 @@ public:
}
};
+/// \brief This represents clause 'lastprivate' in the '#pragma omp ...'
+/// directives.
+///
+/// \code
+/// #pragma omp simd lastprivate(a,b)
+/// \endcode
+/// In this example directive '#pragma omp simd' has clause 'lastprivate'
+/// with the variables 'a' and 'b'.
+///
+class OMPLastprivateClause : public OMPVarListClause<OMPLastprivateClause> {
+ /// \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.
+ ///
+ OMPLastprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, unsigned N)
+ : OMPVarListClause<OMPLastprivateClause>(OMPC_lastprivate, StartLoc,
+ LParenLoc, EndLoc, N) {}
+
+ /// \brief Build an empty clause.
+ ///
+ /// \param N Number of variables.
+ ///
+ explicit OMPLastprivateClause(unsigned N)
+ : OMPVarListClause<OMPLastprivateClause>(
+ OMPC_lastprivate, 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 OMPLastprivateClause *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL);
+ /// \brief Creates an empty clause with the place for \a N variables.
+ ///
+ /// \param C AST context.
+ /// \param N The number of variables.
+ ///
+ static OMPLastprivateClause *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_lastprivate;
+ }
+};
+
/// \brief This represents clause 'shared' in the '#pragma omp ...' directives.
///
/// \code
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 56c07d4a05..1fee8a98c8 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -2375,6 +2375,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPLastprivateClause(
+ OMPLastprivateClause *C) {
+ VisitOMPClauseList(C);
+ return true;
+}
+
+template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
VisitOMPClauseList(C);
return true;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 2ea49df7cb..a15a6e36dc 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6923,6 +6923,8 @@ def err_omp_private_incomplete_type : Error<
"a private variable with incomplete type %0">;
def err_omp_firstprivate_incomplete_type : Error<
"a firstprivate variable with incomplete type %0">;
+def err_omp_lastprivate_incomplete_type : Error<
+ "a lastprivate variable with incomplete type %0">;
def err_omp_unexpected_clause_value : Error<
"expected %0 in OpenMP clause '%1'">;
def err_omp_expected_var_name : Error<
diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def
index 2c57100399..0a6b162abd 100644
--- a/include/clang/Basic/OpenMPKinds.def
+++ b/include/clang/Basic/OpenMPKinds.def
@@ -45,6 +45,7 @@ OPENMP_CLAUSE(collapse, OMPCollapseClause)
OPENMP_CLAUSE(default, OMPDefaultClause)
OPENMP_CLAUSE(private, OMPPrivateClause)
OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause)
+OPENMP_CLAUSE(lastprivate, OMPLastprivateClause)
OPENMP_CLAUSE(shared, OMPSharedClause)
OPENMP_CLAUSE(linear, OMPLinearClause)
OPENMP_CLAUSE(aligned, OMPAlignedClause)
@@ -63,6 +64,7 @@ OPENMP_PARALLEL_CLAUSE(copyin)
// FIXME: more clauses allowed for directive 'omp simd'.
OPENMP_SIMD_CLAUSE(private)
+OPENMP_SIMD_CLAUSE(lastprivate)
OPENMP_SIMD_CLAUSE(linear)
OPENMP_SIMD_CLAUSE(aligned)
OPENMP_SIMD_CLAUSE(safelen)
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 39bb1562ed..2b69fc714f 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -7367,6 +7367,11 @@ public:
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
+ /// \brief Called on well-formed 'lastprivate' clause.
+ OMPClause *ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
/// \brief Called on well-formed 'shared' clause.
OMPClause *ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index e6aa472c39..52906877cf 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -1168,6 +1168,28 @@ OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPFirstprivateClause(N);
}
+OMPLastprivateClause *OMPLastprivateClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastprivateClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * VL.size());
+ OMPLastprivateClause *Clause =
+ new (Mem) OMPLastprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPLastprivateClause *OMPLastprivateClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastprivateClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * N);
+ return new (Mem) OMPLastprivateClause(N);
+}
+
OMPSharedClause *OMPSharedClause::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation LParenLoc,
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index c9d09b74ea..297de5e09a 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -657,6 +657,14 @@ void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) {
}
}
+void OMPClausePrinter::VisitOMPLastprivateClause(OMPLastprivateClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "lastprivate";
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
+
void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) {
if (!Node->varlist_empty()) {
OS << "shared";
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index d96a6116ae..45e94d31e1 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -301,6 +301,10 @@ void OMPClauseProfiler::VisitOMPFirstprivateClause(
const OMPFirstprivateClause *C) {
VisitOMPClauseList(C);
}
+void
+OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) {
+ VisitOMPClauseList(C);
+}
void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) {
VisitOMPClauseList(C);
}
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 3da669c898..8b93c441d4 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -86,6 +86,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
case OMPC_collapse:
case OMPC_private:
case OMPC_firstprivate:
+ case OMPC_lastprivate:
case OMPC_shared:
case OMPC_linear:
case OMPC_aligned:
@@ -124,6 +125,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_collapse:
case OMPC_private:
case OMPC_firstprivate:
+ case OMPC_lastprivate:
case OMPC_shared:
case OMPC_linear:
case OMPC_aligned:
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index a8b73de06d..dc79c0e795 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -258,7 +258,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
/// clause:
/// if-clause | num_threads-clause | safelen-clause | default-clause |
/// private-clause | firstprivate-clause | shared-clause | linear-clause |
-/// aligned-clause | collapse-clause
+/// aligned-clause | collapse-clause | lastprivate-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@@ -305,6 +305,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
break;
case OMPC_private:
case OMPC_firstprivate:
+ case OMPC_lastprivate:
case OMPC_shared:
case OMPC_linear:
case OMPC_aligned:
@@ -393,13 +394,15 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
Tok.getLocation());
}
-/// \brief Parsing of OpenMP clause 'private', 'firstprivate',
+/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
/// 'shared', 'copyin', or 'reduction'.
///
/// private-clause:
/// 'private' '(' list ')'
/// firstprivate-clause:
/// 'firstprivate' '(' list ')'
+/// lastprivate-clause:
+/// 'lastprivate' '(' list ')'
/// shared-clause:
/// 'shared' '(' list ')'
/// linear-clause:
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index db90657b31..8a987c3eae 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -832,6 +832,10 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
AStmt);
}
+static bool isSimdDirective(OpenMPDirectiveKind DKind) {
+ return DKind == OMPD_simd; // FIXME: || DKind == OMPD_for_simd || ...
+}
+
namespace {
/// \brief Helper class for checking canonical form of the OpenMP loops and
/// extracting iteration space of each loop in the loop nest, that will be used
@@ -1238,14 +1242,13 @@ static bool CheckOpenMPIterationSpace(OpenMPDirectiveKind DKind, Stmt *S,
// The loop iteration variable(s) in the associated for-loop(s) of a for or
// parallel for construct may be listed in a private or lastprivate clause.
DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var);
- if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_linear &&
- DVar.CKind != OMPC_threadprivate) {
+ if (isSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
+ DVar.CKind != OMPC_linear && DVar.CKind != OMPC_lastprivate &&
+ (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
// The loop iteration variable in the associated for-loop of a simd
// construct with just one associated for-loop may be listed in a linear
// clause with a constant-linear-step that is the increment of the
// associated for-loop.
- // FIXME: allow OMPC_lastprivate when it is ready.
- assert(DKind == OMPD_simd && "DSA for non-simd loop vars");
SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa)
<< getOpenMPClauseName(DVar.CKind);
if (DVar.RefExpr)
@@ -1260,6 +1263,8 @@ static bool CheckOpenMPIterationSpace(OpenMPDirectiveKind DKind, Stmt *S,
DSA.addDSA(Var, nullptr, OMPC_private);
}
+ assert(isSimdDirective(DKind) && "DSA for non-simd loop vars");
+
// Check test-expr.
HasErrors |= ISC.CheckCond(For->getCond());
@@ -1350,6 +1355,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_proc_bind:
case OMPC_private:
case OMPC_firstprivate:
+ case OMPC_lastprivate:
case OMPC_shared:
case OMPC_linear:
case OMPC_aligned:
@@ -1524,6 +1530,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_collapse:
case OMPC_private:
case OMPC_firstprivate:
+ case OMPC_lastprivate:
case OMPC_shared:
case OMPC_linear:
case OMPC_aligned:
@@ -1623,6 +1630,9 @@ Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef<Expr *> VarList,
case OMPC_firstprivate:
Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_lastprivate:
+ Res = ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_shared:
Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
@@ -1957,6 +1967,171 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
Vars);
}
+OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP lastprivate 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.3.5, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or structure
+ // element) cannot appear in a lastprivate clause.
+ DeclRefExpr *DE = dyn_cast_or_null<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.3.5, Restrictions, C/C++, p.2]
+ // A variable that appears in a lastprivate clause must not have an
+ // incomplete type or a reference type.
+ if (RequireCompleteType(ELoc, Type,
+ diag::err_omp_lastprivate_incomplete_type)) {
+ continue;
+ }
+ if (Type->isReferenceType()) {
+ Diag(ELoc, diag::err_omp_clause_ref_type_arg)
+ << getOpenMPClauseName(OMPC_lastprivate) << Type;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct]
+ // Variables with the predetermined data-sharing attributes may not be
+ // listed in data-sharing attributes clauses, except for the cases
+ // listed below.
+ // A list item that is private within a parallel region, or that appears in
+ // the reduction clause of a parallel construct, must not appear in a
+ // lastprivate clause on a worksharing construct if any of the
+ // corresponding worksharing regions ever binds to any of the corresponding
+ // parallel regions.
+ // TODO: Check implicit DSA for worksharing directives.
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+ if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate &&
+ DVar.CKind != OMPC_firstprivate &&
+ (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
+ Diag(ELoc, diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_lastprivate);
+ if (DVar.RefExpr)
+ Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ else
+ Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ continue;
+ }
+
+ // OpenMP [2.14.3.5, Restrictions, C++, p.1,2]
+ // A variable of class type (or array thereof) that appears in a lastprivate
+ // clause requires an accessible, unambiguous default constructor for the
+ // class type, unless the list item is also specified in a firstprivate
+ // clause.
+ // A variable of class type (or array thereof) that appears in a
+ // lastprivate clause requires an accessible, unambiguous copy assignment
+ // operator for the class type.
+ while (Type.getNonReferenceType()->isArrayType())
+ Type = cast<ArrayType>(Type.getNonReferenceType().getTypePtr())
+ ->getElementType();
+ CXXRecordDecl *RD = getLangOpts().CPlusPlus
+ ? Type.getNonReferenceType()->getAsCXXRecordDecl()
+ : nullptr;
+ if (RD) {
+ // FIXME: If a variable is also specified in a firstprivate clause, we may
+ // not require default constructor. This can be fixed after adding some
+ // directive allowing both firstprivate and lastprivate clauses (and this
+ // should be probably checked after all clauses are processed).
+ CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
+ PartialDiagnostic PD =
+ PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
+ if (!CD || CheckConstructorAccess(
+ ELoc, CD, InitializedEntity::InitializeTemporary(Type),
+ CD->getAccess(), PD) == AR_inaccessible ||
+ CD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_lastprivate) << 0;
+ 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, CD);
+ DiagnoseUseOfDecl(CD, ELoc);
+
+ 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_lastprivate) << 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);
+
+ CXXDestructorDecl *DD = RD->getDestructor();
+ if (DD) {
+ if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
+ DD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_lastprivate) << 4;
+ 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, DD);
+ DiagnoseUseOfDecl(DD, ELoc);
+ }
+ }
+
+ DSAStack->addDSA(VD, DE, OMPC_lastprivate);
+ Vars.push_back(DE);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ Vars);
+}
+
OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 29c9163a5e..94b2e959df 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1394,6 +1394,18 @@ public:
EndLoc);
}
+ /// \brief Build a new OpenMP 'lastprivate' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPLastprivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
/// \brief Build a new OpenMP 'shared' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -6441,6 +6453,21 @@ OMPClause *TreeTransform<Derived>::TransformOMPFirstprivateClause(
template <typename Derived>
OMPClause *
+TreeTransform<Derived>::TransformOMPLastprivateClause(OMPLastprivateClause *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().RebuildOMPLastprivateClause(
+ Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index f7031da7a3..7a4c8b0282 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1697,6 +1697,9 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_firstprivate:
C = OMPFirstprivateClause::CreateEmpty(Context, Record[Idx++]);
break;
+ case OMPC_lastprivate:
+ C = OMPLastprivateClause::CreateEmpty(Context, Record[Idx++]);
+ break;
case OMPC_shared:
C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]);
break;
@@ -1771,6 +1774,16 @@ void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
C->setVarRefs(Vars);
}
+void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *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);
+}
+
void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 2adf86978a..c5fb9b1703 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1721,6 +1721,13 @@ void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
Writer->Writer.AddStmt(VE);
}
+void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+}
+
void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
diff --git a/test/OpenMP/simd_ast_print.cpp b/test/OpenMP/simd_ast_print.cpp
index cf9788316a..4628612375 100644
--- a/test/OpenMP/simd_ast_print.cpp
+++ b/test/OpenMP/simd_ast_print.cpp
@@ -35,8 +35,8 @@ template<class T> struct S {
// CHECK: T res;
// CHECK: T val;
// CHECK: T lin = 0;
- #pragma omp simd private(val) safelen(7) linear(lin : -5)
-// CHECK-NEXT: #pragma omp simd private(val) safelen(7) linear(lin: -5)
+ #pragma omp simd private(val) safelen(7) linear(lin : -5) lastprivate(res)
+// CHECK-NEXT: #pragma omp simd private(val) safelen(7) linear(lin: -5) lastprivate(res)
for (T i = 7; i < m_a; ++i) {
val = v[i-7] + m_a;
res = val;
@@ -97,10 +97,10 @@ int main (int argc, char **argv) {
for (int i=0; i < 2; ++i)*a=2;
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: *a = 2;
-#pragma omp simd private(argc, b) collapse(2) aligned(a : 4)
+#pragma omp simd private(argc, b),lastprivate(d,f) collapse(2) aligned(a : 4)
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;}
-// CHECK-NEXT: #pragma omp simd private(argc,b) collapse(2) aligned(a: 4)
+// CHECK-NEXT: #pragma omp simd private(argc,b) lastprivate(d,f) collapse(2) aligned(a: 4)
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: for (int j = 0; j < 10; ++j) {
// CHECK-NEXT: foo();
diff --git a/test/OpenMP/simd_lastprivate_messages.cpp b/test/OpenMP/simd_lastprivate_messages.cpp
new file mode 100644
index 0000000000..f168e6287a
--- /dev/null
+++ b/test/OpenMP/simd_lastprivate_messages.cpp
@@ -0,0 +1,160 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+ S2(S2 &s2):a(s2.a) { }
+ static float S2s; // expected-note {{predetermined as shared}}
+ static const float S2sc;
+};
+const float S2::S2sc = 0; // expected-note {{predetermined as shared}}
+const S2 b;
+const S2 ba[5];
+class S3 { // expected-note {{'S3' declared here}}
+ int a;
+ S3& operator =(const S3& s3);
+public:
+ S3():a(0) { }
+ S3(S3 &s3):a(s3.a) { }
+};
+const S3 c; // expected-note {{predetermined as shared}}
+const S3 ca[5]; // expected-note {{predetermined as shared}}
+extern const int f; // expected-note {{predetermined as shared}}
+class S4 { // expected-note {{'S4' declared here}}
+ int a;
+ S4();
+ S4(const S4 &s4);
+public:
+ S4(int v):a(v) { }
+};
+class S5 { // expected-note {{'S5' declared here}}
+ int a;
+ S5():a(0) {}
+public:
+ S5(const S5 &s5):a(s5.a) { }
+ S5(int v):a(v) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template<class I, class C> int foomain(I argc, C **argv) {
+ I e(4);
+ I g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ #pragma omp simd lastprivate // expected-error {{expected '(' after 'lastprivate'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd lastprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd lastprivate () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd lastprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd lastprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd lastprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd lastprivate (argc)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd lastprivate (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd lastprivate (a, b) // expected-error {{lastprivate variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd lastprivate (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd lastprivate(e, g)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd firstprivate(i) // expected-error {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int v = 0;
+ int i;
+ #pragma omp simd lastprivate(i)
+ for (int k = 0; k < argc; ++k) { i = k; v += i; }
+ }
+ #pragma omp parallel shared(i)
+ #pragma omp parallel private(i)
+ #pragma omp simd lastprivate (j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd lastprivate(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note {{predetermined as shared}}
+ const int da[5] = { 0 }; // expected-note {{predetermined as shared}}
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ S3 m; // expected-note {{'m' defined here}}
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ #pragma omp simd lastprivate // expected-error {{expected '(' after 'lastprivate'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate () // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate (argc)
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate (S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate (a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate (argv[1]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate (2*2) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate(ba)
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate(ca) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate(da) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i) foo();
+ int xa;
+ #pragma omp simd lastprivate(xa) // OK
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate(S2::S2s) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd firstprivate (g) // expected-error {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd private(xa), lastprivate(xa) // expected-error {{private variable cannot be lastprivate}} expected-note {{defined as private}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp simd lastprivate(i)
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel private(xa)
+ #pragma omp simd lastprivate(xa) // OK: may be lastprivate
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel
+ #pragma omp simd lastprivate(j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}}
+ for (i = 0; i < argc; ++i) foo();
+ return 0;
+}
diff --git a/test/OpenMP/simd_loop_messages.cpp b/test/OpenMP/simd_loop_messages.cpp
index c960e0651a..f41390d61d 100644
--- a/test/OpenMP/simd_loop_messages.cpp
+++ b/test/OpenMP/simd_loop_messages.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -fopenmp=libiomp5 -x c++ -std=c++11 -fexceptions -fcxx-exceptions -verify %s
static int sii;
-#pragma omp threadprivate(sii)
+#pragma omp threadprivate(sii) // expected-note {{defined as threadprivate or thread local}}
int test_iteration_spaces() {
const int N = 100;
@@ -247,6 +247,7 @@ int test_iteration_spaces() {
#pragma omp parallel
{
+ // expected-error@+2 {{loop iteration variable may not be threadprivate or thread local}}
#pragma omp simd
for (sii = 0; sii < 10; sii+=1)
c[sii] = a[sii];
diff --git a/test/OpenMP/simd_misc_messages.c b/test/OpenMP/simd_misc_messages.c
index 648308e44d..20c14f6fc2 100644
--- a/test/OpenMP/simd_misc_messages.c
+++ b/test/OpenMP/simd_misc_messages.c
@@ -290,6 +290,17 @@ void test_linear()
// expected-warning@+1 {{zero linear step (x and other variables in clause should probably be const)}}
#pragma omp simd linear(x,y:0)
for (i = 0; i < 16; ++i) ;
+
+ // expected-note@+2 {{defined as linear}}
+ // expected-error@+1 {{linear variable cannot be lastprivate}}
+ #pragma omp simd linear(x) lastprivate(x)
+ for (i = 0; i < 16; ++i) ;
+
+ // expected-note@+2 {{defined as lastprivate}}
+ // expected-error@+1 {{lastprivate variable cannot be linear}}
+ #pragma omp simd lastprivate(x) linear(x)
+ for (i = 0; i < 16; ++i) ;
+
}
void test_aligned()
@@ -414,6 +425,40 @@ void test_firstprivate()
for (i = 0; i < 16; ++i) ;
}
+void test_lastprivate()
+{
+ int i;
+ // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+ // expected-error@+1 {{expected expression}}
+ #pragma omp simd lastprivate(
+ for (i = 0; i < 16; ++i) ;
+
+ // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+ // expected-error@+1 2 {{expected expression}}
+ #pragma omp simd lastprivate(,
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 2 {{expected expression}}
+ #pragma omp simd lastprivate(,)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected expression}}
+ #pragma omp simd lastprivate()
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected expression}}
+ #pragma omp simd lastprivate(int)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected variable name}}
+ #pragma omp simd lastprivate(0)
+ for (i = 0; i < 16; ++i) ;
+
+ int x, y, z;
+ #pragma omp simd lastprivate(x)
+ for (i = 0; i < 16; ++i) ;
+ #pragma omp simd lastprivate(x, y)
+ for (i = 0; i < 16; ++i) ;
+ #pragma omp simd lastprivate(x, y, z)
+ for (i = 0; i < 16; ++i) ;
+}
+
void test_loop_messages()
{
float a[100], b[100], c[100];
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index bf54fb9376..9c35631625 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -1956,6 +1956,10 @@ void OMPClauseEnqueue::VisitOMPFirstprivateClause(
const OMPFirstprivateClause *C) {
VisitOMPClauseList(C);
}
+void OMPClauseEnqueue::VisitOMPLastprivateClause(
+ const OMPLastprivateClause *C) {
+ VisitOMPClauseList(C);
+}
void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
VisitOMPClauseList(C);
}