60 changes: 43 additions & 17 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,6 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
SemaOpenACC::OpenACCParsedClause ParsedClause(DirKind, ClauseKind, ClauseLoc);

if (ClauseHasRequiredParens(DirKind, ClauseKind)) {
ParsedClause.setLParenLoc(getCurToken().getLocation());
if (Parens.expectAndConsume()) {
// We are missing a paren, so assume that the person just forgot the
// parameter. Return 'false' so we try to continue on and parse the next
Expand All @@ -876,6 +875,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
Parser::StopBeforeMatch);
return OpenACCCanContinue();
}
ParsedClause.setLParenLoc(Parens.getOpenLocation());

switch (ClauseKind) {
case OpenACCClauseKind::Default: {
Expand Down Expand Up @@ -1048,8 +1048,8 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
return OpenACCCannotContinue();

} else if (ClauseHasOptionalParens(DirKind, ClauseKind)) {
ParsedClause.setLParenLoc(getCurToken().getLocation());
if (!Parens.consumeOpen()) {
ParsedClause.setLParenLoc(Parens.getOpenLocation());
switch (ClauseKind) {
case OpenACCClauseKind::Self: {
assert(DirKind != OpenACCDirectiveKind::Update);
Expand Down Expand Up @@ -1099,19 +1099,29 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
return OpenACCCanContinue();
}
break;
case OpenACCClauseKind::Wait:
if (ParseOpenACCWaitArgument(ClauseLoc,
/*IsDirective=*/false)) {
case OpenACCClauseKind::Wait: {
OpenACCWaitParseInfo Info =
ParseOpenACCWaitArgument(ClauseLoc,
/*IsDirective=*/false);
if (Info.Failed) {
Parens.skipToEnd();
return OpenACCCanContinue();
}

ParsedClause.setWaitDetails(Info.DevNumExpr, Info.QueuesLoc,
std::move(Info.QueueIdExprs));
break;
}
default:
llvm_unreachable("Not an optional parens type?");
}
ParsedClause.setEndLoc(getCurToken().getLocation());
if (Parens.consumeClose())
return OpenACCCannotContinue();
} else {
// If we have optional parens, make sure we set the end-location to the
// clause, as we are a 'single token' clause.
ParsedClause.setEndLoc(ClauseLoc);
}
}
return OpenACCSuccess(
Expand All @@ -1135,7 +1145,9 @@ Parser::ParseOpenACCAsyncArgument(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
/// In this section and throughout the specification, the term wait-argument
/// means:
/// [ devnum : int-expr : ] [ queues : ] async-argument-list
bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
Parser::OpenACCWaitParseInfo
Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
OpenACCWaitParseInfo Result;
// [devnum : int-expr : ]
if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&
NextToken().is(tok::colon)) {
Expand All @@ -1149,18 +1161,25 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
: OpenACCDirectiveKind::Invalid,
IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,
Loc);
if (Res.first.isInvalid() && Res.second == OpenACCParseCanContinue::Cannot)
return true;
if (Res.first.isInvalid() &&
Res.second == OpenACCParseCanContinue::Cannot) {
Result.Failed = true;
return Result;
}

if (ExpectAndConsume(tok::colon))
return true;
if (ExpectAndConsume(tok::colon)) {
Result.Failed = true;
return Result;
}

Result.DevNumExpr = Res.first.get();
}

// [ queues : ]
if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&
NextToken().is(tok::colon)) {
// Consume queues.
ConsumeToken();
Result.QueuesLoc = ConsumeToken();
// Consume colon.
ConsumeToken();
}
Expand All @@ -1172,8 +1191,10 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
bool FirstArg = true;
while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
if (!FirstArg) {
if (ExpectAndConsume(tok::comma))
return true;
if (ExpectAndConsume(tok::comma)) {
Result.Failed = true;
return Result;
}
}
FirstArg = false;

Expand All @@ -1183,11 +1204,16 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,
Loc);

