[OPENMP]Initial support for at clause

Error directive is allowed in both declared and executable contexts.
The function ActOnOpenMPAtClause is called in both places during the
parsers.

Adding a param "bool InExContext" to identify context which is used to
emit error massage.

Differential Revision: https://reviews.llvm.org/D137851
This commit is contained in:
Jennifer Yu 2022-11-10 18:12:35 -08:00
parent 05ec16d90d
commit 628fdc3f57
21 changed files with 342 additions and 27 deletions

View File

@ -1563,6 +1563,85 @@ public:
}
};
/// This represents 'at' clause in the '#pragma omp error' directive
///
/// \code
/// #pragma omp error at(compilation)
/// \endcode
/// In this example directive '#pragma omp error' has simple
/// 'at' clause with kind 'complilation'.
class OMPAtClause final : public OMPClause {
friend class OMPClauseReader;
/// Location of '('
SourceLocation LParenLoc;
/// A kind of the 'at' clause.
OpenMPAtClauseKind Kind = OMPC_AT_unknown;
/// Start location of the kind in source code.
SourceLocation KindKwLoc;
/// Set kind of the clause.
///
/// \param K Kind of clause.
void setAtKind(OpenMPAtClauseKind K) { Kind = K; }
/// Set clause kind location.
///
/// \param KLoc Kind location.
void setAtKindKwLoc(SourceLocation KLoc) { KindKwLoc = KLoc; }
/// Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
public:
/// Build 'at' clause with argument \a A ('compilation' or 'execution').
///
/// \param A Argument of the clause ('compilation' or 'execution').
/// \param ALoc Starting location of the argument.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
OMPAtClause(OpenMPAtClauseKind A, SourceLocation ALoc,
SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc)
: OMPClause(llvm::omp::OMPC_at, StartLoc, EndLoc), LParenLoc(LParenLoc),
Kind(A), KindKwLoc(ALoc) {}
/// Build an empty clause.
OMPAtClause()
: OMPClause(llvm::omp::OMPC_at, SourceLocation(), SourceLocation()) {}
/// Returns the locaiton of '('.
SourceLocation getLParenLoc() const { return LParenLoc; }
/// Returns kind of the clause.
OpenMPAtClauseKind getAtKind() const { return Kind; }
/// Returns location of clause kind.
SourceLocation getAtKindKwLoc() const { return KindKwLoc; }
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() == llvm::omp::OMPC_at;
}
};
/// This represents 'schedule' clause in the '#pragma omp ...' directive.
///
/// \code

View File

