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