Skip to content

Commit adeff9f

Browse files
authoredJan 3, 2025
[flang][OpenMP] Allow utility constructs in specification part (#121509)
Allow utility constructs (error and nothing) to appear in the specification part as well as the execution part. The exception is "ERROR AT(EXECUTION)" which should only be in the execution part. In case of ambiguity (the boundary between the specification and the execution part), utility constructs will be parsed as belonging to the specification part. In such cases move them to the execution part in the OpenMP canonicalization code.
1 parent a4d9240 commit adeff9f

File tree

11 files changed

+365
-75
lines changed

11 files changed

+365
-75
lines changed
 

‎flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,16 @@ std::string OpenMPCounterVisitor::getName(const OmpWrapperType &w) {
106106
return getName(*std::get<const OpenMPDeclarativeConstruct *>(w));
107107
}
108108
std::string OpenMPCounterVisitor::getName(const OpenMPDeclarativeConstruct &c) {
109-
return std::visit(
110-
[&](const auto &o) -> std::string {
111-
const CharBlock &source{std::get<Verbatim>(o.t).source};
112-
return normalize_construct_name(source.ToString());
109+
return std::visit( //
110+
Fortran::common::visitors{
111+
[&](const OpenMPUtilityConstruct &o) -> std::string {
112+
const CharBlock &source{o.source};
113+
return normalize_construct_name(source.ToString());
114+
},
115+
[&](const auto &o) -> std::string {
116+
const CharBlock &source{std::get<Verbatim>(o.t).source};
117+
return normalize_construct_name(source.ToString());
118+
},
113119
},
114120
c.u);
115121
}

‎flang/include/flang/Parser/parse-tree.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -4342,7 +4342,7 @@ struct OpenMPDeclarativeConstruct {
43424342
std::variant<OpenMPDeclarativeAllocate, OpenMPDeclareMapperConstruct,
43434343
OpenMPDeclareReductionConstruct, OpenMPDeclareSimdConstruct,
43444344
OpenMPDeclareTargetConstruct, OpenMPThreadprivate,
4345-
OpenMPRequiresConstruct>
4345+
OpenMPRequiresConstruct, OpenMPUtilityConstruct>
43464346
u;
43474347
};
43484348

‎flang/lib/Lower/OpenMP/OpenMP.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -2586,6 +2586,10 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
25862586
//===----------------------------------------------------------------------===//
25872587
// OpenMPDeclarativeConstruct visitors
25882588
//===----------------------------------------------------------------------===//
2589+
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
2590+
semantics::SemanticsContext &semaCtx,
2591+
lower::pft::Evaluation &eval,
2592+
const parser::OpenMPUtilityConstruct &);
25892593

25902594
static void
25912595
genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,

‎flang/lib/Parser/openmp-parsers.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,9 @@ TYPE_PARSER(startOmpLine >>
10901090
construct<OpenMPDeclarativeConstruct>(
10911091
Parser<OpenMPRequiresConstruct>{}) ||
10921092
construct<OpenMPDeclarativeConstruct>(
1093-
Parser<OpenMPThreadprivate>{})) /
1093+
Parser<OpenMPThreadprivate>{}) ||
1094+
construct<OpenMPDeclarativeConstruct>(
1095+
Parser<OpenMPUtilityConstruct>{})) /
10941096
endOmpLine))
10951097

10961098
// Block Construct

‎flang/lib/Parser/unparse.cpp

