From: Alexey Bataev Date: Fri, 28 Nov 2014 07:21:40 +0000 (+0000) Subject: [OPENMP] Additional processing of 'omp atomic write' directive. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f33eba65730daec50efd6edcbb6e1bfcd921e6da;p=platform%2Fupstream%2Fllvm.git [OPENMP] Additional processing of 'omp atomic write' directive. According to OpenMP standard, Section 2.12.6, atomic Construct, '#pragma omp atomic write' is allowed to be used only for expression statements of form 'x = expr;', where x is a lvalue expression and expr is an expression with scalar type. Patch adds checks for it. llvm-svn: 222913 --- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 820f5a4..69d42f5 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7357,11 +7357,11 @@ def err_omp_parallel_reduction_in_task_firstprivate : Error< def err_omp_atomic_read_not_expression_statement : Error< "the statement for 'atomic read' must be an expression statement of form 'v = x;'," " where v and x are both lvalue expressions with scalar type">; -def note_omp_atomic_read: Note< +def note_omp_atomic_read_write: Note< "%select{expected an expression statement|expected built-in assignment operator|expected expression of scalar type|expected lvalue expression}0">; def err_omp_atomic_write_not_expression_statement : Error< "the statement for 'atomic write' must be an expression statement of form 'x = expr;'," - " where x is an l-value expression with scalar type">; + " where x is a lvalue expression with scalar type">; def err_omp_atomic_update_not_expression_statement : Error< "the statement for 'atomic%select{| update}0' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x'," " where x is an l-value expression with scalar type">; diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 09b008a..ddd47f5 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -3222,14 +3222,14 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef Clauses, // expr or subexpressions of expr. // * For forms that allow multiple occurrences of x, the number of times // that x is evaluated is unspecified. + enum { + NotAnExpression, + NotAnAssignmentOp, + NotAScalarType, + NotAnLValue, + NoError + } ErrorFound = NoError; if (AtomicKind == OMPC_read) { - enum { - NotAnExpression, - NotAnAssignmentOp, - NotAScalarType, - NotAnLValue, - NoError - } ErrorFound = NoError; SourceLocation ErrorLoc, NoteLoc; SourceRange ErrorRange, NoteRange; // If clause is read: @@ -3279,16 +3279,65 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef Clauses, if (ErrorFound != NoError) { Diag(ErrorLoc, diag::err_omp_atomic_read_not_expression_statement) << ErrorRange; - Diag(NoteLoc, diag::note_omp_atomic_read) << ErrorFound << NoteRange; + Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound + << NoteRange; return StmtError(); } else if (CurContext->isDependentContext()) V = X = nullptr; } else if (AtomicKind == OMPC_write) { - if (!isa(Body)) { - Diag(Body->getLocStart(), - diag::err_omp_atomic_write_not_expression_statement); - return StmtError(); + SourceLocation ErrorLoc, NoteLoc; + SourceRange ErrorRange, NoteRange; + // If clause is write: + // x = expr; + if (auto AtomicBody = dyn_cast(Body)) { + auto AtomicBinOp = + dyn_cast(AtomicBody->IgnoreParenImpCasts()); + if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { + X = AtomicBinOp->getLHS()->IgnoreParenImpCasts(); + E = AtomicBinOp->getRHS()->IgnoreParenImpCasts(); + if ((X->isInstantiationDependent() || X->getType()->isScalarType()) && + (E->isInstantiationDependent() || E->getType()->isScalarType())) { + if (!X->isLValue()) { + ErrorFound = NotAnLValue; + ErrorLoc = AtomicBinOp->getExprLoc(); + ErrorRange = AtomicBinOp->getSourceRange(); + NoteLoc = X->getExprLoc(); + NoteRange = X->getSourceRange(); + } + } else if (!X->isInstantiationDependent() || + !E->isInstantiationDependent()) { + auto NotScalarExpr = + (X->isInstantiationDependent() || X->getType()->isScalarType()) + ? E + : X; + ErrorFound = NotAScalarType; + ErrorLoc = AtomicBinOp->getExprLoc(); + ErrorRange = AtomicBinOp->getSourceRange(); + NoteLoc = NotScalarExpr->getExprLoc(); + NoteRange = NotScalarExpr->getSourceRange(); + } + } else { + ErrorFound = NotAnAssignmentOp; + ErrorLoc = AtomicBody->getExprLoc(); + ErrorRange = AtomicBody->getSourceRange(); + NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc() + : AtomicBody->getExprLoc(); + NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange() + : AtomicBody->getSourceRange(); + } + } else { + ErrorFound = NotAnExpression; + NoteLoc = ErrorLoc = Body->getLocStart(); + NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc); } + if (ErrorFound != NoError) { + Diag(ErrorLoc, diag::err_omp_atomic_write_not_expression_statement) + << ErrorRange; + Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound + << NoteRange; + return StmtError(); + } else if (CurContext->isDependentContext()) + E = X = nullptr; } else if (AtomicKind == OMPC_update || AtomicKind == OMPC_unknown) { if (!isa(Body)) { Diag(Body->getLocStart(), diff --git a/clang/test/OpenMP/atomic_messages.c b/clang/test/OpenMP/atomic_messages.c index d2d3308..ae490ee 100644 --- a/clang/test/OpenMP/atomic_messages.c +++ b/clang/test/OpenMP/atomic_messages.c @@ -63,3 +63,40 @@ int readS() { return a.a; } + +int writeint() { + int a = 0, b = 0; +// Test for atomic write +#pragma omp atomic write + // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}} + // expected-note@+1 {{expected an expression statement}} + ; +#pragma omp atomic write + // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}} + // expected-note@+1 {{expected built-in assignment operator}} + foo(); +#pragma omp atomic write + // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}} + // expected-note@+1 {{expected built-in assignment operator}} + a += b; +#pragma omp atomic write + a = 0; +#pragma omp atomic write + a = b; + // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'write' clause}} +#pragma omp atomic write write + a = b; + + return 0; +} + +int writeS() { + struct S a, b; + // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'write' clause}} +#pragma omp atomic write write + // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}} + // expected-note@+1 {{expected expression of scalar type}} + a = b; + + return a.a; +} diff --git a/clang/test/OpenMP/atomic_messages.cpp b/clang/test/OpenMP/atomic_messages.cpp index 3965a77..a6c07ad 100644 --- a/clang/test/OpenMP/atomic_messages.cpp +++ b/clang/test/OpenMP/atomic_messages.cpp @@ -100,11 +100,24 @@ T write() { T a, b = 0; // Test for atomic write #pragma omp atomic write - // expected-error@+1 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is an l-value expression with scalar type}} + // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}} + // expected-note@+1 {{expected an expression statement}} ; // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'write' clause}} #pragma omp atomic write write a = b; +#pragma omp atomic write + // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}} + // expected-note@+1 {{expected built-in assignment operator}} + foo(); +#pragma omp atomic write + // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}} + // expected-note@+1 {{expected built-in assignment operator}} + a += b; +#pragma omp atomic write + a = 0; +#pragma omp atomic write + a = b; return T(); } @@ -113,11 +126,24 @@ int write() { int a, b = 0; // Test for atomic write #pragma omp atomic write - // expected-error@+1 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is an l-value expression with scalar type}} + // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}} + // expected-note@+1 {{expected an expression statement}} ; // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'write' clause}} #pragma omp atomic write write a = b; +#pragma omp atomic write + // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}} + // expected-note@+1 {{expected built-in assignment operator}} + foo(); +#pragma omp atomic write + // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}} + // expected-note@+1 {{expected built-in assignment operator}} + a += b; +#pragma omp atomic write + a = 0; +#pragma omp atomic write + a = foo(); return write(); }