Skip to content

Commit 24aec16

Browse files
committed
[OpenACC] Implement no throw out of Compute construct
Exception handling SHOULD be possible depending on codegen (and if not, we can make it trap and add a warning when we make that decision), but throwing out of a compute construct is ill formed. This patch adds an error for a 'throw' that isn't in a 'try' scope. This error is imperfect as it won't diagnose a 'throw' that escapes its 'try', or one in a separate function, but it catches the obvious mistakes. The other cases will need to be handled as runtime failures.
1 parent 4762c65 commit 24aec16

File tree

5 files changed

+82
-25
lines changed

5 files changed

+82
-25
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12217,8 +12217,8 @@ def err_acc_construct_appertainment
1221712217
: Error<"OpenACC construct '%0' cannot be used here; it can only "
1221812218
"be used in a statement context">;
1221912219
def err_acc_branch_in_out_compute_construct
12220-
: Error<"invalid %select{branch|return}0 %select{out of|into}1 OpenACC "
12221-
"Compute Construct">;
12220+
: Error<"invalid %select{branch|return|throw}0 %select{out of|into}1 "
12221+
"OpenACC Compute Construct">;
1222212222
def note_acc_branch_into_compute_construct
1222312223
: Note<"invalid branch into OpenACC Compute Construct">;
1222412224
def note_acc_branch_out_of_compute_construct

clang/include/clang/Sema/Scope.h

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ class Scope {
4343
/// ScopeFlags - These are bitfields that are or'd together when creating a
4444
/// scope, which defines the sorts of things the scope contains.
4545
enum ScopeFlags {
46+
// A bitfield value representing no scopes.
47+
NoScope = 0,
48+
4649
/// This indicates that the scope corresponds to a function, which
4750
/// means that labels are set here.
4851
FnScope = 0x01,
@@ -521,10 +524,17 @@ class Scope {
521524
return getFlags() & Scope::OpenACCComputeConstructScope;
522525
}
523526

524-
bool isInOpenACCComputeConstructScope() const {
527+
/// Determine if this scope (or its parents) are a compute construct. If the
528+
/// argument is provided, the search will stop at any of the specified scopes.
529+
/// Otherwise, it will stop only at the normal 'no longer search' scopes.
530+
bool isInOpenACCComputeConstructScope(ScopeFlags Flags = NoScope) const {
525531
for (const Scope *S = this; S; S = S->getParent()) {
526-
if (S->getFlags() & Scope::OpenACCComputeConstructScope)
532+
if (S->isOpenACCComputeConstructScope())
527533
return true;
534+
535+
if (S->getFlags() & Flags)
536+
return false;
537+
528538
else if (S->getFlags() &
529539
(Scope::FnScope | Scope::ClassScope | Scope::BlockScope |
530540
Scope::TemplateParamScope | Scope::FunctionPrototypeScope |
@@ -534,25 +544,6 @@ class Scope {
534544
return false;
535545
}
536546

537-
/// Determine if this scope (or its parents) are a compute construct inside of
538-
/// the nearest 'switch' scope. This is needed to check whether we are inside
539-
/// of a 'duffs' device, which is an illegal branch into a compute construct.
540-
bool isInOpenACCComputeConstructBeforeSwitch() const {
541-
for (const Scope *S = this; S; S = S->getParent()) {
542-
if (S->getFlags() & Scope::OpenACCComputeConstructScope)
543-
return true;
544-
if (S->getFlags() & Scope::SwitchScope)
545-
return false;
546-
547-
if (S->getFlags() &
548-
(Scope::FnScope | Scope::ClassScope | Scope::BlockScope |
549-
Scope::TemplateParamScope | Scope::FunctionPrototypeScope |
550-
Scope::AtCatchScope | Scope::ObjCMethodScope))
551-
return false;
552-
}
553-
return false;
554-
}
555-
556547
/// Determine whether this scope is a while/do/for statement, which can have
557548
/// continue statements embedded into it.
558549
bool isContinueScope() const {

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,12 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
890890
if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
891891
Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";
892892

893+
// Exceptions that escape a compute construct are ill-formed.
894+
if (getLangOpts().OpenACC && getCurScope() &&
895+
getCurScope()->isInOpenACCComputeConstructScope(Scope::TryScope))
896+
Diag(OpLoc, diag::err_acc_branch_in_out_compute_construct)
897+
<< /*throw*/ 2 << /*out of*/ 0;
898+
893899
if (Ex && !Ex->isTypeDependent()) {
894900
// Initialize the exception result. This implicitly weeds out
895901
// abstract types or types with inaccessible copy constructors.

clang/lib/Sema/SemaStmt.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprResult LHSVal,
528528
}
529529

530530
if (LangOpts.OpenACC &&
531-
getCurScope()->isInOpenACCComputeConstructBeforeSwitch()) {
531+
getCurScope()->isInOpenACCComputeConstructScope(Scope::SwitchScope)) {
532532
Diag(CaseLoc, diag::err_acc_branch_in_out_compute_construct)
533533
<< /*branch*/ 0 << /*into*/ 1;
534534
return StmtError();
@@ -554,7 +554,7 @@ Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
554554
}
555555

556556
if (LangOpts.OpenACC &&
557-
getCurScope()->isInOpenACCComputeConstructBeforeSwitch()) {
557+
getCurScope()->isInOpenACCComputeConstructScope(Scope::SwitchScope)) {
558558
Diag(DefaultLoc, diag::err_acc_branch_in_out_compute_construct)
559559
<< /*branch*/ 0 << /*into*/ 1;
560560
return StmtError();

clang/test/SemaOpenACC/no-branch-in-out.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,66 @@ void DuffsDevice() {
136136
}
137137
}
138138

139+
void Exceptions() {
140+
#pragma acc parallel
141+
for(int i = 0; i < 5; ++i) {
142+
throw 5; // expected-error{{invalid throw out of OpenACC Compute Construct}}
143+
}
144+
145+
#pragma acc parallel
146+
for(int i = 0; i < 5; ++i) {
147+
throw; // expected-error{{invalid throw out of OpenACC Compute Construct}}
148+
}
149+
150+
#pragma acc parallel
151+
for(int i = 0; i < 5; ++i) {
152+
try {
153+
throw 5;
154+
} catch(float f) {
155+
}
156+
}
157+
158+
#pragma acc parallel
159+
for(int i = 0; i < 5; ++i) {
160+
try {
161+
throw 5;
162+
} catch(int f) {
163+
}
164+
}
165+
166+
#pragma acc parallel
167+
for(int i = 0; i < 5; ++i) {
168+
try {
169+
throw 5;
170+
} catch(...) {
171+
}
172+
}
173+
#pragma acc parallel
174+
for(int i = 0; i < 5; ++i) {
175+
try {
176+
throw;
177+
} catch(...) {
178+
}
179+
}
180+
181+
#pragma acc parallel
182+
for(int i = 0; i < 5; ++i) {
183+
try {
184+
throw;
185+
} catch(...) {
186+
throw; // expected-error{{invalid throw out of OpenACC Compute Construct}}
187+
}
188+
}
189+
#pragma acc parallel
190+
for(int i = 0; i < 5; ++i) {
191+
try {
192+
throw;
193+
} catch(int f) {
194+
throw; // expected-error{{invalid throw out of OpenACC Compute Construct}}
195+
}
196+
}
197+
}
198+
139199
void Instantiate() {
140200
BreakContinue<int>();
141201
DuffsDevice<int>();

0 commit comments

Comments
 (0)