140 changes: 139 additions & 1 deletion clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
32 changes: 32 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,19 @@ class TreeTransform {
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.
Expand Down Expand Up @@ -6434,6 +6447,25 @@ TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) {
C->getLocEnd());
}

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) {
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Serialization/ASTReaderStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Serialization/ASTWriterStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
29 changes: 21 additions & 8 deletions clang/test/OpenMP/simd_ast_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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;
Expand All @@ -58,19 +61,29 @@ 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;
}
}
};

// 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: }

Expand Down Expand Up @@ -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();
Expand Down
205 changes: 205 additions & 0 deletions clang/test/OpenMP/simd_linear_messages.cpp
Original file line number Diff line number Diff line change
@@ -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;
}

74 changes: 74 additions & 0 deletions clang/test/OpenMP/simd_misc_messages.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down