}
};
+/// This represents 'acq_rel' clause in the '#pragma omp atomic|flush'
+/// directives.
+///
+/// \code
+/// #pragma omp flush acq_rel
+/// \endcode
+/// In this example directive '#pragma omp flush' has 'acq_rel' clause.
+class OMPAcqRelClause : public OMPClause {
+public:
+ /// Build 'ack_rel' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ OMPAcqRelClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_acq_rel, StartLoc, EndLoc) {}
+
+ /// Build an empty clause.
+ OMPAcqRelClause()
+ : OMPClause(OMPC_acq_rel, SourceLocation(), SourceLocation()) {}
+
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+
+ child_range used_children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+ const_child_range used_children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_acq_rel;
+ }
+};
+
/// This represents clause 'private' in the '#pragma omp ...' directives.
///
/// \code
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPAcqRelClause(OMPAcqRelClause *) {
+ return true;
+}
+
+template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPThreadsClause(OMPThreadsClause *) {
return true;
}
"%select{expected assignment expression|expected compound statement|expected exactly two expression statements|expected in right hand side of the first expression}0">;
def err_omp_atomic_several_clauses : Error<
"directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause">;
+def err_omp_atomic_several_mem_order_clauses : Error<
+ "directive '#pragma omp atomic' cannot contain more than one 'seq_cst' or 'acq_rel' clause">;
def note_omp_atomic_previous_clause : Note<
"'%0' clause used here">;
def err_omp_target_contains_not_only_teams : Error<
def err_omp_lastprivate_conditional_non_scalar : Error<
"expected list item of scalar type in 'lastprivate' clause with 'conditional' modifier"
>;
+def err_omp_flush_order_clause_and_list : Error<
+ "'flush' directive with memory order clause '%0' cannot have the list">;
+def note_omp_flush_order_clause_here : Note<
+ "memory order clause '%0' is specified here">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
#ifndef OPENMP_ORDER_KIND
#define OPENMP_ORDER_KIND(Name)
#endif
+#ifndef OPENMP_FLUSH_CLAUSE
+#define OPENMP_FLUSH_CLAUSE(Name)
+#endif
// OpenMP context selector sets.
OPENMP_CONTEXT_SELECTOR_SET(implementation)
OPENMP_CLAUSE(update, OMPUpdateClause)
OPENMP_CLAUSE(capture, OMPCaptureClause)
OPENMP_CLAUSE(seq_cst, OMPSeqCstClause)
+OPENMP_CLAUSE(acq_rel, OMPAcqRelClause)
OPENMP_CLAUSE(depend, OMPDependClause)
OPENMP_CLAUSE(device, OMPDeviceClause)
OPENMP_CLAUSE(threads, OMPThreadsClause)
OPENMP_ATOMIC_CLAUSE(update)
OPENMP_ATOMIC_CLAUSE(capture)
OPENMP_ATOMIC_CLAUSE(seq_cst)
+OPENMP_ATOMIC_CLAUSE(acq_rel)
// Clauses allowed for OpenMP directive 'target'.
OPENMP_TARGET_CLAUSE(if)
// Type of the 'order' clause.
OPENMP_ORDER_KIND(concurrent)
+// Clauses allowed for OpenMP directive 'flush'.
+OPENMP_FLUSH_CLAUSE(acq_rel)
+
+#undef OPENMP_FLUSH_CLAUSE
#undef OPENMP_ORDER_KIND
#undef OPENMP_LASTPRIVATE_KIND
#undef OPENMP_CONTEXT_SELECTOR
/// Called on well-formed 'seq_cst' clause.
OMPClause *ActOnOpenMPSeqCstClause(SourceLocation StartLoc,
SourceLocation EndLoc);
+ /// Called on well-formed 'acq_rel' clause.
+ OMPClause *ActOnOpenMPAcqRelClause(SourceLocation StartLoc,
+ SourceLocation EndLoc);
/// Called on well-formed 'threads' clause.
OMPClause *ActOnOpenMPThreadsClause(SourceLocation StartLoc,
SourceLocation EndLoc);
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
case OMPC_depend:
case OMPC_device:
case OMPC_threads:
OS << "seq_cst";
}
+void OMPClausePrinter::VisitOMPAcqRelClause(OMPAcqRelClause *) {
+ OS << "acq_rel";
+}
+
void OMPClausePrinter::VisitOMPThreadsClause(OMPThreadsClause *) {
OS << "threads";
}
void OMPClauseProfiler::VisitOMPSeqCstClause(const OMPSeqCstClause *) {}
+void OMPClauseProfiler::VisitOMPAcqRelClause(const OMPAcqRelClause *) {}
+
void OMPClauseProfiler::VisitOMPThreadsClause(const OMPThreadsClause *) {}
void OMPClauseProfiler::VisitOMPSIMDClause(const OMPSIMDClause *) {}
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
}
break;
case OMPD_flush:
- return CKind == OMPC_flush;
+ if (CKind == OMPC_flush)
+ return true;
+ if (OpenMPVersion < 50)
+ return false;
+ switch (CKind) {
+#define OPENMP_FLUSH_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
break;
case OMPD_atomic:
+ if (OpenMPVersion < 50 && CKind == OMPC_acq_rel)
+ return false;
switch (CKind) {
#define OPENMP_ATOMIC_CLAUSE(Name) \
case OMPC_##Name: \
#include "clang/AST/OpenMPClause.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
using namespace clang;
case OMPC_collapse:
case OMPC_default:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
case OMPC_shared:
case OMPC_linear:
case OMPC_aligned:
bool IsSeqCst = S.getSingleClause<OMPSeqCstClause>();
OpenMPClauseKind Kind = OMPC_unknown;
for (const OMPClause *C : S.clauses()) {
- // Find first clause (skip seq_cst clause, if it is first).
- if (C->getClauseKind() != OMPC_seq_cst) {
+ // Find first clause (skip seq_cst|acq_rel clause, if it is first).
+ if (C->getClauseKind() != OMPC_seq_cst &&
+ C->getClauseKind() != OMPC_acq_rel) {
Kind = C->getClauseKind();
break;
}
DeclarationNameInfo DirName;
StmtResult Directive = StmtError();
bool HasAssociatedStatement = true;
- bool FlushHasClause = false;
switch (DKind) {
case OMPD_threadprivate: {
break;
}
case OMPD_flush:
- if (PP.LookAhead(0).is(tok::l_paren)) {
- FlushHasClause = true;
- // Push copy of the current token back to stream to properly parse
- // pseudo-clause OMPFlushClause.
- PP.EnterToken(Tok, /*IsReinject*/ true);
- }
- LLVM_FALLTHROUGH;
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
case OMPD_target_teams_distribute_simd: {
+ // Special processing for flush clause.
+ Token FlushTok;
+ if (DKind == OMPD_flush)
+ FlushTok = Tok;
ConsumeToken();
// Parse directive name of the 'critical' directive if any.
if (DKind == OMPD_critical) {
Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc);
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ bool FlushHasClause = false;
+ if (DKind == OMPD_flush && Tok.is(tok::l_paren)) {
+ FlushHasClause = true;
+ // Push copy of the current token back to stream to properly parse
+ // pseudo-clause OMPFlushClause.
+ PP.EnterToken(Tok, /*IsReinject*/ true);
+ PP.EnterToken(FlushTok, /*IsReinject*/ true);
+ ConsumeAnyToken();
+ }
OpenMPClauseKind CKind =
Tok.isAnnotation()
? OMPC_unknown
/// thread_limit-clause | priority-clause | grainsize-clause |
/// nogroup-clause | num_tasks-clause | hint-clause | to-clause |
/// from-clause | is_device_ptr-clause | task_reduction-clause |
-/// in_reduction-clause | allocator-clause | allocate-clause
+/// in_reduction-clause | allocator-clause | allocate-clause |
+/// acq_rel-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
case OMPC_threads:
case OMPC_simd:
case OMPC_nogroup:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc) {
- assert(Clauses.size() <= 1 && "Extra clauses in flush directive");
+ OMPFlushClause *FC = nullptr;
+ OMPClause *OrderClause = nullptr;
+ for (OMPClause *C : Clauses) {
+ if (C->getClauseKind() == OMPC_flush)
+ FC = cast<OMPFlushClause>(C);
+ else
+ OrderClause = C;
+ }
+ if (FC && OrderClause) {
+ Diag(FC->getLParenLoc(), diag::err_omp_flush_order_clause_and_list)
+ << getOpenMPClauseName(OrderClause->getClauseKind());
+ Diag(OrderClause->getBeginLoc(), diag::note_omp_flush_order_clause_here)
+ << getOpenMPClauseName(OrderClause->getClauseKind());
+ return StmtError();
+ }
return OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses);
}
// longjmp() and throw() must not violate the entry/exit criteria.
OpenMPClauseKind AtomicKind = OMPC_unknown;
SourceLocation AtomicKindLoc;
+ OpenMPClauseKind MemOrderKind = OMPC_unknown;
+ SourceLocation MemOrderLoc;
for (const OMPClause *C : Clauses) {
if (C->getClauseKind() == OMPC_read || C->getClauseKind() == OMPC_write ||
C->getClauseKind() == OMPC_update ||
AtomicKindLoc = C->getBeginLoc();
}
}
+ if (C->getClauseKind() == OMPC_seq_cst ||
+ C->getClauseKind() == OMPC_acq_rel) {
+ if (MemOrderKind != OMPC_unknown) {
+ Diag(C->getBeginLoc(), diag::err_omp_atomic_several_mem_order_clauses)
+ << SourceRange(C->getBeginLoc(), C->getEndLoc());
+ Diag(MemOrderLoc, diag::note_omp_atomic_previous_clause)
+ << getOpenMPClauseName(MemOrderKind);
+ } else {
+ MemOrderKind = C->getClauseKind();
+ MemOrderLoc = C->getBeginLoc();
+ }
+ }
}
Stmt *Body = CS->getCapturedStmt();
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
case OMPC_depend:
case OMPC_device:
case OMPC_threads:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
case OMPC_depend:
case OMPC_device:
case OMPC_threads:
case OMPC_seq_cst:
Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc);
break;
+ case OMPC_acq_rel:
+ Res = ActOnOpenMPAcqRelClause(StartLoc, EndLoc);
+ break;
case OMPC_threads:
Res = ActOnOpenMPThreadsClause(StartLoc, EndLoc);
break;
return new (Context) OMPSeqCstClause(StartLoc, EndLoc);
}
+OMPClause *Sema::ActOnOpenMPAcqRelClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPAcqRelClause(StartLoc, EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPThreadsClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPThreadsClause(StartLoc, EndLoc);
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
template <typename Derived>
OMPClause *
+TreeTransform<Derived>::TransformOMPAcqRelClause(OMPAcqRelClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
TreeTransform<Derived>::TransformOMPThreadsClause(OMPThreadsClause *C) {
// No need to rebuild this clause, no template-dependent parameters.
return C;
case OMPC_seq_cst:
C = new (Context) OMPSeqCstClause();
break;
+ case OMPC_acq_rel:
+ C = new (Context) OMPAcqRelClause();
+ break;
case OMPC_threads:
C = new (Context) OMPThreadsClause();
break;
void OMPClauseReader::VisitOMPSeqCstClause(OMPSeqCstClause *) {}
+void OMPClauseReader::VisitOMPAcqRelClause(OMPAcqRelClause *) {}
+
void OMPClauseReader::VisitOMPThreadsClause(OMPThreadsClause *) {}
void OMPClauseReader::VisitOMPSIMDClause(OMPSIMDClause *) {}
void OMPClauseWriter::VisitOMPSeqCstClause(OMPSeqCstClause *) {}
+void OMPClauseWriter::VisitOMPAcqRelClause(OMPAcqRelClause *) {}
+
void OMPClauseWriter::VisitOMPThreadsClause(OMPThreadsClause *) {}
void OMPClauseWriter::VisitOMPSIMDClause(OMPSIMDClause *) {}
-// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
-// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
-// RUN: %clang_cc1 -verify -fopenmp-simd -ast-print %s | FileCheck %s
-// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp-simd -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
// expected-no-diagnostics
#ifndef HEADER
a = b;
b++;
}
+#pragma omp atomic acq_rel
+ a++;
+#pragma omp atomic read acq_rel
+ a = argc;
+#pragma omp atomic acq_rel write
+ a = argc + argc;
+#pragma omp atomic update acq_rel
+ a = a + argc;
+#pragma omp atomic acq_rel capture
+ a = b++;
+#pragma omp atomic capture acq_rel
+ {
+ a = b;
+ b++;
+ }
return T();
}
// CHECK-NEXT: a = b;
// CHECK-NEXT: b++;
// CHECK-NEXT: }
+// CHECK-NEXT: #pragma omp atomic acq_rel
+// CHECK-NEXT: a++;
+// CHECK-NEXT: #pragma omp atomic read acq_rel
+// CHECK-NEXT: a = argc;
+// CHECK-NEXT: #pragma omp atomic acq_rel write
+// CHECK-NEXT: a = argc + argc;
+// CHECK-NEXT: #pragma omp atomic update acq_rel
+// CHECK-NEXT: a = a + argc;
+// CHECK-NEXT: #pragma omp atomic acq_rel capture
+// CHECK-NEXT: a = b++;
+// CHECK-NEXT: #pragma omp atomic capture acq_rel
+// CHECK-NEXT: {
+// CHECK-NEXT: a = b;
+// CHECK-NEXT: b++;
+// CHECK-NEXT: }
// CHECK: int a = int();
// CHECK-NEXT: #pragma omp atomic
// CHECK-NEXT: a++;
// CHECK-NEXT: a = b;
// CHECK-NEXT: b++;
// CHECK-NEXT: }
+// CHECK-NEXT: #pragma omp atomic acq_rel
+// CHECK-NEXT: a++;
+// CHECK-NEXT: #pragma omp atomic read acq_rel
+// CHECK-NEXT: a = argc;
+// CHECK-NEXT: #pragma omp atomic acq_rel write
+// CHECK-NEXT: a = argc + argc;
+// CHECK-NEXT: #pragma omp atomic update acq_rel
+// CHECK-NEXT: a = a + argc;
+// CHECK-NEXT: #pragma omp atomic acq_rel capture
+// CHECK-NEXT: a = b++;
+// CHECK-NEXT: #pragma omp atomic capture acq_rel
+// CHECK-NEXT: {
+// CHECK-NEXT: a = b;
+// CHECK-NEXT: b++;
+// CHECK-NEXT: }
int main(int argc, char **argv) {
int b = 0;
a = b;
b++;
}
+#pragma omp atomic acq_rel
+ a++;
+#pragma omp atomic read acq_rel
+ a = argc;
+#pragma omp atomic acq_rel write
+ a = argc + argc;
+#pragma omp atomic update acq_rel
+ a = a + argc;
+#pragma omp atomic acq_rel capture
+ a = b++;
+#pragma omp atomic capture acq_rel
+ {
+ a = b;
+ b++;
+ }
// CHECK-NEXT: #pragma omp atomic
// CHECK-NEXT: a++;
// CHECK-NEXT: #pragma omp atomic read
// CHECK-NEXT: a = b;
// CHECK-NEXT: b++;
// CHECK-NEXT: }
+ // CHECK-NEXT: #pragma omp atomic acq_rel
+ // CHECK-NEXT: a++;
+ // CHECK-NEXT: #pragma omp atomic read acq_rel
+ // CHECK-NEXT: a = argc;
+ // CHECK-NEXT: #pragma omp atomic acq_rel write
+ // CHECK-NEXT: a = argc + argc;
+ // CHECK-NEXT: #pragma omp atomic update acq_rel
+ // CHECK-NEXT: a = a + argc;
+ // CHECK-NEXT: #pragma omp atomic acq_rel capture
+ // CHECK-NEXT: a = b++;
+ // CHECK-NEXT: #pragma omp atomic capture acq_rel
+ // CHECK-NEXT: {
+ // CHECK-NEXT: a = b;
+ // CHECK-NEXT: b++;
+ // CHECK-NEXT: }
return foo(a);
}
-// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -fopenmp-version=45 -ferror-limit 150 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -ferror-limit 150 %s -Wuninitialized
-// RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -fopenmp-version=45 -ferror-limit 150 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -ferror-limit 150 %s -Wuninitialized
int foo() {
L1:
}
template <class T>
+T acq_rel() {
+ T a = 0, b = 0;
+// omp45-error@+1 {{unexpected OpenMP clause 'acq_rel' in directive '#pragma omp atomic'}}
+#pragma omp atomic acq_rel
+ // expected-error@+2 {{the statement for 'atomic' 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}}
+ // expected-note@+1 {{expected an expression statement}}
+ ;
+// omp50-error@+1 2 {{directive '#pragma omp atomic' cannot contain more than one 'seq_cst' or 'acq_rel' clause}} omp50-note@+1 2 {{'acq_rel' clause used here}} omp45-error@+1 {{unexpected OpenMP clause 'acq_rel' in directive '#pragma omp atomic'}}
+#pragma omp atomic acq_rel seq_cst
+ a += b;
+
+// omp45-error@+1 {{unexpected OpenMP clause 'acq_rel' in directive '#pragma omp atomic'}}
+#pragma omp atomic update acq_rel
+ // expected-error@+2 {{the statement for 'atomic update' 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}}
+ // expected-note@+1 {{expected an expression statement}}
+ ;
+
+ return T();
+}
+
+int acq_rel() {
+ int a = 0, b = 0;
+// Test for atomic acq_rel
+// omp45-error@+1 {{unexpected OpenMP clause 'acq_rel' in directive '#pragma omp atomic'}}
+#pragma omp atomic acq_rel
+ // expected-error@+2 {{the statement for 'atomic' 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}}
+ // expected-note@+1 {{expected an expression statement}}
+ ;
+// omp50-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'seq_cst' or 'acq_rel' clause}} omp50-note@+1 {{'seq_cst' clause used here}} omp45-error@+1 {{unexpected OpenMP clause 'acq_rel' in directive '#pragma omp atomic'}}
+#pragma omp atomic seq_cst acq_rel
+ a += b;
+
+// omp45-error@+1 {{unexpected OpenMP clause 'acq_rel' in directive '#pragma omp atomic'}}
+#pragma omp atomic update acq_rel
+ // expected-error@+2 {{the statement for 'atomic update' 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}}
+ // expected-note@+1 {{expected an expression statement}}
+ ;
+
+ return acq_rel<int>(); // omp50-note {{in instantiation of function template specialization 'acq_rel<int>' requested here}}
+}
+
+template <class T>
T mixed() {
T a, b = T();
// expected-error@+2 2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}}
-// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
-// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
-// RUN: %clang_cc1 -verify -fopenmp-simd -ast-print %s | FileCheck %s
-// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp-simd -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
// expected-no-diagnostics
#ifndef HEADER
T tmain(T argc) {
static T a;
#pragma omp flush
+#pragma omp flush acq_rel
#pragma omp flush(a)
return a + argc;
}
// CHECK: static T a;
// CHECK-NEXT: #pragma omp flush{{$}}
+// CHECK-NEXT: #pragma omp flush acq_rel{{$}}
// CHECK-NEXT: #pragma omp flush (a)
// CHECK: static int a;
// CHECK-NEXT: #pragma omp flush
+// CHECK-NEXT: #pragma omp flush acq_rel{{$}}
// CHECK-NEXT: #pragma omp flush (a)
// CHECK: static char a;
// CHECK-NEXT: #pragma omp flush
+// CHECK-NEXT: #pragma omp flush acq_rel{{$}}
// CHECK-NEXT: #pragma omp flush (a)
int main(int argc, char **argv) {
static int a;
// CHECK: static int a;
#pragma omp flush
+#pragma omp flush acq_rel
#pragma omp flush(a)
// CHECK-NEXT: #pragma omp flush
+// CHECK-NEXT: #pragma omp flush acq_rel
// CHECK-NEXT: #pragma omp flush (a)
return tmain(argc) + tmain(argv[0][0]) + a;
}
-// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -fopenmp-version=45 -ferror-limit 100 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -ferror-limit 100 %s -Wuninitialized
-// RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -fopenmp-version=45 -ferror-limit 100 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -ferror-limit 100 %s -Wuninitialized
struct S1 { // expected-note 2 {{declared here}}
int a;
#pragma omp flush(argc) flush(argc) // expected-warning {{extra tokens at the end of '#pragma omp flush' are ignored}}
#pragma omp parallel flush(argc) // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
;
+#pragma omp flush seq_cst // expected-error {{unexpected OpenMP clause 'seq_cst' in directive '#pragma omp flush'}}
+#pragma omp flush acq_rel // omp45-error {{unexpected OpenMP clause 'acq_rel' in directive '#pragma omp flush'}}
+#pragma omp flush acq_rel (argc) // omp45-error {{unexpected OpenMP clause 'acq_rel' in directive '#pragma omp flush'}} omp50-error {{'flush' directive with memory order clause 'acq_rel' cannot have the list}} omp50-note {{memory order clause 'acq_rel' is specified here}}
+#pragma omp flush(argc) acq_rel // omp45-error {{unexpected OpenMP clause 'acq_rel' in directive '#pragma omp flush'}} omp50-error {{'flush' directive with memory order clause 'acq_rel' cannot have the list}} omp50-note {{memory order clause 'acq_rel' is specified here}}
return tmain(argc);
}
void OMPClauseEnqueue::VisitOMPSeqCstClause(const OMPSeqCstClause *) {}
+void OMPClauseEnqueue::VisitOMPAcqRelClause(const OMPAcqRelClause *) {}
+
void OMPClauseEnqueue::VisitOMPThreadsClause(const OMPThreadsClause *) {}
void OMPClauseEnqueue::VisitOMPSIMDClause(const OMPSIMDClause *) {}