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