if (Res.first.isInvalid() && Res.second == OpenACCParseCanContinue::Cannot)
return true;
if (Res.first.isInvalid() &&
Res.second == OpenACCParseCanContinue::Cannot) {
Result.Failed = true;
return Result;
}

Result.QueueIdExprs.push_back(Res.first.get());
}

return false;
return Result;
}

ExprResult Parser::ParseOpenACCIDExpression() {
Expand Down Expand Up @@ -1356,7 +1382,7 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() {
break;
case OpenACCDirectiveKind::Wait:
// OpenACC has an optional paren-wrapped 'wait-argument'.
if (ParseOpenACCWaitArgument(StartLoc, /*IsDirective=*/true))
if (ParseOpenACCWaitArgument(StartLoc, /*IsDirective=*/true).Failed)
T.skipToEnd();
else
T.consumeClose();
Expand Down
28 changes: 28 additions & 0 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,22 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind,
default:
return false;
}
case OpenACCClauseKind::Wait:
switch (DirectiveKind) {
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
case OpenACCDirectiveKind::Data:
case OpenACCDirectiveKind::EnterData:
case OpenACCDirectiveKind::ExitData:
case OpenACCDirectiveKind::Update:
case OpenACCDirectiveKind::ParallelLoop:
case OpenACCDirectiveKind::SerialLoop:
case OpenACCDirectiveKind::KernelsLoop:
return true;
default:
return false;
}

default:
// Do nothing so we can go to the 'unimplemented' diagnostic instead.
Expand Down Expand Up @@ -623,6 +639,18 @@ SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
Clause.getVarList(), Clause.getEndLoc());
}
case OpenACCClauseKind::Wait: {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
// this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
break;

return OpenACCWaitClause::Create(
getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
Clause.getDevNumExpr(), Clause.getQueuesLoc(), Clause.getQueueIdExprs(),
Clause.getEndLoc());
}
default:
break;
}
Expand Down
45 changes: 45 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -11425,6 +11425,51 @@ void OpenACCClauseTransform<Derived>::VisitAsyncClause(
: nullptr,
ParsedClause.getEndLoc());
}
template <typename Derived>
void OpenACCClauseTransform<Derived>::VisitWaitClause(
const OpenACCWaitClause &C) {
if (!C.getLParenLoc().isInvalid()) {
Expr *DevNumExpr = nullptr;
llvm::SmallVector<Expr *> InstantiatedQueueIdExprs;

// Instantiate devnum expr if it exists.
if (C.getDevNumExpr()) {
ExprResult Res = Self.TransformExpr(C.getDevNumExpr());
if (!Res.isUsable())
return;
Res = Self.getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Invalid,
C.getClauseKind(),
C.getBeginLoc(), Res.get());
if (!Res.isUsable())
return;

DevNumExpr = Res.get();
}

// Instantiate queue ids.
for (Expr *CurQueueIdExpr : C.getQueueIdExprs()) {
ExprResult Res = Self.TransformExpr(CurQueueIdExpr);
if (!Res.isUsable())
return;
Res = Self.getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Invalid,
C.getClauseKind(),
C.getBeginLoc(), Res.get());
if (!Res.isUsable())
return;

InstantiatedQueueIdExprs.push_back(Res.get());
}

ParsedClause.setWaitDetails(DevNumExpr, C.getQueuesLoc(),
std::move(InstantiatedQueueIdExprs));
}

