summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Musman <alexander.musman@gmail.com>2014-04-22 13:09:42 +0000
committerAlexander Musman <alexander.musman@gmail.com>2014-04-22 13:09:42 +0000
commitf1e95d44ac2449a5c4285a5754ac033c72b114f6 (patch)
tree21bfe345f322fffb250e3870b12509563de8d762
parentfae71a4219af4d96f5baabc98205f6909857c43e (diff)
downloadclang-f1e95d44ac2449a5c4285a5754ac033c72b114f6.tar.gz
clang-f1e95d44ac2449a5c4285a5754ac033c72b114f6.tar.bz2
clang-f1e95d44ac2449a5c4285a5754ac033c72b114f6.tar.xz
[OPENMP] parsing 'linear' clause (for directive 'omp simd')
Differential Revision: http://reviews.llvm.org/D3272 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206891 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DataRecursiveASTVisitor.h8
-rw-r--r--include/clang/AST/OpenMPClause.h85
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h7
-rw-r--r--include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td10
-rw-r--r--include/clang/Basic/OpenMPKinds.def2
-rw-r--r--include/clang/Sema/Sema.h9
-rw-r--r--lib/AST/Stmt.cpp24
-rw-r--r--lib/AST/StmtPrinter.cpp12
-rw-r--r--lib/AST/StmtProfile.cpp4
-rw-r--r--lib/Basic/OpenMPKinds.cpp2
-rw-r--r--lib/Parse/ParseOpenMP.cpp41
-rw-r--r--lib/Sema/SemaOpenMP.cpp140
-rw-r--r--lib/Sema/TreeTransform.h32
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp15
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp9
-rw-r--r--test/OpenMP/simd_ast_print.cpp29
-rw-r--r--test/OpenMP/simd_linear_messages.cpp205
-rw-r--r--test/OpenMP/simd_misc_messages.c74
-rw-r--r--tools/libclang/CIndex.cpp4
20 files changed, 693 insertions, 20 deletions
diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h
index d10258e6f9..c44a47f33e 100644
--- a/include/clang/AST/DataRecursiveASTVisitor.h
+++ b/include/clang/AST/DataRecursiveASTVisitor.h
@@ -2406,6 +2406,14 @@ bool DataRecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C)
}
template<typename Derived>
+bool
+DataRecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
+ VisitOMPClauseList(C);
+ TraverseStmt(C->getStep());
+ return true;
+}
+
+template<typename Derived>
bool DataRecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
VisitOMPClauseList(C);
return true;
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index 64b5ce4c5b..f91b491b8f 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -553,6 +553,91 @@ public:
}
};
+/// \brief This represents clause 'linear' in the '#pragma omp ...'
+/// directives.
+///
+/// \code
+/// #pragma omp simd linear(a,b : 2)
+/// \endcode
+/// In this example directive '#pragma omp simd' has clause 'linear'
+/// with variables 'a', 'b' and linear step '2'.
+///
+class OMPLinearClause : public OMPVarListClause<OMPLinearClause> {
+ friend class OMPClauseReader;
+ /// \brief Location of ':'.
+ SourceLocation ColonLoc;
+
+ /// \brief Sets the linear step for clause.
+ void setStep(Expr *Step) { *varlist_end() = Step; }
+
+ /// \brief Build 'linear' clause with given number of variables \a NumVars.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param ColonLoc Location of ':'.
+ /// \param EndLoc Ending location of the clause.
+ /// \param NumVars Number of variables.
+ ///
+ OMPLinearClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ unsigned NumVars)
+ : OMPVarListClause<OMPLinearClause>(OMPC_linear, StartLoc, LParenLoc,
+ EndLoc, NumVars),
+ ColonLoc(ColonLoc) {}
+
+ /// \brief Build an empty clause.
+ ///
+ /// \param NumVars Number of variables.
+ ///
+ explicit OMPLinearClause(unsigned NumVars)
+ : OMPVarListClause<OMPLinearClause>(OMPC_linear, SourceLocation(),
+ SourceLocation(), SourceLocation(),
+ NumVars),
+ ColonLoc(SourceLocation()) {}
+
+public:
+ /// \brief Creates clause with a list of variables \a VL and a linear step
+ /// \a Step.
+ ///
+ /// \param C AST Context.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param ColonLoc Location of ':'.
+ /// \param EndLoc Ending location of the clause.
+ /// \param VL List of references to the variables.
+ /// \param Step Linear step.
+ static OMPLinearClause *Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ ArrayRef<Expr *> VL, Expr *Step);
+
+ /// \brief Creates an empty clause with the place for \a NumVars variables.
+ ///
+ /// \param C AST context.
+ /// \param NumVars Number of variables.
+ ///
+ static OMPLinearClause *CreateEmpty(const ASTContext &C, unsigned NumVars);
+
+ /// \brief Sets the location of ':'.
+ void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; }
+ /// \brief Returns the location of '('.
+ SourceLocation getColonLoc() const { return ColonLoc; }
+
+ /// \brief Returns linear step.
+ Expr *getStep() { return *varlist_end(); }
+ /// \brief Returns linear step.
+ const Expr *getStep() const { return *varlist_end(); }
+
+ StmtRange children() {
+ return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end() + 1));
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_linear;
+ }
+};
+
/// \brief This represents clause 'copyin' in the '#pragma omp ...' directives.
///
/// \code
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 1a2ce44556..714d5a6921 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -2443,6 +2443,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
}
template<typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
+ VisitOMPClauseList(C);
+ TraverseStmt(C->getStep());
+ return true;
+}
+
+template<typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
VisitOMPClauseList(C);
return true;
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 5ab8b97ba7..0521e30ad1 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -671,6 +671,7 @@ def ASM : DiagGroup<"asm", [
// OpenMP warnings.
def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">;
+def OpenMPClauses : DiagGroup<"openmp-clauses">;
// Backend warnings.
def BackendInlineAsm : DiagGroup<"inline-asm">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 67d5e81a93..843f69d38c 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6928,6 +6928,16 @@ def err_omp_ambiguous_conversion : Error<
"enumeration type">;
def err_omp_required_access : Error<
"%0 variable must be %1">;
+def err_omp_const_variable : Error<
+ "const-qualified variable cannot be %0">;
+def err_omp_linear_incomplete_type : Error<
+ "a linear variable with incomplete type %0">;
+def err_omp_linear_expected_int_or_ptr : Error<
+ "argument of a linear clause should be of integral or pointer "
+ "type, not %0">;
+def warn_omp_linear_step_zero : Warning<
+ "zero linear step (%0 %select{|and other variables in clause }1should probably be const)">,
+ InGroup<OpenMPClauses>;
} // 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 348f40f416..479ef3df30 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(linear, OMPLinearClause)
OPENMP_CLAUSE(copyin, OMPCopyinClause)
// Clauses allowed for OpenMP directive 'parallel'.
@@ -55,6 +56,7 @@ OPENMP_PARALLEL_CLAUSE(copyin)
// FIXME: more clauses allowed for directive 'omp simd'.
OPENMP_SIMD_CLAUSE(private)
+OPENMP_SIMD_CLAUSE(linear)
OPENMP_SIMD_CLAUSE(safelen)
// Static attributes for 'default' clause.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 778d839ba4..fc6c42265a 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -7286,8 +7286,10 @@ public:
OMPClause *ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
ArrayRef<Expr *> Vars,
+ Expr *TailExpr,
SourceLocation StartLoc,
SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
SourceLocation EndLoc);
/// \brief Called on well-formed 'private' clause.
OMPClause *ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
@@ -7304,6 +7306,13 @@ public:
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
+ /// \brief Called on well-formed 'linear' clause.
+ OMPClause *ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList,
+ Expr *Step,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc);
/// \brief Called on well-formed 'copyin' clause.
OMPClause *ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index a03ef00ce7..8e937fb08b 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -1192,6 +1192,30 @@ OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPSharedClause(N);
}
+OMPLinearClause *OMPLinearClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL, Expr *Step) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * (VL.size() + 1));
+ OMPLinearClause *Clause = new (Mem)
+ OMPLinearClause(StartLoc, LParenLoc, ColonLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ Clause->setStep(Step);
+ return Clause;
+}
+
+OMPLinearClause *OMPLinearClause::CreateEmpty(const ASTContext &C,
+ unsigned NumVars) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * (NumVars + 1));
+ return new (Mem) OMPLinearClause(NumVars);
+}
+
OMPCopyinClause *OMPCopyinClause::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation LParenLoc,
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 5cfaab26e5..758db44828 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -664,6 +664,18 @@ void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) {
}
}
+void OMPClausePrinter::VisitOMPLinearClause(OMPLinearClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "linear";
+ VisitOMPClauseList(Node, '(');
+ if (Node->getStep() != 0) {
+ OS << ": ";
+ Node->getStep()->printPretty(OS, 0, Policy, 0);
+ }
+ OS << ")";
+ }
+}
+
void OMPClausePrinter::VisitOMPCopyinClause(OMPCopyinClause *Node) {
if (!Node->varlist_empty()) {
OS << "copyin";
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 07ed86a91c..1a6d1812dc 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -297,6 +297,10 @@ void OMPClauseProfiler::VisitOMPFirstprivateClause(
void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) {
VisitOMPClauseList(C);
}
+void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) {
+ VisitOMPClauseList(C);
+ Profiler->VisitStmt(C->getStep());
+}
void OMPClauseProfiler::VisitOMPCopyinClause(const OMPCopyinClause *C) {
VisitOMPClauseList(C);
}
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index ec09de1eb3..6a7f89069a 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_linear:
case OMPC_copyin:
case NUM_OPENMP_CLAUSES:
break;
@@ -110,6 +111,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
+ case OMPC_linear:
case OMPC_copyin:
case NUM_OPENMP_CLAUSES:
break;
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index f1b61077b3..bf3753fd81 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
+/// private-clause | firstprivate-clause | shared-clause | linear-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@@ -301,6 +301,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
+ case OMPC_linear:
case OMPC_copyin:
Clause = ParseOpenMPVarListClause(CKind);
break;
@@ -392,10 +393,13 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
/// 'firstprivate' '(' list ')'
/// shared-clause:
/// 'shared' '(' list ')'
+/// linear-clause:
+/// 'linear' '(' list [ ':' linear-step ] ')'
///
OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
SourceLocation LOpen = ConsumeToken();
+ SourceLocation ColonLoc = SourceLocation();
// Parse '('.
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after,
@@ -404,8 +408,10 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
SmallVector<Expr *, 5> Vars;
bool IsComma = true;
- while (IsComma || (Tok.isNot(tok::r_paren) &&
+ const bool MayHaveTail = (Kind == OMPC_linear);
+ while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
Tok.isNot(tok::annot_pragma_openmp_end))) {
+ ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
// Parse variable
ExprResult VarExpr = ParseAssignmentExpression();
if (VarExpr.isUsable()) {
@@ -416,21 +422,34 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
}
// Skip ',' if any
IsComma = Tok.is(tok::comma);
- if (IsComma) {
+ if (IsComma)
ConsumeToken();
- } else if (Tok.isNot(tok::r_paren) &&
- Tok.isNot(tok::annot_pragma_openmp_end)) {
- Diag(Tok, diag::err_omp_expected_punc)
- << getOpenMPClauseName(Kind);
- }
+ else if (Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end) &&
+ (!MayHaveTail || Tok.isNot(tok::colon)))
+ Diag(Tok, diag::err_omp_expected_punc) << getOpenMPClauseName(Kind);
+ }
+
+ // Parse ':' linear-step
+ Expr *TailExpr = 0;
+ const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
+ if (MustHaveTail) {
+ ColonLoc = Tok.getLocation();
+ ConsumeToken();
+ ExprResult Tail = ParseAssignmentExpression();
+ if (Tail.isUsable())
+ TailExpr = Tail.take();
+ else
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
}
// Parse ')'.
T.consumeClose();
- if (Vars.empty())
+ if (Vars.empty() || (MustHaveTail && !TailExpr))
return 0;
- return Actions.ActOnOpenMPVarListClause(Kind, Vars, Loc, LOpen,
- Tok.getLocation());
+ return Actions.ActOnOpenMPVarListClause(Kind, Vars, TailExpr, Loc, LOpen,
+ ColonLoc, Tok.getLocation());
}
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index b70a9c8dc2..0c592a6144 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -294,9 +294,10 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {
if (Kind != OMPD_parallel) {
if (isOpenMPLocal(D, std::next(Stack.rbegin())) && D->isLocalVarDecl() &&
(D->getStorageClass() == SC_Auto ||
- D->getStorageClass() == SC_None))
+ D->getStorageClass() == SC_None)) {
DVar.CKind = OMPC_private;
return DVar;
+ }
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
@@ -774,6 +775,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
+ case OMPC_linear:
case OMPC_copyin:
case OMPC_threadprivate:
case OMPC_unknown:
@@ -929,6 +931,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind,
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
+ case OMPC_linear:
case OMPC_copyin:
case OMPC_threadprivate:
case OMPC_unknown:
@@ -986,8 +989,10 @@ OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
ArrayRef<Expr *> VarList,
+ Expr *TailExpr,
SourceLocation StartLoc,
SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
SourceLocation EndLoc) {
OMPClause *Res = 0;
switch (Kind) {
@@ -1000,6 +1005,10 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
case OMPC_shared:
Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_linear:
+ Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
+ ColonLoc, EndLoc);
+ break;
case OMPC_copyin:
Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
@@ -1382,6 +1391,135 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
return OMPSharedClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
}
+OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end();
+ I != E; ++I) {
+ assert(*I && "NULL expr in OpenMP linear clause.");
+ if (isa<DependentScopeDeclRefExpr>(*I)) {
+ // It will be analyzed later.
+ Vars.push_back(*I);
+ continue;
+ }
+
+ // OpenMP [2.14.3.7, linear clause]
+ // A list item that appears in a linear clause is subject to the private
+ // clause semantics described in Section 2.14.3.3 on page 159 except as
+ // noted. In addition, the value of the new list item on each iteration
+ // of the associated loop(s) corresponds to the value of the original
+ // list item before entering the construct plus the logical number of
+ // the iteration times linear-step.
+
+ SourceLocation ELoc = (*I)->getExprLoc();
+ // OpenMP [2.1, C/C++]
+ // A list item is a variable name.
+ // OpenMP [2.14.3.3, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or
+ // structure element) cannot appear in a private clause.
+ DeclRefExpr *DE = dyn_cast<DeclRefExpr>(*I);
+ if (!DE || !isa<VarDecl>(DE->getDecl())) {
+ Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange();
+ continue;
+ }
+
+ VarDecl *VD = cast<VarDecl>(DE->getDecl());
+
+ // OpenMP [2.14.3.7, linear clause]
+ // A list-item cannot appear in more than one linear clause.
+ // A list-item that appears in a linear clause cannot appear in any
+ // other data-sharing attribute clause.
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+ if (DVar.RefExpr) {
+ Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_linear);
+ Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ continue;
+ }
+
+ QualType QType = VD->getType();
+ if (QType->isDependentType() || QType->isInstantiationDependentType()) {
+ // It will be analyzed later.
+ Vars.push_back(DE);
+ continue;
+ }
+
+ // A variable must not have an incomplete type or a reference type.
+ if (RequireCompleteType(ELoc, QType,
+ diag::err_omp_linear_incomplete_type)) {
+ continue;
+ }
+ if (QType->isReferenceType()) {
+ Diag(ELoc, diag::err_omp_clause_ref_type_arg)
+ << getOpenMPClauseName(OMPC_linear) << QType;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ // A list item must not be const-qualified.
+ if (QType.isConstant(Context)) {
+ Diag(ELoc, diag::err_omp_const_variable)
+ << getOpenMPClauseName(OMPC_linear);
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ // A list item must be of integral or pointer type.
+ QType = QType.getUnqualifiedType().getCanonicalType();
+ const Type *Ty = QType.getTypePtrOrNull();
+ if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
+ !Ty->isPointerType())) {
+ Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << QType;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ DSAStack->addDSA(VD, DE, OMPC_linear);
+ Vars.push_back(DE);
+ }
+
+ if (Vars.empty())
+ return 0;
+
+ Expr *StepExpr = Step;
+ if (Step && !Step->isValueDependent() && !Step->isTypeDependent() &&
+ !Step->isInstantiationDependent() &&
+ !Step->containsUnexpandedParameterPack()) {
+ SourceLocation StepLoc = Step->getLocStart();
+ ExprResult Val = PerformImplicitIntegerConversion(StepLoc, Step);
+ if (Val.isInvalid())
+ return 0;
+ StepExpr = Val.take();
+
+ // Warn about zero linear step (it would be probably better specified as
+ // making corresponding variables 'const').
+ llvm::APSInt Result;
+ if (StepExpr->isIntegerConstantExpr(Result, Context) &&
+ !Result.isNegative() && !Result.isStrictlyPositive())
+ Diag(StepLoc, diag::warn_omp_linear_step_zero) << Vars[0]
+ << (Vars.size() > 1);
+ }
+
+ return OMPLinearClause::Create(Context, StartLoc, LParenLoc, ColonLoc, EndLoc,
+ Vars, StepExpr);
+}
+
OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 22913104d7..f113891882 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1382,6 +1382,19 @@ public:
EndLoc);
}
+ /// \brief Build a new OpenMP 'linear' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPLinearClause(VarList, Step, StartLoc, LParenLoc,
+ ColonLoc, EndLoc);
+ }
+
/// \brief Build a new OpenMP 'copyin' clause.
///
/// By default, performs semantic analysis to build the new statement.
@@ -6436,6 +6449,25 @@ TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) {
template<typename Derived>
OMPClause *
+TreeTransform<Derived>::TransformOMPLinearClause(OMPLinearClause *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 0;
+ Vars.push_back(EVar.take());
+ }
+ ExprResult Step = getDerived().TransformExpr(C->getStep());
+ if (Step.isInvalid())
+ return 0;
+ return getDerived().RebuildOMPLinearClause(
+ Vars, Step.take(), C->getLocStart(), C->getLParenLoc(), C->getColonLoc(),
+ C->getLocEnd());
+}
+
+template<typename Derived>
+OMPClause *
TreeTransform<Derived>::TransformOMPCopyinClause(OMPCopyinClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 9a201d0f69..da652ff8e3 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_linear:
+ C = OMPLinearClause::CreateEmpty(Context, Record[Idx++]);
+ break;
case OMPC_copyin:
C = OMPCopyinClause::CreateEmpty(Context, Record[Idx++]);
break;
@@ -1755,6 +1758,18 @@ void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) {
C->setVarRefs(Vars);
}
+void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setColonLoc(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);
+ C->setStep(Reader->Reader.ReadSubExpr());
+}
+
void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *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 bbbd3377cb..958620636e 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1716,6 +1716,15 @@ void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) {
Writer->Writer.AddStmt(VE);
}
+void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+ Writer->Writer.AddStmt(C->getStep());
+}
+
void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *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 4b1fccb92f..5e8cbecfbc 100644
--- a/test/OpenMP/simd_ast_print.cpp
+++ b/test/OpenMP/simd_ast_print.cpp
@@ -14,8 +14,8 @@ template<class T, class N> T reduct(T* arr, N num) {
N myind;
T sum = (T)0;
// CHECK: T sum = (T)0;
-#pragma omp simd private(myind, g_ind)
-// CHECK-NEXT: #pragma omp simd private(myind,g_ind)
+#pragma omp simd private(myind, g_ind), linear(ind)
+// CHECK-NEXT: #pragma omp simd private(myind,g_ind) linear(ind)
for (i = 0; i < num; ++i) {
myind = ind;
T cur = arr[myind];
@@ -31,13 +31,16 @@ template<class T> struct S {
T result(T *v) const {
T res;
T val;
+ T lin = 0;
// CHECK: T res;
// CHECK: T val;
- #pragma omp simd private(val) safelen(7)
-// CHECK-NEXT: #pragma omp simd private(val) safelen(7)
+// 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)
for (T i = 7; i < m_a; ++i) {
val = v[i-7] + m_a;
res = val;
+ lin -= 5;
}
const T clen = 3;
// CHECK: T clen = 3;
@@ -58,9 +61,14 @@ template<class T> struct S {
template<int LEN> struct S2 {
static void func(int n, float *a, float *b, float *c) {
-#pragma omp simd safelen(LEN)
+ int k1 = 0, k2 = 0;
+#pragma omp simd safelen(LEN) linear(k1,k2:LEN)
for(int i = 0; i < n; i++) {
c[i] = a[i] + b[i];
+ c[k1] = a[k1] + b[k1];
+ c[k2] = a[k2] + b[k2];
+ k1 = k1 + LEN;
+ k2 = k2 + LEN;
}
}
};
@@ -68,9 +76,14 @@ template<int LEN> struct S2 {
// S2<4>::func is called below in main.
// CHECK: template <int LEN = 4> struct S2 {
// CHECK-NEXT: static void func(int n, float *a, float *b, float *c) {
-// CHECK-NEXT: #pragma omp simd safelen(4)
+// CHECK-NEXT: int k1 = 0, k2 = 0;
+// CHECK-NEXT: #pragma omp simd safelen(4) linear(k1,k2: 4)
// CHECK-NEXT: for (int i = 0; i < n; i++) {
// CHECK-NEXT: c[i] = a[i] + b[i];
+// CHECK-NEXT: c[k1] = a[k1] + b[k1];
+// CHECK-NEXT: c[k2] = a[k2] + b[k2];
+// CHECK-NEXT: k1 = k1 + 4;
+// CHECK-NEXT: k2 = k2 + 4;
// CHECK-NEXT: }
// CHECK-NEXT: }
@@ -99,8 +112,8 @@ int main (int argc, char **argv) {
// CHECK-NEXT: foo();
const int CLEN = 4;
// CHECK-NEXT: const int CLEN = 4;
- #pragma omp simd safelen(CLEN)
-// CHECK-NEXT: #pragma omp simd safelen(CLEN)
+ #pragma omp simd linear(a:CLEN) safelen(CLEN)
+// CHECK-NEXT: #pragma omp simd linear(a: CLEN) safelen(CLEN)
for (int i = 0; i < 10; ++i)foo();
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: foo();
diff --git a/test/OpenMP/simd_linear_messages.cpp b/test/OpenMP/simd_linear_messages.cpp
new file mode 100644
index 0000000000..e90bc69444
--- /dev/null
+++ b/test/OpenMP/simd_linear_messages.cpp
@@ -0,0 +1,205 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+namespace X {
+ int x;
+};
+
+struct B {
+ static int ib; // expected-note {{'B::ib' declared here}}
+ static int bfoo() { return 8; }
+};
+
+int bfoo() { return 4; }
+
+int z;
+const int C1 = 1;
+const int C2 = 2;
+void test_linear_colons()
+{
+ int B = 0;
+ #pragma omp simd linear(B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'}}
+ #pragma omp simd linear(B::ib:B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{use of undeclared identifier 'ib'; did you mean 'B::ib'}}
+ #pragma omp simd linear(B:ib)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'?}}
+ #pragma omp simd linear(z:B:ib)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp simd linear(B:B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp simd linear(X::x : ::z)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp simd linear(B,::z, X::x)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp simd linear(::z)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{expected variable name}}
+ #pragma omp simd linear(B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp simd linear(B::ib,B:C1+C2)
+ for (int i = 0; i < 10; ++i) ;
+}
+
+template<int L, class T, class N> T test_template(T* arr, N num) {
+ N i;
+ T sum = (T)0;
+ T ind2 = - num * L; // expected-note {{'ind2' defined here}}
+ // expected-error@+1 {{argument of a linear clause should be of integral or pointer type}}
+#pragma omp simd linear(ind2:L)
+ for (i = 0; i < num; ++i) {
+ T cur = arr[ind2];
+ ind2 += L;
+ sum += cur;
+ }
+}
+
+template<int LEN> int test_warn() {
+ int ind2 = 0;
+ // expected-warning@+1 {{zero linear step (ind2 should probably be const)}}
+ #pragma omp simd linear(ind2:LEN)
+ for (int i = 0; i < 100; i++) {
+ ind2 += LEN;
+ }
+ return ind2;
+}
+
+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) { }
+};
+const S2 b; // expected-note 2 {{'b' defined here}}
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+};
+const S3 ca[5];
+class S4 {
+ int a;
+ S4();
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {}
+public:
+ 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 linear // expected-error {{expected '(' after 'linear'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc : 5)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{linear variable with incomplete type 'S1'}}
+ // expected-error@+1 {{const-qualified variable cannot be linear}}
+ #pragma omp simd linear (a, b:B::ib)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear(e, g)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear(h) // expected-error {{threadprivate or thread local variable cannot be linear}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int v = 0;
+ int i;
+ #pragma omp simd linear(v:i)
+ for (int k = 0; k < argc; ++k) { i = k; v += i; }
+ }
+ #pragma omp simd linear(j) // expected-error {{arguments of OpenMP clause 'linear' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k) ++k;
+ int v = 0;
+ #pragma omp simd linear(v:j)
+ for (int k = 0; k < argc; ++k) { ++k; v += j; }
+ #pragma omp simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ double darr[100];
+ // expected-note@+1 {{in instantiation of function template specialization 'test_template<-4, double, int>' requested here}}
+ test_template<-4>(darr, 4);
+ // expected-note@+1 {{in instantiation of function template specialization 'test_warn<0>' requested here}}
+ test_warn<0>();
+
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ #pragma omp simd linear // expected-error {{expected '(' after 'linear'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{linear variable with incomplete type 'S1'}}
+ // expected-error@+1 {{const-qualified variable cannot be linear}}
+ #pragma omp simd linear (a, b)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{argument of a linear clause should be of integral or pointer type, not 'S4'}}
+ // expected-error@+1 {{argument of a linear clause should be of integral or pointer type, not 'S5'}}
+ #pragma omp simd linear(e, g)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear(h) // expected-error {{threadprivate or thread local variable cannot be linear}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int i;
+ #pragma omp simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear(i : 4)
+ for (int k = 0; k < argc; ++k) { ++k; i += 4; }
+ }
+ #pragma omp simd linear(j) // expected-error {{arguments of OpenMP clause 'linear' cannot be of reference type 'int &'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+
+ foomain<int,char>(argc,argv);
+ return 0;
+}
+
diff --git a/test/OpenMP/simd_misc_messages.c b/test/OpenMP/simd_misc_messages.c
index 0800d22988..6e2f81cee1 100644
--- a/test/OpenMP/simd_misc_messages.c
+++ b/test/OpenMP/simd_misc_messages.c
@@ -146,6 +146,80 @@ void test_safelen()
for (i = 0; i < 16; ++i);
}
+void test_linear()
+{
+ int i;
+ // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd linear(
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+2 {{expected expression}}
+ // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd linear(,
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+2 {{expected expression}}
+ // expected-error@+1 {{expected expression}}
+ #pragma omp simd linear(,)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected expression}}
+ #pragma omp simd linear()
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected expression}}
+ #pragma omp simd linear(int)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected variable name}}
+ #pragma omp simd linear(0)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{use of undeclared identifier 'x'}}
+ #pragma omp simd linear(x)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+2 {{use of undeclared identifier 'x'}}
+ // expected-error@+1 {{use of undeclared identifier 'y'}}
+ #pragma omp simd linear(x, y)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+3 {{use of undeclared identifier 'x'}}
+ // expected-error@+2 {{use of undeclared identifier 'y'}}
+ // expected-error@+1 {{use of undeclared identifier 'z'}}
+ #pragma omp simd linear(x, y, z)
+ for (i = 0; i < 16; ++i) ;
+
+ int x, y;
+ // expected-error@+1 {{expected expression}}
+ #pragma omp simd linear(x:)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd linear(x:,)
+ for (i = 0; i < 16; ++i) ;
+ #pragma omp simd linear(x:1)
+ for (i = 0; i < 16; ++i) ;
+ #pragma omp simd linear(x:2*2)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd linear(x:1,y)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd linear(x:1,y,z:1)
+ for (i = 0; i < 16; ++i) ;
+
+ // expected-note@+2 {{defined as linear}}
+ // expected-error@+1 {{linear variable cannot be linear}}
+ #pragma omp simd linear(x) linear(x)
+ for (i = 0; i < 16; ++i) ;
+
+ // expected-note@+2 {{defined as private}}
+ // expected-error@+1 {{private variable cannot be linear}}
+ #pragma omp simd private(x) linear(x)
+ for (i = 0; i < 16; ++i) ;
+
+ // expected-note@+2 {{defined as linear}}
+ // expected-error@+1 {{linear variable cannot be private}}
+ #pragma omp simd linear(x) private(x)
+ for (i = 0; i < 16; ++i) ;
+
+ // 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) ;
+}
+
void test_private()
{
int i;
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 50e7c68204..1290c72067 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -1954,6 +1954,10 @@ void OMPClauseEnqueue::VisitOMPFirstprivateClause(
void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
VisitOMPClauseList(C);
}
+void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause *C) {
+ VisitOMPClauseList(C);
+ Visitor->AddStmt(C->getStep());
+}
void OMPClauseEnqueue::VisitOMPCopyinClause(const OMPCopyinClause *C) {
VisitOMPClauseList(C);
}