@ -3310,6 +3310,11 @@ bool RecursiveASTVisitor<Derived>::VisitOMPAtomicDefaultMemOrderClause(
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPAtClause(OMPAtClause *) {
return true;
}
template <typename Derived>
bool
RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) {

View File

@ -1401,6 +1401,8 @@ def err_omp_mapper_expected_declarator : Error<
"expected declarator on 'omp declare mapper' directive">;
def err_omp_unexpected_append_op : Error<
"unexpected operation specified in 'append_args' clause, expected 'interop'">;
def err_omp_unexpected_execution_modifier : Error<
"unexpected 'execution' modifier in non-executable context">;
def err_omp_declare_variant_wrong_clause : Error<
"expected %select{'match'|'match', 'adjust_args', or 'append_args'}0 clause "
"on 'omp declare variant' directive">;

View File

@ -41,6 +41,9 @@
#ifndef OPENMP_ATOMIC_DEFAULT_MEM_ORDER_KIND
#define OPENMP_ATOMIC_DEFAULT_MEM_ORDER_KIND(Name)
#endif
#ifndef OPENMP_AT_KIND
#define OPENMP_AT_KIND(Name)
#endif
#ifndef OPENMP_DEFAULTMAP_MODIFIER
#define OPENMP_DEFAULTMAP_MODIFIER(Name)
#endif
@ -119,6 +122,10 @@ OPENMP_ATOMIC_DEFAULT_MEM_ORDER_KIND(seq_cst)
OPENMP_ATOMIC_DEFAULT_MEM_ORDER_KIND(acq_rel)
OPENMP_ATOMIC_DEFAULT_MEM_ORDER_KIND(relaxed)
// Modifiers for 'at' clause.
OPENMP_AT_KIND(compilation)
OPENMP_AT_KIND(execution)
// Map types for 'map' clause.
OPENMP_MAP_KIND(alloc)
OPENMP_MAP_KIND(to)
@ -179,6 +186,7 @@ OPENMP_BIND_KIND(thread)
#undef OPENMP_SCHEDULE_MODIFIER
#undef OPENMP_SCHEDULE_KIND
#undef OPENMP_ATOMIC_DEFAULT_MEM_ORDER_KIND
#undef OPENMP_AT_KIND
#undef OPENMP_MAP_KIND
#undef OPENMP_MAP_MODIFIER_KIND
#undef OPENMP_MOTION_MODIFIER_KIND

View File

@ -131,6 +131,13 @@ enum OpenMPAtomicDefaultMemOrderClauseKind {
OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown
};
/// OpenMP attributes for 'at' clause.
enum OpenMPAtClauseKind {
#define OPENMP_AT_KIND(Name) OMPC_AT_##Name,
#include "clang/Basic/OpenMPKinds.def"
OMPC_AT_unknown
};
/// OpenMP device type for 'device_type' clause.
enum OpenMPDeviceType {
#define OPENMP_DEVICE_TYPE_KIND(Name) \

View File

@ -3293,6 +3293,15 @@ private:
/// Parse 'omp end assumes' directive.
void ParseOpenMPEndAssumesDirective(SourceLocation Loc);
/// Parses clauses for directive.
///
/// \param DKind Kind of current directive.
/// \param clauses for current directive.
/// \param start location for clauses of current directive
void ParseOpenMPClauses(OpenMPDirectiveKind DKind,
SmallVectorImpl<clang::OMPClause *> &Clauses,
SourceLocation Loc);
/// Parse clauses for '#pragma omp [begin] declare target'.
void ParseOMPDeclareTargetClauses(Sema::DeclareTargetContextInfo &DTCI);

View File

@ -11287,9 +11287,12 @@ public:
StmtResult ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc,
SourceLocation EndLoc);
/// Called on well-formed '\#pragma omp error'.
/// Error direcitive is allowed in both declared and excutable contexts.
/// Adding InExContext to identify which context is called from.
StmtResult ActOnOpenMPErrorDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc);
SourceLocation EndLoc,
bool InExContext = true);
/// Called on well-formed '\#pragma omp barrier'.
StmtResult ActOnOpenMPBarrierDirective(SourceLocation StartLoc,
SourceLocation EndLoc);
@ -11826,6 +11829,13 @@ public:
OpenMPAtomicDefaultMemOrderClauseKind Kind, SourceLocation KindLoc,
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc);
/// Called on well-formed 'at' clause.
OMPClause *ActOnOpenMPAtClause(OpenMPAtClauseKind Kind,
SourceLocation KindLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// Data used for processing a list of variables in OpenMP clauses.
struct OpenMPVarListDataTy final {
Expr *DepModOrTailExpr = nullptr;

View File

@ -152,6 +152,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
case OMPC_at:
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
@ -251,6 +252,7 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
case OMPC_at:
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
@ -1781,6 +1783,11 @@ void OMPClausePrinter::VisitOMPAtomicDefaultMemOrderClause(
<< ")";
}
void OMPClausePrinter::VisitOMPAtClause(OMPAtClause *Node) {
OS << "at(" << getOpenMPSimpleClauseTypeName(OMPC_at, Node->getAtKind())
<< ")";
}
void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) {
OS << "schedule(";
if (Node->getFirstScheduleModifier() != OMPC_SCHEDULE_MODIFIER_unknown) {

View File

@ -530,6 +530,8 @@ void OMPClauseProfiler::VisitOMPDynamicAllocatorsClause(
void OMPClauseProfiler::VisitOMPAtomicDefaultMemOrderClause(
const OMPAtomicDefaultMemOrderClause *C) {}
void OMPClauseProfiler::VisitOMPAtClause(const OMPAtClause *C) {}
void OMPClauseProfiler::VisitOMPScheduleClause(const OMPScheduleClause *C) {
VistOMPClauseWithPreInit(C);
if (auto *S = C->getChunkSize())

View File

@ -104,6 +104,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str,
#define OPENMP_DEVICE_TYPE_KIND(Name) .Case(#Name, OMPC_DEVICE_TYPE_##Name)
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_DEVICE_TYPE_unknown);
case OMPC_at:
return llvm::StringSwitch<OpenMPAtClauseKind>(Str)
#define OPENMP_AT_KIND(Name) .Case(#Name, OMPC_AT_##Name)
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_AT_unknown);
case OMPC_lastprivate:
return llvm::StringSwitch<OpenMPLastprivateModifier>(Str)
#define OPENMP_LASTPRIVATE_KIND(Name) .Case(#Name, OMPC_LASTPRIVATE_##Name)
@ -336,6 +341,17 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
#include "clang/Basic/OpenMPKinds.def"
}
llvm_unreachable("Invalid OpenMP 'device_type' clause type");
case OMPC_at:
switch (Type) {
case OMPC_AT_unknown:
return "unknown";
#define OPENMP_AT_KIND(Name) \
case OMPC_AT_##Name: \
return #Name;
#include "clang/Basic/OpenMPKinds.def"
}
llvm_unreachable("Invalid OpenMP 'at' clause type");
llvm_unreachable("Invalid OpenMP 'at' clause type");
case OMPC_lastprivate:
switch (Type) {
case OMPC_LASTPRIVATE_unknown:

View File

@ -6512,6 +6512,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
case OMPC_at:
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:

View File

@ -1627,6 +1627,42 @@ bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc,
return false;
}
/// <clause> [clause[ [,] clause] ... ]
///
/// clauses: for error directive
/// 'at' '(' compilation | execution ')'
/// 'severity' '(' fatal | warning ')'
/// 'message' '(' msg-string ')'
/// ....
void Parser::ParseOpenMPClauses(OpenMPDirectiveKind DKind,
SmallVectorImpl<OMPClause *> &Clauses,
SourceLocation Loc) {
SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>,
llvm::omp::Clause_enumSize + 1>
FirstClauses(llvm::omp::Clause_enumSize + 1);
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
OpenMPClauseKind CKind = Tok.isAnnotation()
? OMPC_unknown
: getOpenMPClauseKind(PP.getSpelling(Tok));
Actions.StartOpenMPClause(CKind);
OMPClause *Clause = ParseOpenMPClause(
DKind, CKind, !FirstClauses[unsigned(CKind)].getInt());
SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,
StopBeforeMatch);
FirstClauses[unsigned(CKind)].setInt(true);
if (Clause != nullptr)
Clauses.push_back(Clause);
if (Tok.is(tok::annot_pragma_openmp_end)) {
Actions.EndOpenMPClause();
break;
}
// Skip ',' if any.
if (Tok.is(tok::comma))
ConsumeToken();
Actions.EndOpenMPClause();
}
}
/// `omp assumes` or `omp begin/end assumes` <clause> [[,]<clause>]...
/// where
///
@ -2124,6 +2160,14 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
ConsumeAnnotationToken();
return Actions.ActOnOpenMPRequiresDirective(StartLoc, Clauses);
}
case OMPD_error: {
SmallVector<OMPClause *, 1> Clauses;
SourceLocation StartLoc = ConsumeToken();
ParseOpenMPClauses(DKind, Clauses, StartLoc);
Actions.ActOnOpenMPErrorDirective(Clauses, StartLoc, SourceLocation(),
/*InExContext = */ false);
break;
}
case OMPD_assumes:
case OMPD_begin_assumes:
ParseOpenMPAssumesDirective(DKind, ConsumeToken());
@ -2310,7 +2354,6 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
case OMPD_unroll:
case OMPD_task:
case OMPD_taskyield:
case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_taskgroup:
@ -2711,6 +2754,10 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
ParsedStmtContext()) {
Diag(Tok, diag::err_omp_immediate_directive)
<< getOpenMPDirectiveName(DKind) << 0;
if (DKind == OMPD_error) {
SkipUntil(tok::annot_pragma_openmp_end);
break;
}
}
HasAssociatedStatement = false;
// Fall through for further analysis.
@ -3170,6 +3217,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_default:
case OMPC_proc_bind:
case OMPC_atomic_default_mem_order:
case OMPC_at:
case OMPC_order:
case OMPC_bind:
// OpenMP [2.14.3.1, Restrictions]
@ -3180,6 +3228,8 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
// OpenMP [5.0, Requires directive, Restrictions]
// At most one atomic_default_mem_order clause can appear
// on the directive
// OpenMP [5.1, Requires directive, Restrictions]
// At most one at clause can appear on the directive
// OpenMP 5.1, 2.11.7 loop Construct, Restrictions.
// At most one bind clause can appear on a loop directive.
if (!FirstClause && CKind != OMPC_order) {

View File

@ -6308,7 +6308,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
break;
case OMPD_error:
assert(AStmt == nullptr &&
"No associated statement allowed for 'omp taskyield' directive");
"No associated statement allowed for 'omp error' directive");
Res = ActOnOpenMPErrorDirective(ClausesWithImplicit, StartLoc, EndLoc);
break;
case OMPD_barrier:
@ -6719,6 +6719,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_device_type:
case OMPC_match:
case OMPC_when:
case OMPC_at:
default:
llvm_unreachable("Unexpected clause");
}
@ -11028,7 +11029,21 @@ StmtResult Sema::ActOnOpenMPBarrierDirective(SourceLocation StartLoc,
StmtResult Sema::ActOnOpenMPErrorDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc) {
SourceLocation EndLoc,
bool InExContext) {
auto AtClauses =
OMPExecutableDirective::getClausesOfKind<OMPAtClause>(Clauses);
const OMPAtClause *AtC = AtClauses.empty() ? nullptr : (*AtClauses.begin());
if (AtC && !InExContext && AtC->getAtKind() == OMPC_AT_execution) {
Diag(AtC->getAtKindKwLoc(), diag::err_omp_unexpected_execution_modifier);
return StmtError();
}
if (!AtC || AtC->getAtKind() == OMPC_AT_compilation) {
Diag(AtC ? AtC->getBeginLoc() : StartLoc, diag::err_diagnose_if_succeeded)
<< "ERROR";
return StmtError();
}
return OMPErrorDirective::Create(Context, StartLoc, EndLoc, Clauses);
}
@ -15171,6 +15186,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_match:
case OMPC_nontemporal:
case OMPC_order:
case OMPC_at:
case OMPC_destroy:
case OMPC_inclusive:
case OMPC_exclusive:
@ -16096,6 +16112,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_match:
case OMPC_nontemporal:
case OMPC_order:
case OMPC_at:
case OMPC_destroy:
case OMPC_detach:
case OMPC_inclusive:
@ -16498,6 +16515,10 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
Res = ActOnOpenMPBindClause(static_cast<OpenMPBindClauseKind>(Argument),
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_at:
Res = ActOnOpenMPAtClause(static_cast<OpenMPAtClauseKind>(Argument),
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
@ -16676,6 +16697,22 @@ OMPClause *Sema::ActOnOpenMPAtomicDefaultMemOrderClause(
LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPAtClause(OpenMPAtClauseKind Kind,
SourceLocation KindKwLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
if (Kind == OMPC_AT_unknown) {
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
<< getListOfPossibleValues(OMPC_at, /*First=*/0,
/*Last=*/OMPC_AT_unknown)
<< getOpenMPClauseName(OMPC_at);
return nullptr;
}
return new (Context)
OMPAtClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPOrderClause(OpenMPOrderClauseKind Kind,
SourceLocation KindKwLoc,
SourceLocation StartLoc,
@ -16875,6 +16912,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_match:
case OMPC_nontemporal:
case OMPC_order:
case OMPC_at:
case OMPC_destroy:
case OMPC_novariants:
case OMPC_nocontext:
@ -17131,6 +17169,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_match:
case OMPC_nontemporal:
case OMPC_order:
case OMPC_at:
case OMPC_novariants:
case OMPC_nocontext:
case OMPC_detach:
@ -17685,6 +17724,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
case OMPC_device_type:
case OMPC_match:
case OMPC_order:
case OMPC_at:
case OMPC_destroy:
case OMPC_novariants:
case OMPC_nocontext:

View File

@ -2351,6 +2351,17 @@ public:
return getSema().ActOnOpenMPAlignClause(A, StartLoc, LParenLoc, EndLoc);
}
/// Build a new OpenMP 'at' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPAtClause(OpenMPAtClauseKind Kind, SourceLocation KwLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
return getSema().ActOnOpenMPAtClause(Kind, KwLoc, StartLoc, LParenLoc,
EndLoc);
}
/// Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@ -9855,6 +9866,13 @@ OMPClause *TreeTransform<Derived>::TransformOMPAtomicDefaultMemOrderClause(
"atomic_default_mem_order clause cannot appear in dependent context");
}
template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPAtClause(OMPAtClause *C) {
return getDerived().RebuildOMPAtClause(C->getAtKind(), C->getAtKindKwLoc(),
C->getBeginLoc(), C->getLParenLoc(),
C->getEndLoc());
}
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) {

View File

@ -9934,7 +9934,10 @@ OMPClause *OMPClauseReader::readClause() {
case llvm::omp::OMPC_atomic_default_mem_order:
C = new (Context) OMPAtomicDefaultMemOrderClause();
break;
case llvm::omp::OMPC_private:
case llvm::omp::OMPC_at:
C = new (Context) OMPAtClause();
break;
case llvm::omp::OMPC_private:
C = OMPPrivateClause::CreateEmpty(Context, Record.readInt());
break;
case llvm::omp::OMPC_firstprivate:
@ -10336,6 +10339,12 @@ void OMPClauseReader::VisitOMPAtomicDefaultMemOrderClause(
C->setAtomicDefaultMemOrderKindKwLoc(Record.readSourceLocation());
}
void OMPClauseReader::VisitOMPAtClause(OMPAtClause *C) {
C->setAtKind(static_cast<OpenMPAtClauseKind>(Record.readInt()));
C->setLParenLoc(Record.readSourceLocation());
C->setAtKindKwLoc(Record.readSourceLocation());
}
void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
C->setLParenLoc(Record.readSourceLocation());
unsigned NumVars = C->varlist_size();

View File

@ -6981,6 +6981,12 @@ void OMPClauseWriter::VisitOMPAtomicDefaultMemOrderClause(
Record.AddSourceLocation(C->getAtomicDefaultMemOrderKindKwLoc());
}
void OMPClauseWriter::VisitOMPAtClause(OMPAtClause *C) {
Record.push_back(C->getAtKind());
Record.AddSourceLocation(C->getLParenLoc());
Record.AddSourceLocation(C->getAtKindKwLoc());
}
void OMPClauseWriter::VisitOMPNontemporalClause(OMPNontemporalClause *C) {
Record.push_back(C->varlist_size());
Record.AddSourceLocation(C->getLParenLoc());

View File

@ -13,16 +13,16 @@
void foo() {}
// CHECK: template <typename T, int N> int tmain(T argc, char **argv)
// CHECK: static int a;
// CHECK-NEXT: #pragma omp error
// CHECK-NEXT: #pragma omp error at(execution)
// CHECK-NEXT: a = argv[0][0];
// CHECK-NEXT: ++a;
// CHECK-NEXT: #pragma omp error
// CHECK-NEXT: #pragma omp error at(execution)
// CHECK-NEXT: {
// CHECK-NEXT: int b = 10;
// CHECK-NEXT: T c = 100;
// CHECK-NEXT: a = b + c;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp error
// CHECK-NEXT: #pragma omp error at(execution)
// CHECK-NEXT: foo();
// CHECK-NEXT: return N;
@ -30,16 +30,16 @@ template <typename T, int N>
int tmain(T argc, char **argv) {
T b = argc, c, d, e, f, g;
static int a;
#pragma omp error
#pragma omp error at(execution)
a = argv[0][0];
++a;
#pragma omp error
#pragma omp error at(execution)
{
int b = 10;
T c = 100;
a = b + c;
}
#pragma omp error
#pragma omp error at(execution)
foo();
return N;
}
@ -47,16 +47,16 @@ return N;
// CHECK: int main(int argc, char **argv)
// CHECK-NEXT: int b = argc, c, d, e, f, g;
// CHECK-NEXT: static int a;
// CHECK-NEXT: #pragma omp error
// CHECK-NEXT: #pragma omp error at(execution)
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp error
// CHECK-NEXT: #pragma omp error at(execution)
// CHECK-NEXT: foo();
int main (int argc, char **argv) {
int b = argc, c, d, e, f, g;
static int a;
#pragma omp error
#pragma omp error at(execution)
a=2;
#pragma omp error
#pragma omp error at(execution)
foo();
}
#endif

View File

@ -7,19 +7,19 @@ T tmain(T argc) {
if (argc)
#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
if (argc) {
#pragma omp error
#pragma omp error // expected-error {{ERROR}}
}
while (argc)
#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
while (argc) {
#pragma omp error
#pragma omp error // expected-error {{ERROR}}
}
do
#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
while (argc)
;
do {
#pragma omp error
#pragma omp error // expected-error {{ERROR}}
} while (argc);
switch (argc)
#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
@ -28,47 +28,75 @@ T tmain(T argc) {
#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
switch (argc)
case 1: {
#pragma omp error
#pragma omp error // expected-error {{ERROR}}
}
switch (argc) {
#pragma omp error
#pragma omp error // expected-error {{ERROR}}
case 1:
#pragma omp error
#pragma omp error // expected-error {{ERROR}}
break;
default: {
#pragma omp error
#pragma omp error // expected-error {{ERROR}}
} break;
}
for (;;)
#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
for (;;) {
#pragma omp error
#pragma omp error // expected-error {{ERROR}}
}
label:
#pragma omp error
#pragma omp error // expected-error {{ERROR}}
label1 : {
#pragma omp error
#pragma omp error // expected-error {{ERROR}}
}
if (1)
label2:
#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
// expected-error@+1 {{ERROR}}
#pragma omp error at() // expected-error {{expected 'compilation' or 'execution' in OpenMP clause 'at'}}
// expected-error@+1 {{ERROR}}
#pragma omp error at(up) // expected-error {{expected 'compilation' or 'execution' in OpenMP clause 'at'}}
// expected-error@+3 {{ERROR}}
// expected-error@+2 {{expected ')'}}
// expected-note@+1 {{to match this '('}}
#pragma omp error at(up(a)) // expected-error {{expected 'compilation' or 'execution' in OpenMP clause 'at'}}
#pragma omp error at(execution) // no error
#pragma omp error at(compilation) // expected-error {{ERROR}}
return T();
}
#pragma omp error at(execution) // expected-error {{unexpected 'execution' modifier in non-executable context}}
#pragma omp error at(compilation) // expected-error {{ERROR}}
class A {
#pragma omp error at(compilation) // expected-error {{ERROR}}
#pragma omp error at(execution) // expected-error {{unexpected 'execution' modifier in non-executable context}}
int A;
};
int main(int argc, char **argv) {
// expected-error@+1 {{ERROR}}
#pragma omp error
;
// expected-error@+1 {{ERROR}}
#pragma omp error untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp error'}}
#pragma omp error unknown // expected-warning {{extra tokens at the end of '#pragma omp error' are ignored}}
if (argc)
#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
if (argc) {
// expected-error@+1 {{ERROR}}
#pragma omp error
}
while (argc)
#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
while (argc) {
// expected-error@+1 {{ERROR}}
#pragma omp error
}
do
@ -76,6 +104,7 @@ int main(int argc, char **argv) {
while (argc)
;
do {
// expected-error@+1 {{ERROR}}
#pragma omp error
} while (argc);
switch (argc)
@ -85,25 +114,32 @@ int main(int argc, char **argv) {
#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
switch (argc)
case 1: {
// expected-error@+1 {{ERROR}}
#pragma omp error
}
switch (argc) {
// expected-error@+1 {{ERROR}}
#pragma omp error
case 1:
// expected-error@+1 {{ERROR}}
#pragma omp error
break;
default: {
// expected-error@+1 {{ERROR}}
#pragma omp error
} break;
}
for (;;)
#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
for (;;) {
// expected-error@+1 {{ERROR}}
#pragma omp error
}
label:
// expected-error@+1 {{ERROR}}
#pragma omp error
label1 : {
// expected-error@+1 {{ERROR}}
#pragma omp error
}
if (1)

View File

@ -2443,6 +2443,8 @@ void OMPClauseEnqueue::VisitOMPDynamicAllocatorsClause(
void OMPClauseEnqueue::VisitOMPAtomicDefaultMemOrderClause(
const OMPAtomicDefaultMemOrderClause *) {}
void OMPClauseEnqueue::VisitOMPAtClause(const OMPAtClause *) {}
void OMPClauseEnqueue::VisitOMPDeviceClause(const OMPDeviceClause *C) {
Visitor->AddStmt(C->getDevice());
}

View File

@ -1868,6 +1868,7 @@ CHECK_SIMPLE_CLAUSE(Init, OMPC_init)
CHECK_SIMPLE_CLAUSE(Use, OMPC_use)
CHECK_SIMPLE_CLAUSE(Novariants, OMPC_novariants)
CHECK_SIMPLE_CLAUSE(Nocontext, OMPC_nocontext)
CHECK_SIMPLE_CLAUSE(At, OMPC_at)
CHECK_SIMPLE_CLAUSE(Filter, OMPC_filter)
CHECK_SIMPLE_CLAUSE(When, OMPC_when)
CHECK_SIMPLE_CLAUSE(AdjustArgs, OMPC_adjust_args)

View File

@ -301,6 +301,9 @@ def OMPC_AtomicDefaultMemOrder : Clause<"atomic_default_mem_order"> {
let clangClass = "OMPAtomicDefaultMemOrderClause";
let flangClass = "OmpAtomicDefaultMemOrderClause";
}
def OMPC_At : Clause<"at"> {
let clangClass = "OMPAtClause";
}
def OMPC_Allocate : Clause<"allocate"> {
let clangClass = "OMPAllocateClause";
let flangClass = "OmpAllocateClause";
@ -527,7 +530,11 @@ def OMP_Critical : Directive<"critical"> {
}
def OMP_TaskYield : Directive<"taskyield"> {}
def OMP_Barrier : Directive<"barrier"> {}
def OMP_Error : Directive<"error"> {}
def OMP_Error : Directive<"error"> {
let allowedClauses = [
VersionedClause<OMPC_At>
];
}
def OMP_TaskWait : Directive<"taskwait"> {
let allowedClauses = [
VersionedClause<OMPC_Depend, 50>