NewClause = OpenACCWaitClause::Create(
Self.getSema().getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), ParsedClause.getDevNumExpr(),
ParsedClause.getQueuesLoc(), ParsedClause.getQueueIdExprs(),
ParsedClause.getEndLoc());
}
} // namespace
template <typename Derived>
OpenACCClause *TreeTransform<Derived>::TransformOpenACCClause(
Expand Down
18 changes: 17 additions & 1 deletion clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11766,6 +11766,14 @@ SmallVector<Expr *> ASTRecordReader::readOpenACCVarList() {
return VarList;
}

SmallVector<Expr *> ASTRecordReader::readOpenACCIntExprList() {
unsigned NumExprs = readInt();
llvm::SmallVector<Expr *> ExprList;
for (unsigned I = 0; I < NumExprs; ++I)
ExprList.push_back(readSubExpr());
return ExprList;
}

OpenACCClause *ASTRecordReader::readOpenACCClause() {
OpenACCClauseKind ClauseKind = readEnum<OpenACCClauseKind>();
SourceLocation BeginLoc = readSourceLocation();
Expand Down Expand Up @@ -11888,6 +11896,15 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
return OpenACCAsyncClause::Create(getContext(), BeginLoc, LParenLoc,
AsyncExpr, EndLoc);
}
case OpenACCClauseKind::Wait: {
SourceLocation LParenLoc = readSourceLocation();
Expr *DevNumExpr = readBool() ? readSubExpr() : nullptr;
SourceLocation QueuesLoc = readSourceLocation();
llvm::SmallVector<Expr *> QueueIdExprs = readOpenACCIntExprList();
return OpenACCWaitClause::Create(getContext(), BeginLoc, LParenLoc,
DevNumExpr, QueuesLoc, QueueIdExprs,
EndLoc);
}

case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
Expand All @@ -11913,7 +11930,6 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
case OpenACCClauseKind::DType:
case OpenACCClauseKind::Tile:
case OpenACCClauseKind::Gang:
case OpenACCClauseKind::Wait:
case OpenACCClauseKind::Invalid:
llvm_unreachable("Clause serialization not yet implemented");
}
Expand Down
18 changes: 17 additions & 1 deletion clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7791,6 +7791,12 @@ void ASTRecordWriter::writeOpenACCVarList(const OpenACCClauseWithVarList *C) {
AddStmt(E);
}

void ASTRecordWriter::writeOpenACCIntExprList(ArrayRef<Expr *> Exprs) {
writeUInt32(Exprs.size());
for (Expr *E : Exprs)
AddStmt(E);
}

void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
writeEnum(C->getClauseKind());
writeSourceLocation(C->getBeginLoc());
Expand Down Expand Up @@ -7916,6 +7922,17 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
AddStmt(const_cast<Expr *>(AC->getIntExpr()));
return;
}
case OpenACCClauseKind::Wait: {
const auto *WC = cast<OpenACCWaitClause>(C);
writeSourceLocation(WC->getLParenLoc());
writeBool(WC->getDevNumExpr());
if (const Expr *DNE = WC->getDevNumExpr())
AddStmt(const_cast<Expr *>(DNE));
writeSourceLocation(WC->getQueuesLoc());

writeOpenACCIntExprList(WC->getQueueIdExprs());
return;
}

case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
Expand All @@ -7941,7 +7958,6 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
case OpenACCClauseKind::DType:
case OpenACCClauseKind::Tile:
case OpenACCClauseKind::Gang:
case OpenACCClauseKind::Wait:
case OpenACCClauseKind::Invalid:
llvm_unreachable("Clause serialization not yet implemented");
}
Expand Down
24 changes: 24 additions & 0 deletions clang/test/AST/ast-print-openacc-compute-construct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,29 @@ void foo() {
// CHECK: #pragma acc kernels async
#pragma acc kernels async
while(true);

// CHECK: #pragma acc parallel wait
#pragma acc parallel wait
while(true);

// CHECK: #pragma acc parallel wait()
#pragma acc parallel wait()
while(true);

// CHECK: #pragma acc parallel wait(*iPtr, i)
#pragma acc parallel wait(*iPtr, i)
while(true);

// CHECK: #pragma acc parallel wait(queues: *iPtr, i)
#pragma acc parallel wait(queues:*iPtr, i)
while(true);

// CHECK: #pragma acc parallel wait(devnum: i : *iPtr, i)
#pragma acc parallel wait(devnum:i:*iPtr, i)
while(true);

// CHECK: #pragma acc parallel wait(devnum: i : queues: *iPtr, i)
#pragma acc parallel wait(devnum:i:queues:*iPtr, i)
while(true);
}