+42-59
Original file line numberDiff line numberDiff line change
@@ -2631,81 +2631,64 @@ class UnparseVisitor {
26312631
}
26322632
}
26332633
void Unparse(const OpenMPDeclareReductionConstruct &x) {
2634+
BeginOpenMP();
2635+
Word("!$OMP DECLARE REDUCTION ");
26342636
Put("(");
26352637
Walk(std::get<OmpReductionIdentifier>(x.t)), Put(" : ");
26362638
Walk(std::get<std::list<DeclarationTypeSpec>>(x.t), ","), Put(" : ");
26372639
Walk(std::get<OmpReductionCombiner>(x.t));
26382640
Put(")");
26392641
Walk(std::get<std::optional<OmpReductionInitializerClause>>(x.t));
2642+
EndOpenMP();
26402643
}
2641-
bool Pre(const OpenMPDeclarativeConstruct &x) {
2644+
2645+
void Unparse(const OpenMPDeclareMapperConstruct &z) {
26422646
BeginOpenMP();
2643-
Word("!$OMP ");
2644-
return common::visit(
2645-
common::visitors{
2646-
[&](const OpenMPDeclarativeAllocate &z) {
2647-
Word("ALLOCATE (");
2648-
Walk(std::get<OmpObjectList>(z.t));
2649-
Put(")");
2650-
Walk(std::get<OmpClauseList>(z.t));
2651-
Put("\n");
2652-
EndOpenMP();
2653-
return false;
2654-
},
2655-
[&](const OpenMPDeclareMapperConstruct &z) {
2656-
Word("DECLARE MAPPER (");
2657-
const auto &spec{std::get<OmpDeclareMapperSpecifier>(z.t)};
2658-
if (auto mapname{std::get<std::optional<Name>>(spec.t)}) {
2659-
Walk(mapname);
2660-
Put(":");
2661-
}
2662-
Walk(std::get<TypeSpec>(spec.t));
2663-
Put("::");
2664-
Walk(std::get<Name>(spec.t));
2665-
Put(")");
2647+
Word("!$OMP DECLARE MAPPER (");
2648+
const auto &spec{std::get<OmpDeclareMapperSpecifier>(z.t)};
2649+
if (auto mapname{std::get<std::optional<Name>>(spec.t)}) {
2650+
Walk(mapname);
2651+
Put(":");
2652+
}
2653+
Walk(std::get<TypeSpec>(spec.t));
2654+
Put("::");
2655+
Walk(std::get<Name>(spec.t));
2656+
Put(")");
26662657

2667-
Walk(std::get<OmpClauseList>(z.t));
2668-
Put("\n");
2669-
return false;
2670-
},
2671-
[&](const OpenMPDeclareReductionConstruct &) {
2672-
Word("DECLARE REDUCTION ");
2673-
return true;
2674-
},
2675-
[&](const OpenMPDeclareSimdConstruct &y) {
2676-
Word("DECLARE SIMD ");
2677-
Walk("(", std::get<std::optional<Name>>(y.t), ")");
2678-
Walk(std::get<OmpClauseList>(y.t));
2679-
Put("\n");
2680-
EndOpenMP();
2681-
return false;
2682-
},
2683-
[&](const OpenMPDeclareTargetConstruct &) {
2684-
Word("DECLARE TARGET ");
2685-
return true;
2686-
},
2687-
[&](const OpenMPRequiresConstruct &y) {
2688-
Word("REQUIRES ");
2689-
Walk(std::get<OmpClauseList>(y.t));
2690-
Put("\n");
2691-
EndOpenMP();
2692-
return false;
2693-
},
2694-
[&](const OpenMPThreadprivate &) {
2695-
Word("THREADPRIVATE (");
2696-
return true;
2697-
},
2698-
},
2699-
x.u);
2658+
Walk(std::get<OmpClauseList>(z.t));
2659+
Put("\n");
2660+
EndOpenMP();
2661+
}
2662+
void Unparse(const OpenMPDeclareSimdConstruct &y) {
2663+
BeginOpenMP();
2664+
Word("!$OMP DECLARE SIMD ");
2665+
Walk("(", std::get<std::optional<Name>>(y.t), ")");
2666+
Walk(std::get<OmpClauseList>(y.t));
2667+
Put("\n");
2668+
EndOpenMP();
27002669
}
2701-
void Post(const OpenMPDeclarativeConstruct &) {
2670+
void Unparse(const OpenMPDeclareTargetConstruct &x) {
2671+
BeginOpenMP();
2672+
Word("!$OMP DECLARE TARGET ");
2673+
Walk(std::get<parser::OmpDeclareTargetSpecifier>(x.t));
27022674
Put("\n");
27032675
EndOpenMP();
27042676
}
2705-
void Post(const OpenMPThreadprivate &) {
2677+
void Unparse(const OpenMPRequiresConstruct &y) {
2678+
BeginOpenMP();
2679+
Word("!$OMP REQUIRES ");
2680+
Walk(std::get<OmpClauseList>(y.t));
2681+
Put("\n");
2682+
EndOpenMP();
2683+
}
2684+
void Unparse(const OpenMPThreadprivate &x) {
2685+
BeginOpenMP();
2686+
Word("!$OMP THREADPRIVATE (");
2687+
Walk(std::get<parser::OmpObjectList>(x.t));
27062688
Put(")\n");
27072689
EndOpenMP();
27082690
}
2691+
27092692
bool Pre(const OmpMessageClause &x) {
27102693
Walk(x.v);
27112694
return false;

‎flang/lib/Semantics/canonicalize-omp.cpp

+162
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,43 @@ class CanonicalizationOfOmp {
5050

5151
void Post(parser::ExecutionPart &body) { RewriteOmpAllocations(body); }
5252

53+
// Pre-visit all constructs that have both a specification part and
54+
// an execution part, and store the connection between the two.
55+
bool Pre(parser::BlockConstruct &x) {
56+
auto *spec = &std::get<parser::BlockSpecificationPart>(x.t).v;
57+
auto *block = &std::get<parser::Block>(x.t);
58+
blockForSpec_.insert(std::make_pair(spec, block));
59+
return true;
60+
}
61+
bool Pre(parser::MainProgram &x) {
62+
auto *spec = &std::get<parser::SpecificationPart>(x.t);
63+
auto *block = &std::get<parser::ExecutionPart>(x.t).v;
64+
blockForSpec_.insert(std::make_pair(spec, block));
65+
return true;
66+
}
67+
bool Pre(parser::FunctionSubprogram &x) {
68+
auto *spec = &std::get<parser::SpecificationPart>(x.t);
69+
auto *block = &std::get<parser::ExecutionPart>(x.t).v;
70+
blockForSpec_.insert(std::make_pair(spec, block));
71+
return true;
72+
}
73+
bool Pre(parser::SubroutineSubprogram &x) {
74+
auto *spec = &std::get<parser::SpecificationPart>(x.t);
75+
auto *block = &std::get<parser::ExecutionPart>(x.t).v;
76+
blockForSpec_.insert(std::make_pair(spec, block));
77+
return true;
78+
}
79+
bool Pre(parser::SeparateModuleSubprogram &x) {
80+
auto *spec = &std::get<parser::SpecificationPart>(x.t);
81+
auto *block = &std::get<parser::ExecutionPart>(x.t).v;
82+
blockForSpec_.insert(std::make_pair(spec, block));
83+
return true;
84+
}
85+
86+
void Post(parser::SpecificationPart &spec) {
87+
CanonicalizeUtilityConstructs(spec);
88+
}
89+
5390
private:
5491
template <typename T> T *GetConstructIf(parser::ExecutionPartConstruct &x) {
5592
if (auto *y{std::get_if<parser::ExecutableConstruct>(&x.u)}) {
@@ -155,6 +192,131 @@ class CanonicalizationOfOmp {
155192
}
156193
}
157194

195+
// Canonicalization of utility constructs.
196+
//
197+
// This addresses the issue of utility constructs that appear at the
198+
// boundary between the specification and the execution parts, e.g.
199+
// subroutine foo
200+
// integer :: x ! Specification
201+
// !$omp nothing
202+
// x = 1 ! Execution
203+
// ...
204+
// end
205+
//
206+
// Utility constructs (error and nothing) can appear in both the
207+
// specification part and the execution part, except "error at(execution)",
208+
// which cannot be present in the specification part (whereas any utility
209+
// construct can be in the execution part).
210+
// When a utility construct is at the boundary, it should preferably be
211+
// parsed as an element of the execution part, but since the specification
212+
// part is parsed first, the utility construct ends up belonging to the
213+
// specification part.
214+
//
215+
// To allow the likes of the following code to compile, move all utility
216+
// construct that are at the end of the specification part to the beginning
217+
// of the execution part.
218+
//
219+
// subroutine foo
220+
// !$omp error at(execution) ! Initially parsed as declarative construct.
221+
// ! Move it to the execution part.
222+
// end
223+
224+
void CanonicalizeUtilityConstructs(parser::SpecificationPart &spec) {
225+
auto found = blockForSpec_.find(&spec);
226+
if (found == blockForSpec_.end()) {
227+
// There is no corresponding execution part, so there is nothing to do.
228+
return;
229+
}
230+
parser::Block &block = *found->second;
231+
232+
// There are two places where an OpenMP declarative construct can
233+
// show up in the tuple in specification part:
234+
// (1) in std::list<OpenMPDeclarativeConstruct>, or
235+
// (2) in std::list<DeclarationConstruct>.
236+
// The case (1) is only possible is the list (2) is empty.
237+
238+
auto &omps =
239+
std::get<std::list<parser::OpenMPDeclarativeConstruct>>(spec.t);
240+
auto &decls = std::get<std::list<parser::DeclarationConstruct>>(spec.t);
241+
242+
if (!decls.empty()) {
243+
MoveUtilityConstructsFromDecls(decls, block);
244+
} else {
245+
MoveUtilityConstructsFromOmps(omps, block);
246+
}
247+
}
248+
249+
void MoveUtilityConstructsFromDecls(
250+
std::list<parser::DeclarationConstruct> &decls, parser::Block &block) {
251+
// Find the trailing range of DeclarationConstructs that are OpenMP
252+
// utility construct, that are to be moved to the execution part.
253+
std::list<parser::DeclarationConstruct>::reverse_iterator rlast = [&]() {
254+
for (auto rit = decls.rbegin(), rend = decls.rend(); rit != rend; ++rit) {
255+
parser::DeclarationConstruct &dc = *rit;
256+
if (!std::holds_alternative<parser::SpecificationConstruct>(dc.u)) {
257+
return rit;
258+
}
259+
auto &sc = std::get<parser::SpecificationConstruct>(dc.u);
260+
using OpenMPDeclarativeConstruct =
261+
common::Indirection<parser::OpenMPDeclarativeConstruct>;
262+
if (!std::holds_alternative<OpenMPDeclarativeConstruct>(sc.u)) {
263+
return rit;
264+
}
265+
// Got OpenMPDeclarativeConstruct. If it's not a utility construct
266+
// then stop.
267+
auto &odc = std::get<OpenMPDeclarativeConstruct>(sc.u).value();
268+
if (!std::holds_alternative<parser::OpenMPUtilityConstruct>(odc.u)) {
269+
return rit;
270+
}
271+
}
272+
return decls.rend();
273+
}();
274+
275+
std::transform(decls.rbegin(), rlast, std::front_inserter(block),
276+
[](parser::DeclarationConstruct &dc) {
277+
auto &sc = std::get<parser::SpecificationConstruct>(dc.u);
278+
using OpenMPDeclarativeConstruct =
279+
common::Indirection<parser::OpenMPDeclarativeConstruct>;
280+
auto &oc = std::get<OpenMPDeclarativeConstruct>(sc.u).value();
281+
auto &ut = std::get<parser::OpenMPUtilityConstruct>(oc.u);
282+
283+
return parser::ExecutionPartConstruct(parser::ExecutableConstruct(
284+
common::Indirection(parser::OpenMPConstruct(std::move(ut)))));
285+
});
286+
287+
decls.erase(rlast.base(), decls.end());
288+
}
289+
290+
void MoveUtilityConstructsFromOmps(
291+
std::list<parser::OpenMPDeclarativeConstruct> &omps,
292+
parser::Block &block) {
293+
using OpenMPDeclarativeConstruct = parser::OpenMPDeclarativeConstruct;
294+
// Find the trailing range of OpenMPDeclarativeConstruct that are OpenMP
295+
// utility construct, that are to be moved to the execution part.
296+
std::list<OpenMPDeclarativeConstruct>::reverse_iterator rlast = [&]() {
297+
for (auto rit = omps.rbegin(), rend = omps.rend(); rit != rend; ++rit) {
298+
OpenMPDeclarativeConstruct &dc = *rit;
299+
if (!std::holds_alternative<parser::OpenMPUtilityConstruct>(dc.u)) {
300+
return rit;
301+
}
302+
}
303+
return omps.rend();
304+
}();
305+
306+
std::transform(omps.rbegin(), rlast, std::front_inserter(block),
307+
[](parser::OpenMPDeclarativeConstruct &dc) {
308+
auto &ut = std::get<parser::OpenMPUtilityConstruct>(dc.u);
309+
return parser::ExecutionPartConstruct(parser::ExecutableConstruct(
310+
common::Indirection(parser::OpenMPConstruct(std::move(ut)))));
311+
});
312+
313+
omps.erase(rlast.base(), omps.end());
314+
}
315+
316+
// Mapping from the specification parts to the blocks that follow in the
317+
// same construct. This is for converting utility constructs to executable
318+
// constructs.
319+
std::map<parser::SpecificationPart *, parser::Block *> blockForSpec_;
158320
parser::Messages &messages_;
159321
};
160322

‎flang/lib/Semantics/check-omp-structure.cpp

+18-1
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,14 @@ void OmpStructureChecker::Leave(const parser::OpenMPConstruct &) {
614614
deferredNonVariables_.clear();
615615
}
616616

617+
void OmpStructureChecker::Enter(const parser::OpenMPDeclarativeConstruct &x) {
618+
EnterDirectiveNest(DeclarativeNest);
619+
}
620+
621+
void OmpStructureChecker::Leave(const parser::OpenMPDeclarativeConstruct &x) {
622+
ExitDirectiveNest(DeclarativeNest);
623+
}
624+
617625
void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
618626
loopStack_.push_back(&x);
619627
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
@@ -1697,6 +1705,16 @@ void OmpStructureChecker::Leave(const parser::OmpErrorDirective &x) {
16971705
dirContext_.pop_back();
16981706
}
16991707

1708+
void OmpStructureChecker::Enter(const parser::OmpClause::At &x) {
1709+
CheckAllowedClause(llvm::omp::Clause::OMPC_at);
1710+
if (GetDirectiveNest(DeclarativeNest) > 0) {
1711+
if (x.v.v == parser::OmpAtClause::ActionTime::Execution) {
1712+
context_.Say(GetContext().clauseSource,
1713+
"The ERROR directive with AT(EXECUTION) cannot appear in the specification part"_err_en_US);
1714+
}
1715+
}
1716+
}
1717+
17001718
void OmpStructureChecker::Enter(const parser::OpenMPExecutableAllocate &x) {
17011719
isPredefinedAllocator = true;
17021720
const auto &dir{std::get<parser::Verbatim>(x.t)};
@@ -2856,7 +2874,6 @@ CHECK_SIMPLE_CLAUSE(Init, OMPC_init)
28562874
CHECK_SIMPLE_CLAUSE(Use, OMPC_use)
28572875
CHECK_SIMPLE_CLAUSE(Novariants, OMPC_novariants)
28582876
CHECK_SIMPLE_CLAUSE(Nocontext, OMPC_nocontext)
2859-
CHECK_SIMPLE_CLAUSE(At, OMPC_at)
28602877
CHECK_SIMPLE_CLAUSE(Severity, OMPC_severity)
28612878
CHECK_SIMPLE_CLAUSE(Message, OMPC_message)
28622879
CHECK_SIMPLE_CLAUSE(Filter, OMPC_filter)

‎flang/lib/Semantics/check-omp-structure.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ class OmpStructureChecker
7373

7474
void Enter(const parser::OpenMPConstruct &);
7575
void Leave(const parser::OpenMPConstruct &);
76+
void Enter(const parser::OpenMPDeclarativeConstruct &);
77+
void Leave(const parser::OpenMPDeclarativeConstruct &);
78+
7679
void Enter(const parser::OpenMPLoopConstruct &);
7780
void Leave(const parser::OpenMPLoopConstruct &);
7881
void Enter(const parser::OmpEndLoopDirective &);
@@ -270,11 +273,12 @@ class OmpStructureChecker
270273
const parser::Variable &, const parser::Expr &);
271274
inline void ErrIfNonScalarAssignmentStmt(
272275
const parser::Variable &, const parser::Expr &);
273-
enum directiveNestType {
276+
enum directiveNestType : int {
274277
SIMDNest,
275278
TargetBlockOnlyTeams,
276279
TargetNest,
277-
LastType
280+
DeclarativeNest,
281+
LastType = DeclarativeNest,
278282
};
279283
int directiveNest_[LastType + 1] = {0};
280284

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
1-
! RUN: %flang_fc1 -fopenmp-version=51 -fopenmp -fdebug-unparse-no-sema %s 2>&1 | FileCheck %s
2-
! RUN: %flang_fc1 -fopenmp-version=51 -fopenmp -fdebug-dump-parse-tree-no-sema %s 2>&1 | FileCheck %s --check-prefix="PARSE-TREE"
1+
! RUN: %flang_fc1 -fopenmp-version=51 -fopenmp -fdebug-unparse %s 2>&1 | FileCheck %s
2+
! RUN: %flang_fc1 -fopenmp-version=51 -fopenmp -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s --check-prefix="PARSE-TREE"
33
program main
44
character(*), parameter :: message = "This is an error"
55
!CHECK: !$OMP ERROR AT(COMPILATION) SEVERITY(WARNING) MESSAGE("some message here")
66
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPUtilityConstruct -> OmpErrorDirective
77
!PARSE-TREE: OmpClauseList -> OmpClause -> At -> OmpAtClause -> ActionTime = Compilation
88
!PARSE-TREE: OmpClause -> Severity -> OmpSeverityClause -> Severity = Warning
9-
!PARSE-TREE: OmpClause -> Message -> OmpMessageClause -> Expr -> LiteralConstant -> CharLiteralConstant
9+
!PARSE-TREE: OmpClause -> Message -> OmpMessageClause -> Expr = '"some message here"'
10+
!PARSE-TREE: LiteralConstant -> CharLiteralConstant
11+
!PARSE-TREE: string = 'some message here'
1012
!$omp error at(compilation) severity(warning) message("some message here")
11-
!CHECK: !$OMP ERROR AT(COMPILATION) SEVERITY(FATAL) MESSAGE(message)
13+
!CHECK: !$OMP ERROR AT(COMPILATION) SEVERITY(FATAL) MESSAGE("This is an error")
1214
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPUtilityConstruct -> OmpErrorDirective
1315
!PARSE-TREE: OmpClauseList -> OmpClause -> At -> OmpAtClause -> ActionTime = Compilation
1416
!PARSE-TREE: OmpClause -> Severity -> OmpSeverityClause -> Severity = Fatal
15-
!PARSE-TREE: OmpClause -> Message -> OmpMessageClause -> Expr -> Designator -> DataRef -> Name = 'message'
17+
!PARSE-TREE: OmpClause -> Message -> OmpMessageClause -> Expr = '"This is an error"'
18+
!PARSE-TREE: Designator -> DataRef -> Name = 'message'
1619
!$omp error at(compilation) severity(fatal) message(message)
17-
!CHECK: !$OMP ERROR AT(EXECUTION) SEVERITY(FATAL) MESSAGE(message)
20+
!CHECK: !$OMP ERROR AT(EXECUTION) SEVERITY(FATAL) MESSAGE("This is an error")
1821
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPUtilityConstruct -> OmpErrorDirective
1922
!PARSE-TREE: OmpClauseList -> OmpClause -> At -> OmpAtClause -> ActionTime = Execution
2023
!PARSE-TREE: OmpClause -> Severity -> OmpSeverityClause -> Severity = Fatal
21-
!PARSE-TREE: OmpClause -> Message -> OmpMessageClause -> Expr -> Designator -> DataRef -> Name = 'message'
24+
!PARSE-TREE: OmpClause -> Message -> OmpMessageClause -> Expr = '"This is an error"'
25+
!PARSE-TREE: Designator -> DataRef -> Name = 'message'
2226
!$omp error at(EXECUTION) severity(fatal) message(message)
2327
end program main

‎flang/test/Parser/OpenMP/nothing.f90

+100
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,103 @@ subroutine f00
1111

1212
!PARSE-TREE: ExecutionPart -> Block
1313
!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPUtilityConstruct -> OmpNothingDirective
14+
15+
subroutine f01
16+
block
17+
import, none
18+
integer :: x
19+
!$omp nothing ! "nothing" in the execution part
20+
x = x+1
21+
end block
22+
end
23+
24+
!UNPARSE: SUBROUTINE f01
25+
!UNPARSE: BLOCK
26+
!UNPARSE: IMPORT, NONE
27+
!UNPARSE: INTEGER x
28+
!UNPARSE: !$OMP NOTHING
29+
!UNPARSE: x=x+1_4
30+
!UNPARSE: END BLOCK
31+
!UNPARSE: END SUBROUTINE
32+
33+
!PARSE-TREE: BlockStmt ->
34+
!PARSE-TREE: BlockSpecificationPart -> SpecificationPart
35+
!PARSE-TREE: | ImportStmt
36+
!PARSE-TREE: | ImplicitPart ->
37+
!PARSE-TREE: | DeclarationConstruct -> SpecificationConstruct -> TypeDeclarationStmt
38+
!PARSE-TREE: | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec ->
39+
!PARSE-TREE: | | EntityDecl
40+
!PARSE-TREE: | | | Name = 'x'
41+
!PARSE-TREE: Block
42+
!PARSE-TREE: | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPUtilityConstruct -> OmpNothingDirective
43+
!PARSE-TREE: | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'x=x+1_4'
44+
!PARSE-TREE: | | Variable = 'x'
45+
!PARSE-TREE: | | | Designator -> DataRef -> Name = 'x'
46+
!PARSE-TREE: | | Expr = 'x+1_4'
47+
!PARSE-TREE: | | | Add
48+
!PARSE-TREE: | | | | Expr = 'x'
49+
!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'x'
50+
!PARSE-TREE: | | | | Expr = '1_4'
51+
!PARSE-TREE: | | | | | LiteralConstant -> IntLiteralConstant = '1'
52+
!PARSE-TREE: EndBlockStmt ->
53+
54+
subroutine f02
55+
integer :: x
56+
!$omp nothing
57+
end
58+
59+
!UNPARSE: SUBROUTINE f02
60+
!UNPARSE: INTEGER x
61+
!UNPARSE: !$OMP NOTHING
62+
!UNPARSE: END SUBROUTINE
63+
64+
!PARSE-TREE: SpecificationPart
65+
!PARSE-TREE: | ImplicitPart ->
66+
!PARSE-TREE: | DeclarationConstruct -> SpecificationConstruct -> TypeDeclarationStmt
67+
!PARSE-TREE: | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec ->
68+
!PARSE-TREE: | | EntityDecl
69+
!PARSE-TREE: | | | Name = 'x'
70+
!PARSE-TREE: ExecutionPart -> Block
71+
!PARSE-TREE: | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPUtilityConstruct -> OmpNothingDirective
72+
73+
subroutine f03
74+
block
75+
!$omp nothing ! "nothing" in the specification part
76+
import, none
77+
integer :: x
78+
x = x+1
79+
end block
80+
end
81+
82+
!UNPARSE: SUBROUTINE f03
83+
!UNPARSE: BLOCK
84+
!UNPARSE: !$OMP NOTHING
85+
!UNPARSE: IMPORT, NONE
86+
!UNPARSE: INTEGER x
87+
!UNPARSE: x=x+1_4
88+
!UNPARSE: END BLOCK
89+
!UNPARSE: END SUBROUTINE
90+
91+
!PARSE-TREE: ExecutionPart -> Block
92+
!PARSE-TREE: | ExecutionPartConstruct -> ExecutableConstruct -> BlockConstruct
93+
!PARSE-TREE: | | BlockStmt ->
94+
!PARSE-TREE: | | BlockSpecificationPart -> SpecificationPart
95+
!PARSE-TREE: | | | OpenMPDeclarativeConstruct -> OpenMPUtilityConstruct -> OmpNothingDirective
96+
!PARSE-TREE: | | | ImportStmt
97+
!PARSE-TREE: | | | ImplicitPart ->
98+
!PARSE-TREE: | | | DeclarationConstruct -> SpecificationConstruct -> TypeDeclarationStmt
99+
!PARSE-TREE: | | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec ->
100+
!PARSE-TREE: | | | | EntityDecl
101+
!PARSE-TREE: | | | | | Name = 'x'
102+
!PARSE-TREE: | | Block
103+
!PARSE-TREE: | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'x=x+1_4'
104+
!PARSE-TREE: | | | | Variable = 'x'
105+
!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'x'
106+
!PARSE-TREE: | | | | Expr = 'x+1_4'
107+
!PARSE-TREE: | | | | | Add
108+
!PARSE-TREE: | | | | | | Expr = 'x'
109+
!PARSE-TREE: | | | | | | | Designator -> DataRef -> Name = 'x'
110+
!PARSE-TREE: | | | | | | Expr = '1_4'
111+
!PARSE-TREE: | | | | | | | LiteralConstant -> IntLiteralConstant = '1'
112+
!PARSE-TREE: | | EndBlockStmt ->
113+
!PARSE-TREE: EndSubroutineStmt ->

‎flang/test/Semantics/OpenMP/error.f90

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=51
2+
3+
subroutine f00(x)
4+
!ERROR: The ERROR directive with AT(EXECUTION) cannot appear in the specification part
5+
!$omp error at(execution) message("Haaa!")
6+
integer :: x
7+
end
8+

0 commit comments

Comments
 (0)
Please sign in to comment.