FLANG
check-omp-structure.h
1//===-- lib/Semantics/check-omp-structure.h ---------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// OpenMP structure validity check list
10// 1. invalid clauses on directive
11// 2. invalid repeated clauses on directive
12// 3. TODO: invalid nesting of regions
13
14#ifndef FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
15#define FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
16
17#include "check-directive-structure.h"
18#include "flang/Common/enum-set.h"
19#include "flang/Parser/parse-tree.h"
20#include "flang/Semantics/openmp-directive-sets.h"
21#include "flang/Semantics/semantics.h"
22#include "llvm/ADT/SmallVector.h"
23#include "llvm/ADT/iterator_range.h"
24
25using OmpClauseSet =
27
28#define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
29#include "llvm/Frontend/OpenMP/OMP.inc"
30
31namespace llvm {
32namespace omp {
33static OmpClauseSet privateSet{
34 Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate};
35static OmpClauseSet privateReductionSet{
36 OmpClauseSet{Clause::OMPC_reduction} | privateSet};
37} // namespace omp
38} // namespace llvm
39
40namespace Fortran::semantics {
41struct AnalyzedCondStmt;
42
43namespace omp {
44struct LoopSequence;
45}
46
47// Mapping from 'Symbol' to 'Source' to keep track of the variables
48// used in multiple clauses
49using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>;
50// Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause>
51using DirectivesClauseTriple = std::multimap<llvm::omp::Directive,
52 std::pair<llvm::omp::Directive, const OmpClauseSet>>;
53
54using OmpStructureCheckerBase = DirectiveStructureChecker<llvm::omp::Directive,
55 llvm::omp::Clause, parser::OmpClause, llvm::omp::Clause_enumSize>;
56
57class OmpStructureChecker : public OmpStructureCheckerBase {
58public:
59 using Base = OmpStructureCheckerBase;
60
61 OmpStructureChecker(SemanticsContext &context);
62
63 void Enter(const parser::ProgramUnit &);
64 void Leave(const parser::ProgramUnit &);
65 void Enter(const parser::MainProgram &);
66 void Leave(const parser::MainProgram &);
67 void Enter(const parser::BlockData &);
68 void Leave(const parser::BlockData &);
69 void Enter(const parser::Module &);
70 void Leave(const parser::Module &);
71 void Enter(const parser::Submodule &);
72 void Leave(const parser::Submodule &);
73 void Enter(const parser::SubroutineStmt &);
74 void Enter(const parser::EndSubroutineStmt &);
75 void Enter(const parser::FunctionStmt &);
76 void Enter(const parser::EndFunctionStmt &);
77 void Enter(const parser::MpSubprogramStmt &);
78 void Enter(const parser::EndMpSubprogramStmt &);
79 void Enter(const parser::Block &);
80 void Leave(const parser::Block &);
81 void Enter(const parser::BlockConstruct &);
82 void Leave(const parser::BlockConstruct &);
83 void Enter(const parser::InternalSubprogram &);
84 void Enter(const parser::ModuleSubprogram &);
85 void Enter(const parser::ModuleSubprogramPart &);
86 void Enter(const parser::InterfaceBody &);
87 void Leave(const parser::InterfaceBody &);
88
89 void Enter(const parser::SpecificationPart &);
90 void Leave(const parser::SpecificationPart &);
91 void Enter(const parser::ExecutionPart &);
92 void Leave(const parser::ExecutionPart &);
93
94 void Enter(const parser::OpenMPConstruct &);
95 void Leave(const parser::OpenMPConstruct &);
96 void Enter(const parser::OpenMPDeclarativeConstruct &);
97 void Leave(const parser::OpenMPDeclarativeConstruct &);
98
99 void Enter(const parser::OpenMPMisplacedEndDirective &);
100 void Leave(const parser::OpenMPMisplacedEndDirective &);
101 void Enter(const parser::OpenMPInvalidDirective &);
102 void Leave(const parser::OpenMPInvalidDirective &);
103
104 void Enter(const parser::OpenMPLoopConstruct &);
105 void Leave(const parser::OpenMPLoopConstruct &);
106
107 void Enter(const parser::OpenMPInteropConstruct &);
108 void Enter(const parser::OmpBlockConstruct &);
109 void Leave(const parser::OmpBlockConstruct &);
110 void Enter(const parser::OmpBeginDirective &);
111 void Leave(const parser::OmpBeginDirective &);
112
113 void Enter(const parser::OpenMPSectionsConstruct &);
114
115 void Enter(const parser::OmpDeclareVariantDirective &);
116 void Enter(const parser::OmpDeclareSimdDirective &);
117 void Enter(const parser::OmpAllocateDirective &);
118 void Leave(const parser::OmpAllocateDirective &);
119 void Enter(const parser::OmpDeclareMapperDirective &);
120 void Enter(const parser::OmpDeclareReductionDirective &);
121 void Enter(const parser::OmpDeclareTargetDirective &);
122 void Leave(const parser::OmpDeclareTargetDirective &);
123 void Enter(const parser::OpenMPDepobjConstruct &);
124 void Enter(const parser::OpenMPDispatchConstruct &);
125 void Enter(const parser::OpenMPAllocatorsConstruct &);
126 void Enter(const parser::OmpRequiresDirective &);
127 void Enter(const parser::OmpGroupprivateDirective &);
128 void Leave(const parser::OmpThreadprivateDirective &);
129
130 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
131 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
132 void Leave(const parser::OpenMPFlushConstruct &);
133 void Enter(const parser::OpenMPCancelConstruct &);
135 void Enter(const parser::OpenMPCriticalConstruct &);
136 void Enter(const parser::OpenMPAtomicConstruct &);
137
138 void Enter(const parser::OmpClauseList &);
139 void Leave(const parser::OmpClauseList &);
140 void Enter(const parser::OmpClause &);
141
142 void Enter(const parser::DoConstruct &);
143 void Leave(const parser::DoConstruct &);
144
145 void Enter(const parser::OmpDirectiveSpecification &);
146 void Leave(const parser::OmpDirectiveSpecification &);
147
148 void Enter(const parser::OmpMetadirectiveDirective &);
149 void Leave(const parser::OmpMetadirectiveDirective &);
150
151 void Enter(const parser::ExecutionPartConstruct &);
152 void Leave(const parser::OmpClause::When &);
153
154 void Enter(const parser::OmpContextSelector &);
155 void Leave(const parser::OmpContextSelector &);
156
157 void Enter(const parser::OmpLoopModifier &);
158
159 void Enter(const parser::OmpClause::Apply &);
160 void Leave(const parser::OmpClause::Apply &);
161
162 template <typename A> void Enter(const parser::Statement<A> &);
163 void Leave(const parser::GotoStmt &);
164 void Leave(const parser::ComputedGotoStmt &);
165 void Leave(const parser::ArithmeticIfStmt &);
166 void Leave(const parser::AssignedGotoStmt &);
167 void Leave(const parser::AltReturnSpec &);
168 void Leave(const parser::ErrLabel &);
169 void Leave(const parser::EndLabel &);
170 void Leave(const parser::EorLabel &);
171
172 void Enter(const parser::OmpClause::Affinity &x);
173 void Enter(const parser::OmpClause::Align &x);
174 void Enter(const parser::OmpClause::Aligned &x);
175 void Enter(const parser::OmpClause::Allocate &x);
176 void Enter(const parser::OmpClause::Allocator &x);
177 void Enter(const parser::OmpClause::At &x);
178 void Enter(const parser::OmpClause::AtomicDefaultMemOrder &x);
179 void Enter(const parser::OmpClause::CancellationConstructType &x);
180 void Enter(const parser::OmpClause::Collapse &x);
181 void Enter(const parser::OmpClause::Copyin &x);
182 void Enter(const parser::OmpClause::Copyprivate &x);
183 void Enter(const parser::OmpClause::Defaultmap &x);
184 void Enter(const parser::OmpClause::Depend &x);
185 void Enter(const parser::OmpClause::Depth &x);
186 void Enter(const parser::OmpClause::Destroy &x);
187 void Enter(const parser::OmpClause::Detach &x);
188 void Enter(const parser::OmpClause::DeviceSafesync &x);
189 void Enter(const parser::OmpClause::Device &x);
190 void Enter(const parser::OmpClause::Doacross &x);
191 void Enter(const parser::OmpClause::DynamicAllocators &x);
192 void Enter(const parser::OmpClause::DynGroupprivate &x);
193 void Enter(const parser::OmpClause::Enter &x);
194 void Enter(const parser::OmpClause::Firstprivate &x);
195 void Enter(const parser::OmpClause::From &x);
196 void Enter(const parser::OmpClause::HasDeviceAddr &x);
197 void Enter(const parser::OmpClause::Hint &x);
198 void Enter(const parser::OmpClause::If &x);
199 void Enter(const parser::OmpClause::InReduction &x);
200 void Enter(const parser::OmpClause::IsDevicePtr &x);
201 void Enter(const parser::OmpClause::Lastprivate &x);
202 void Enter(const parser::OmpClause::Linear &x);
203 void Enter(const parser::OmpClause::Looprange &x);
204 void Enter(const parser::OmpClause::Map &x);
205 void Enter(const parser::OmpClause::NumTeams &x);
206 void Enter(const parser::OmpClause::NumThreads &x);
207 void Enter(const parser::OmpClause::OmpxBare &x);
208 void Enter(const parser::OmpClause::OmpxDynCgroupMem &x);
209 void Enter(const parser::OmpClause::Ordered &x);
210 void Enter(const parser::OmpClause::Permutation &x);
211 void Enter(const parser::OmpClause::Priority &x);
212 void Enter(const parser::OmpClause::Private &x);
213 void Enter(const parser::OmpClause::Reduction &x);
214 void Enter(const parser::OmpClause::ReverseOffload &x);
215 void Enter(const parser::OmpClause::Safelen &x);
216 void Enter(const parser::OmpClause::Schedule &x);
217 void Enter(const parser::OmpClause::SelfMaps &x);
218 void Enter(const parser::OmpClause::Shared &x);
219 void Enter(const parser::OmpClause::Simdlen &x);
220 void Enter(const parser::OmpClause::Sizes &x);
221 void Enter(const parser::OmpClause::TaskReduction &x);
222 void Enter(const parser::OmpClause::ThreadLimit &x);
223 void Enter(const parser::OmpClause::To &x);
224 void Enter(const parser::OmpClause::UnifiedAddress &x);
225 void Enter(const parser::OmpClause::UnifiedSharedMemory &x);
226 void Enter(const parser::OmpClause::Update &x);
227 void Enter(const parser::OmpClause::UseDeviceAddr &x);
228 void Enter(const parser::OmpClause::UseDevicePtr &x);
229 void Enter(const parser::OmpClause::When &x);
230
231private:
232 using LoopOrConstruct = std::variant<const parser::DoConstruct *,
234
235 // Most of these functions are defined in check-omp-structure.cpp, but
236 // some groups have their own files.
237
238 // check-omp-atomic.cpp
239 void CheckStorageOverlap(const evaluate::Expr<evaluate::SomeType> &,
241 void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source);
242 void CheckAtomicType(SymbolRef sym, parser::CharBlock source,
243 std::string_view name, bool checkTypeOnPointer = true);
244 void CheckAtomicVariable(const evaluate::Expr<evaluate::SomeType> &,
245 parser::CharBlock, bool checkTypeOnPointer = true);
246 std::pair<const parser::ExecutionPartConstruct *,
248 CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1,
250 void CheckAtomicCaptureAssignment(const evaluate::Assignment &capture,
251 const SomeExpr &atom, parser::CharBlock source);
252 void CheckAtomicReadAssignment(
253 const evaluate::Assignment &read, parser::CharBlock source);
254 void CheckAtomicWriteAssignment(
255 const evaluate::Assignment &write, parser::CharBlock source);
256 std::optional<evaluate::Assignment> CheckAtomicUpdateAssignment(
257 const evaluate::Assignment &update, parser::CharBlock source);
258 std::pair<bool, bool> CheckAtomicUpdateAssignmentRhs(const SomeExpr &atom,
259 const SomeExpr &rhs, parser::CharBlock source, bool suppressDiagnostics);
260 void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond,
261 parser::CharBlock condSource, const evaluate::Assignment &assign,
262 parser::CharBlock assignSource);
263 void CheckAtomicConditionalUpdateStmt(
264 const AnalyzedCondStmt &update, parser::CharBlock source);
265 void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x,
266 const parser::Block &body, parser::CharBlock source);
267 void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x,
268 const parser::Block &body, parser::CharBlock source);
269 void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x,
270 const parser::Block &body, parser::CharBlock source);
271 void CheckAtomicConditionalUpdateCapture(
272 const parser::OpenMPAtomicConstruct &x, const parser::Block &body,
273 parser::CharBlock source);
274 void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x);
275 void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x);
276 void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x);
277
278 // check-omp-loop.cpp
279 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
280 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
281 void CheckSIMDNest(const parser::OpenMPConstruct &x);
282 void CheckRectangularNest(const parser::OmpDirectiveSpecification &spec,
283 const omp::LoopSequence &nest);
284 void CheckNestedConstruct(const parser::OpenMPLoopConstruct &x);
285 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
286 void CheckIterationVariables(const parser::OpenMPLoopConstruct &x);
287 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
288 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
289 void CheckScanModifier(const parser::OmpClause::Reduction &x);
290 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
291
292 void BeginMetadirectiveVariantScope();
293 void EndMetadirectiveVariantScope();
294
295 // check-omp-variant.cpp
296 void CheckMetadirectiveVariantsWithoutLoop(std::size_t firstVariant = 0);
297 void CheckOmpDeclareVariantDirective(
299 void CheckDeclareVariantUserConditions(const parser::OmpContextSelector &);
300 const std::list<parser::OmpTraitProperty> &GetTraitPropertyList(
302 std::optional<llvm::omp::Clause> GetClauseFromProperty(
304
305 void CheckTraitSelectorList(const std::list<parser::OmpTraitSelector> &);
306 void CheckContextSelectorSpecification(const parser::OmpContextSelector &);
307 void CheckTraitSetSelector(const parser::OmpTraitSetSelector &);
308 void CheckTraitScore(const parser::OmpTraitScore &);
309 bool VerifyTraitPropertyLists(
311 void CheckTraitSelector(
313 void CheckTraitADMO(
315 void CheckTraitCondition(
317 void CheckTraitDeviceNum(
319 void CheckTraitRequires(
321 void CheckTraitSimd(
323
324 // check-omp-structure.cpp
325 using ClauseIterator =
326 decltype(std::declval<const parser::OmpClauseList>().v.begin());
327 bool IsAllowedClause(llvm::omp::Clause clauseId);
328 bool CheckAllowedClause(llvm::omp::Clause clauseId,
329 parser::CharBlock clauseSource, llvm::omp::Directive dirId);
330 void CheckArgumentObjectKind(const parser::OmpClause &x);
331 void CheckDirectiveSpelling(
332 parser::CharBlock spelling, llvm::omp::Directive id);
333 void CheckDirectiveDeprecation(const parser::OpenMPConstruct &x);
334 void CheckClauses(parser::OmpDirectiveName dirName,
335 llvm::iterator_range<ClauseIterator> beginClauses,
336 llvm::iterator_range<ClauseIterator> endClauses);
337 void AnalyzeObject(const parser::OmpObject &object);
338 std::pair<const parser::OmpClause *, const parser::OmpClause *>
339 FindMutuallyExclusiveClauses(OmpClauseSet exclusive,
340 const std::vector<const parser::OmpClause *> &clauses);
341
342 const parser::OpenMPConstruct *GetCurrentConstruct() const;
343 void CheckSourceLabel(const parser::Label &);
344 void CheckLabelContext(const parser::CharBlock, const parser::CharBlock,
346 void ClearLabels();
347 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
348 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
349 const std::string &clauseName);
350 void CheckMultListItems();
351 void CheckStructureComponent(
352 const parser::OmpObject &object, llvm::omp::Clause clauseId);
353 void CheckStructureComponent(
354 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
355 bool HasInvalidWorksharingNesting(
356 const parser::OmpDirectiveName &name, const OmpDirectiveSet &);
357
358 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
359 bool IsNestedInDirective(llvm::omp::Directive directive);
360 bool IsCombinedParallelWorksharing(llvm::omp::Directive directive) const;
361 bool InTargetRegion();
362 void HasInvalidTeamsNesting(
363 const llvm::omp::Directive &dir, const parser::CharBlock &source);
364 bool HasRequires(llvm::omp::Clause req);
365 void CheckAllowedMapTypes(
366 parser::OmpMapType::Value, llvm::ArrayRef<parser::OmpMapType::Value>);
367
368 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
369 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
370
371 template < //
372 typename LessTy, typename RangeTy,
373 typename IterTy = decltype(std::declval<RangeTy>().begin())>
374 std::optional<IterTy> FindDuplicate(RangeTy &&);
375
376 void CheckDependList(const parser::DataRef &);
377 void CheckDoacross(const parser::OmpDoacross &doa);
378 void CheckDimsModifier(parser::CharBlock source, size_t numValues,
379 const parser::OmpDimsModifier &x);
380 void CheckTypeParamInquiry(const parser::CharBlock &source,
381 const parser::OmpObject &object, llvm::omp::Directive dirId);
382 void CheckTypeParamInquiry(const parser::CharBlock &source,
383 const parser::OmpObject &object, llvm::omp::Clause clauseId);
384 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
385 const parser::OmpObject &object, llvm::StringRef clause = "");
386 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
387 const parser::OmpObjectList &objList, llvm::StringRef clause = "");
388 void CheckThreadprivateOrDeclareTargetVar(const parser::Designator &);
389 void CheckThreadprivateOrDeclareTargetVar(const parser::Name &);
390 void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObject &);
391 void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObjectList &);
392 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
393 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
394 void CheckCrayPointee(const parser::OmpObjectList &objectList,
395 llvm::StringRef clause, bool suggestToUseCrayPointer = true);
396 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
397 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
398 void CheckCopyingPolymorphicAllocatable(
399 SymbolSourceMap &, const llvm::omp::Clause);
400 void CheckPrivateSymbolsInOuterCxt(
401 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
402 bool CheckTargetBlockOnlyTeams(const parser::Block &);
403 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
404 void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock);
405 void CheckIndividualAllocateDirective(
406 const parser::OmpAllocateDirective &x, bool isExecutable);
407 void CheckExecutableAllocateDirective(const parser::OmpAllocateDirective &x);
408
409 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
410 void CheckIteratorModifier(const parser::OmpIterator &x);
411
412 void CheckTargetNest(const parser::OpenMPConstruct &x);
413 void CheckTargetUpdate();
414 void CheckTaskgraph(const parser::OmpBlockConstruct &x);
415 void CheckDependenceType(const parser::OmpDependenceType::Value &x);
416 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
417 std::optional<llvm::omp::Directive> GetCancelType(
418 llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,
419 const std::optional<parser::OmpClauseList> &maybeClauses);
420 void CheckCancellationNest(
421 const parser::CharBlock &source, llvm::omp::Directive type);
422 void CheckReductionObjects(
423 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
424 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
425 parser::CharBlock source, llvm::omp::Clause clauseId);
426 void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
427 const parser::OmpReductionIdentifier &ident);
428 void CheckReductionModifier(const parser::OmpReductionModifier &);
429 void CheckLastprivateModifier(const parser::OmpLastprivateModifier &);
430 void CheckSingleConstruct(const parser::OmpBlockConstruct &x);
431 void CheckMasterNesting(const parser::OmpBlockConstruct &x);
432 void ChecksOnOrderedAsBlock();
433 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
434 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
435 void ChecksOnOrderedAsStandalone();
436 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
437 void CheckReductionArraySection(
438 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
439 void CheckArraySection(const parser::ArrayElement &arrayElement,
440 const parser::Name &name, const llvm::omp::Clause clause);
441 void CheckLastPartRefForArraySection(
442 const parser::Designator &designator, llvm::omp::Clause clauseId);
443 void CheckSharedBindingInOuterContext(
444 const parser::OmpObjectList &ompObjectList);
445 void CheckIfContiguous(const parser::OmpObject &object);
446 const parser::Name *GetObjectName(const parser::OmpObject &object);
447 void CheckInitOnDepobj(const parser::OpenMPDepobjConstruct &depobj,
448 const parser::OmpClause &initClause);
449 void CheckAllowedRequiresClause(llvm::omp::Clause clause);
450 void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);
451 void CheckTempDescriptorMappings();
452
453 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
454 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
455 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
456
457 bool deviceConstructFound_{false};
458 enum directiveNestType : int {
459 ApplyNest,
460 SIMDNest,
461 TargetBlockOnlyTeams,
462 TargetNest,
463 DeclarativeNest,
464 ContextSelectorNest,
465 MetadirectiveNest,
466 LastType = MetadirectiveNest,
467 };
468 int directiveNest_[LastType + 1] = {0};
469
470 std::set<std::pair<const Symbol *, const Symbol *>> declareVariantPairs_;
471 // For each variant procedure: its construct-selector-set as an ordered list
472 // of elements (a leaf construct directive plus a normalized rendering of any
473 // properties), and the source of the DECLARE VARIANT directive that first
474 // established the set.
475 std::map<const Symbol *,
476 std::pair<
479 declareVariantConstructSets_;
480 // Tracks the procedures that appear as a base in DECLARE VARIANT.
481 std::set<const Symbol *> declareVariantBases_;
482
483 int allocateDirectiveLevel_{0};
484 parser::CharBlock visitedAtomicSource_;
485
486 // Mapping of directive-name-modifier constituents to the sources of the
487 // IF clauses that referenced them. If there was no modifier, the entire
488 // directive is assumed to be listed.
489 std::map<llvm::omp::Directive, parser::CharBlock> ifLeafs_;
490
491 // Track symbols with temporary stack descriptors mapped in TARGET ENTER DATA
492 // and symbols mapped in TARGET EXIT DATA within the current function scope.
493 // Used to warn about potential issues with mapping temporary descriptors.
494 std::multimap<const Symbol *, parser::CharBlock> tempDescriptorEnterMaps_;
495 std::set<const Symbol *> tempDescriptorExitMaps_;
496
497 // Stack of nested DO loops and OpenMP constructs.
498 // This is used to verify DO loop nest for DOACROSS, and branches into
499 // and out of OpenMP constructs.
500 std::vector<LoopOrConstruct> constructStack_;
501 // Scopes for scoping units.
502 std::vector<const Scope *> scopeStack_;
503 // Stack of directive specifications (except for SECTION).
504 // This is to allow visitor functions to see all specified clauses, since
505 // they are only recorded in DirectiveContext as they are processed.
506 std::vector<const parser::OmpDirectiveSpecification *> dirStack_;
507
508 enum class PartKind : int {
509 // There are also other "parts", such as internal-subprogram-part, etc,
510 // but we're keeping track of these two for now.
511 SpecificationPart,
512 ExecutionPart,
513 };
514 std::vector<PartKind> partStack_;
515
516 struct MetadirectiveLoopVariant {
519 };
520 std::vector<MetadirectiveLoopVariant> metadirectiveLoopVariants_;
521 std::vector<std::size_t> metadirectiveVariantScopeStarts_;
522 const parser::traits::OmpContextSelectorSpecification *currentWhenSelector_{
523 nullptr};
524
525 std::multimap<const parser::Label,
526 std::pair<parser::CharBlock, const parser::OpenMPConstruct *>>
527 sourceLabels_;
528 std::map<const parser::Label,
529 std::pair<parser::CharBlock, const parser::OpenMPConstruct *>>
530 targetLabels_;
531 parser::CharBlock currentStatementSource_;
532};
533
534template <typename A>
535void OmpStructureChecker::Enter(const parser::Statement<A> &statement) {
536 currentStatementSource_ = statement.source;
537 // Keep track of the labels in all the labelled statements
538 if (statement.label) {
539 auto label{statement.label.value()};
540 // Get the context to check if the labelled statement is in an
541 // enclosing OpenMP construct
542 auto *thisConstruct{GetCurrentConstruct()};
543 targetLabels_.emplace(
544 label, std::make_pair(currentStatementSource_, thisConstruct));
545 // Check if a statement that causes a jump to the 'label'
546 // has already been encountered
547 auto range{sourceLabels_.equal_range(label)};
548 for (auto it{range.first}; it != range.second; ++it) {
549 // Check if both the statement with 'label' and the statement that
550 // causes a jump to the 'label' are in the same scope
551 CheckLabelContext(it->second.first, currentStatementSource_,
552 it->second.second, thisConstruct);
553 }
554 }
555}
556
559template <typename LessTy, typename RangeTy, typename IterTy>
560std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
561 // Deal with iterators, since the actual elements may be rvalues (i.e.
562 // have no addresses), for example with custom-constructed ranges that
563 // are not simple c.begin()..c.end().
564 std::set<IterTy, LessTy> uniq;
565 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
566 if (!uniq.insert(it).second) {
567 return it;
568 }
569 }
570 return std::nullopt;
571}
572} // namespace Fortran::semantics
573#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
Definition enum-set.h:28
Definition expression.h:920
Definition common.h:215
Definition char-block.h:26
Definition check-directive-structure.h:208
Definition semantics.h:67
Definition symbol.h:893
Definition FIRType.h:106
Definition OpenACC.h:20
Definition parse-tree.h:3541
Definition parse-tree.h:1938
Definition parse-tree.h:3551
Definition parse-tree.h:2222
Definition parse-tree.h:3061
Definition parse-tree.h:2550
Definition parse-tree.h:1848
Definition parse-tree.h:1887
Definition parse-tree.h:2365
Definition parse-tree.h:558
Definition parse-tree.h:3181
Definition parse-tree.h:3213
Definition parse-tree.h:467
Definition parse-tree.h:2969
Definition parse-tree.h:2994
Definition parse-tree.h:2983
Definition parse-tree.h:3005
Definition parse-tree.h:591
Definition parse-tree.h:5397
Definition parse-tree.h:5186
Definition parse-tree.h:5196
Definition parse-tree.h:5155
Definition parse-tree.h:5139
Definition parse-tree.h:5324
Definition parse-tree.h:5341
Definition parse-tree.h:5316
Definition parse-tree.h:3577
Definition parse-tree.h:5162
Definition parse-tree.h:4586
Definition parse-tree.h:5350
Definition parse-tree.h:5209
Definition parse-tree.h:3632
Definition parse-tree.h:3620
Definition parse-tree.h:3676
Definition parse-tree.h:5357
Definition parse-tree.h:5363
Definition parse-tree.h:5423
Definition parse-tree.h:5428
Definition parse-tree.h:5465
Definition parse-tree.h:5549
Definition parse-tree.h:5413
Definition parse-tree.h:5476
Definition parse-tree.h:5490
Definition parse-tree.h:5506
Definition parse-tree.h:5514
Definition parse-tree.h:5567
Definition parse-tree.h:5535
Definition parse-tree.h:5281
Definition parse-tree.h:575
Definition parse-tree.h:455
Definition parse-tree.h:361
Definition parse-tree.h:3047
Definition parse-tree.h:3200
Definition parse-tree.h:4060
Definition parse-tree.h:4126
Definition parse-tree.h:4136
Definition parse-tree.h:4144
Definition parse-tree.h:4168
Definition parse-tree.h:4303
Definition parse-tree.h:3813
Definition parse-tree.h:3779
Definition parse-tree.h:3852
Definition parse-tree.h:3874
Definition check-omp-atomic.cpp:242
Definition openmp-utils.h:413