48 changes: 16 additions & 32 deletions clang/test/ParserOpenACC/parse-wait-clause.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
void func() {
int i, j;

// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
#pragma acc parallel wait
{}

// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait clause-list
{}

Expand All @@ -17,12 +15,10 @@ void func() {
#pragma acc parallel wait (
{}

// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
#pragma acc parallel wait ()
{}

// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait () clause-list
{}

Expand Down Expand Up @@ -61,12 +57,10 @@ void func() {
#pragma acc parallel wait (queues:
{}

// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
#pragma acc parallel wait (queues:)
{}

// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait (queues:) clause-list
{}

Expand All @@ -75,12 +69,10 @@ void func() {
#pragma acc parallel wait (devnum: i + j:queues:
{}

// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
#pragma acc parallel wait (devnum: i + j:queues:)
{}

// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait (devnum: i + j:queues:) clause-list
{}

Expand Down Expand Up @@ -108,13 +100,11 @@ void func() {
#pragma acc parallel wait(i, j, 1+1, 3.3
{}

// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
#pragma acc parallel wait(i, j, 1+1, 3.3)
{}
// expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait(i, j, 1+1, 3.3) clause-list
{}

Expand Down Expand Up @@ -146,14 +136,12 @@ void func() {
#pragma acc parallel wait(queues:i, j, 1+1, 3.3,
{}

// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
#pragma acc parallel wait(queues:i, j, 1+1, 3.3)
{}

// expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait(queues:i, j, 1+1, 3.3) clause-list
{}

Expand All @@ -162,13 +150,11 @@ void func() {
// expected-note@+1{{to match this '('}}
#pragma acc parallel wait(devnum:3:i, j, 1+1, 3.3
{}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
#pragma acc parallel wait(devnum:3:i, j, 1+1, 3.3)
{}
// expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait(devnum:3:i, j, 1+1, 3.3) clause-list
{}

Expand All @@ -177,13 +163,11 @@ void func() {
// expected-note@+1{{to match this '('}}
#pragma acc parallel wait(devnum:3:queues:i, j, 1+1, 3.3
{}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
#pragma acc parallel wait(devnum:3:queues:i, j, 1+1, 3.3)
{}
// expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait(devnum:3:queues:i, j, 1+1, 3.3) clause-list
{}
}
229 changes: 229 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-intexpr-clause-ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,93 @@ void NormalUses() {
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel wait
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
#pragma acc parallel wait()
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
#pragma acc parallel wait(some_int(), some_long())
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// CHECK-NEXT: CallExpr{{.*}}'long'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
#pragma acc parallel wait(queues:some_int(), some_long())
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause has queues tag
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// CHECK-NEXT: CallExpr{{.*}}'long'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
#pragma acc parallel wait(devnum: some_int() :some_int(), some_long())
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause has devnum
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// CHECK-NEXT: CallExpr{{.*}}'long'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
#pragma acc parallel wait(devnum: some_int() : queues :some_int(), some_long()) wait(devnum: some_int() : queues :some_int(), some_long())
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause has devnum has queues tag
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// CHECK-NEXT: CallExpr{{.*}}'long'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()'
// CHECK-NEXT: wait clause has devnum has queues tag
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// CHECK-NEXT: CallExpr{{.*}}'long'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
}


Expand Down Expand Up @@ -282,6 +369,72 @@ void TemplUses(T t, U u) {
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel wait
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel wait()
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel wait(U::value, u)
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'U'
// CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel wait(queues: U::value, u)
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause has queues tag
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'U'
// CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel wait(devnum:u:queues: U::value, u)
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause has devnum has queues tag
// CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U'
// CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'U'
// CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel wait(devnum:u: U::value, u)
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause has devnum
// CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U'
// CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'U'
// CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt


// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl{{.*}}EndMarker
Expand Down Expand Up @@ -437,6 +590,82 @@ void TemplUses(T t, U u) {
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt'
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char
// CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause has queues tag
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt'
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char
// CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause has devnum has queues tag
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char
// CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt'
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char
// CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause has devnum
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char
// CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt'
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char
// CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl{{.*}}EndMarker
}
Expand Down
38 changes: 38 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-wait-clause.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// RUN: %clang_cc1 %s -fopenacc -verify

struct NotConvertible{} NC;
short getS();
int getI();

void uses() {
int arr[5];

#pragma acc parallel wait
while(1);

#pragma acc serial wait()
while(1);

#pragma acc kernels wait(getS(), getI())
while(1);

#pragma acc parallel wait(devnum:getS(): getI())
while(1);

#pragma acc parallel wait(devnum:getS(): queues: getI()) wait(devnum:getI(): queues: getS(), getI(), 5)
while(1);

// expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('struct NotConvertible' invalid)}}
#pragma acc parallel wait(devnum:NC : 5)
while(1);

// expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('struct NotConvertible' invalid)}}
#pragma acc parallel wait(devnum:5 : NC)
while(1);

// expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('int[5]' invalid)}}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('int[5]' invalid)}}
// expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('struct NotConvertible' invalid)}}
#pragma acc parallel wait(devnum:arr : queues: arr, NC, 5)
while(1);
}
104 changes: 104 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-wait-clause.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// RUN: %clang_cc1 %s -fopenacc -verify

struct ExplicitConvertOnly {
explicit operator int() const; // #EXPL_CONV
} Explicit;

struct AmbiguousConvert{
operator int(); // #AMBIG_INT
operator short(); // #AMBIG_SHORT
operator float();
} Ambiguous;

void Test() {

// expected-error@+3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel wait(Ambiguous)
while (true);

// expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
#pragma acc parallel wait(4, Explicit, 5)
while (true);

// expected-error@+3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel wait(queues: Ambiguous, 5)
while (true);

// expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
#pragma acc parallel wait(devnum: Explicit: 5)
while (true);

// expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
#pragma acc parallel wait(devnum: Explicit:queues: 5)
while (true);

// expected-error@+1{{use of undeclared identifier 'queues'}}
#pragma acc parallel wait(devnum: queues: 5)
while (true);
}

struct HasInt {
using IntTy = int;
using ShortTy = short;
static constexpr int value = 1;
static constexpr AmbiguousConvert ACValue;
static constexpr ExplicitConvertOnly EXValue;

operator char();
};

template<typename T>
void TestInst() {

#pragma acc parallel wait(T{})
while (true);

#pragma acc parallel wait(devnum:typename T::ShortTy{}:queues:typename T::IntTy{})
while (true);

// expected-error@+4{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
// expected-note@#INST{{in instantiation of function template specialization}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel wait(devnum:T::value :queues:T::ACValue)
while (true);

// expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
// expected-error@+3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel wait(devnum:T::EXValue :queues:T::ACValue)
while (true);

// expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
// expected-error@+3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel wait(T::EXValue, T::ACValue)
while (true);

// expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
// expected-error@+3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel wait(queues: T::EXValue, T::ACValue)
while (true);

// expected-error@+1{{no member named 'Invalid' in 'HasInt'}}
#pragma acc parallel wait(queues: T::Invalid, T::Invalid2)
while (true);
}

void Inst() {
TestInst<HasInt>(); // #INST
}
6 changes: 6 additions & 0 deletions clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2851,6 +2851,12 @@ void OpenACCClauseEnqueue::VisitAsyncClause(const OpenACCAsyncClause &C) {
if (C.hasIntExpr())
Visitor.AddStmt(C.getIntExpr());
}
void OpenACCClauseEnqueue::VisitWaitClause(const OpenACCWaitClause &C) {
if (const Expr *DevNumExpr = C.getDevNumExpr())
Visitor.AddStmt(DevNumExpr);
for (Expr *QE : C.getQueueIdExprs())
Visitor.AddStmt(QE);
}
} // namespace

void EnqueueVisitor::EnqueueChildren(const OpenACCClause *C) {
Expand Down