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
23using OmpClauseSet =
25
26#define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
27#include "llvm/Frontend/OpenMP/OMP.inc"
28
29namespace llvm {
30namespace omp {
31static OmpClauseSet privateSet{
32 Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate};
33static OmpClauseSet privateReductionSet{
34 OmpClauseSet{Clause::OMPC_reduction} | privateSet};
35// omp.td cannot differentiate allowed/not allowed clause list for few
36// directives for fortran. nowait is not allowed on begin directive clause list
37// for below list of directives. Directives with conflicting list of clauses are
38// included in below list.
39static const OmpDirectiveSet noWaitClauseNotAllowedSet{
40 Directive::OMPD_do,
41 Directive::OMPD_do_simd,
42 Directive::OMPD_sections,
43 Directive::OMPD_single,
44 Directive::OMPD_workshare,
45};
46} // namespace omp
47} // namespace llvm
48
49namespace Fortran::semantics {
50struct AnalyzedCondStmt;
51
52namespace omp {
53struct LoopSequence;
54}
55
56// Mapping from 'Symbol' to 'Source' to keep track of the variables
57// used in multiple clauses
58using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>;
59// Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause>
60using DirectivesClauseTriple = std::multimap<llvm::omp::Directive,
61 std::pair<llvm::omp::Directive, const OmpClauseSet>>;
62
63using OmpStructureCheckerBase = DirectiveStructureChecker<llvm::omp::Directive,
64 llvm::omp::Clause, parser::OmpClause, llvm::omp::Clause_enumSize>;
65
66class OmpStructureChecker : public OmpStructureCheckerBase {
67public:
68 using Base = OmpStructureCheckerBase;
69
70 OmpStructureChecker(SemanticsContext &context);
71
72 void Enter(const parser::ProgramUnit &);
73 void Enter(const parser::MainProgram &);
74 void Leave(const parser::MainProgram &);
75 void Enter(const parser::BlockData &);
76 void Leave(const parser::BlockData &);
77 void Enter(const parser::Module &);
78 void Leave(const parser::Module &);
79 void Enter(const parser::Submodule &);
80 void Leave(const parser::Submodule &);
81 void Enter(const parser::SubroutineStmt &);
82 void Enter(const parser::EndSubroutineStmt &);
83 void Enter(const parser::FunctionStmt &);
84 void Enter(const parser::EndFunctionStmt &);
85 void Enter(const parser::MpSubprogramStmt &);
86 void Enter(const parser::EndMpSubprogramStmt &);
87 void Enter(const parser::BlockConstruct &);
88 void Leave(const parser::BlockConstruct &);
89 void Enter(const parser::InternalSubprogram &);
90 void Enter(const parser::ModuleSubprogram &);
91
92 void Enter(const parser::SpecificationPart &);
93 void Leave(const parser::SpecificationPart &);
94 void Enter(const parser::ExecutionPart &);
95 void Leave(const parser::ExecutionPart &);
96
97 void Enter(const parser::OpenMPConstruct &);
98 void Leave(const parser::OpenMPConstruct &);
99 void Enter(const parser::OpenMPDeclarativeConstruct &);
100 void Leave(const parser::OpenMPDeclarativeConstruct &);
101
102 void Enter(const parser::OpenMPMisplacedEndDirective &);
103 void Leave(const parser::OpenMPMisplacedEndDirective &);
104 void Enter(const parser::OpenMPInvalidDirective &);
105 void Leave(const parser::OpenMPInvalidDirective &);
106
107 void Enter(const parser::OpenMPLoopConstruct &);
108 void Leave(const parser::OpenMPLoopConstruct &);
109
110 void Enter(const parser::OmpAssumeDirective &);
111 void Leave(const parser::OmpAssumeDirective &);
112 void Enter(const parser::OmpAssumesDirective &);
113 void Leave(const parser::OmpAssumesDirective &);
114 void Enter(const parser::OpenMPInteropConstruct &);
115 void Leave(const parser::OpenMPInteropConstruct &);
116 void Enter(const parser::OmpBlockConstruct &);
117 void Leave(const parser::OmpBlockConstruct &);
118 void Enter(const parser::OmpBeginDirective &);
119 void Leave(const parser::OmpBeginDirective &);
120 void Enter(const parser::OmpEndDirective &);
121 void Leave(const parser::OmpEndDirective &);
122
123 void Enter(const parser::OpenMPSectionsConstruct &);
124 void Leave(const parser::OpenMPSectionsConstruct &);
125 void Enter(const parser::OmpEndSectionsDirective &);
126 void Leave(const parser::OmpEndSectionsDirective &);
127
128 void Enter(const parser::OmpDeclareVariantDirective &);
129 void Leave(const parser::OmpDeclareVariantDirective &);
130 void Enter(const parser::OmpDeclareSimdDirective &);
131 void Leave(const parser::OmpDeclareSimdDirective &);
132 void Enter(const parser::OmpAllocateDirective &);
133 void Leave(const parser::OmpAllocateDirective &);
134 void Enter(const parser::OmpDeclareMapperDirective &);
135 void Leave(const parser::OmpDeclareMapperDirective &);
136 void Enter(const parser::OmpDeclareReductionDirective &);
137 void Leave(const parser::OmpDeclareReductionDirective &);
138 void Enter(const parser::OmpDeclareTargetDirective &);
139 void Leave(const parser::OmpDeclareTargetDirective &);
140 void Enter(const parser::OpenMPDepobjConstruct &);
141 void Leave(const parser::OpenMPDepobjConstruct &);
142 void Enter(const parser::OpenMPDispatchConstruct &);
143 void Leave(const parser::OpenMPDispatchConstruct &);
144 void Enter(const parser::OmpErrorDirective &);
145 void Leave(const parser::OmpErrorDirective &);
146 void Enter(const parser::OmpNothingDirective &);
147 void Leave(const parser::OmpNothingDirective &);
148 void Enter(const parser::OpenMPAllocatorsConstruct &);
149 void Leave(const parser::OpenMPAllocatorsConstruct &);
150 void Enter(const parser::OmpRequiresDirective &);
151 void Leave(const parser::OmpRequiresDirective &);
152 void Enter(const parser::OmpGroupprivateDirective &);
153 void Leave(const parser::OmpGroupprivateDirective &);
154 void Enter(const parser::OmpThreadprivateDirective &);
155 void Leave(const parser::OmpThreadprivateDirective &);
156
157 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
158 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
159 void Enter(const parser::OpenMPFlushConstruct &);
160 void Leave(const parser::OpenMPFlushConstruct &);
161 void Enter(const parser::OpenMPCancelConstruct &);
162 void Leave(const parser::OpenMPCancelConstruct &);
165 void Enter(const parser::OpenMPCriticalConstruct &);
166 void Leave(const parser::OpenMPCriticalConstruct &);
167 void Enter(const parser::OpenMPAtomicConstruct &);
168 void Leave(const parser::OpenMPAtomicConstruct &);
169
170 void Leave(const parser::OmpClauseList &);
171 void Enter(const parser::OmpClause &);
172
173 void Enter(const parser::DoConstruct &);
174 void Leave(const parser::DoConstruct &);
175
176 void Enter(const parser::OmpDirectiveSpecification &);
177 void Leave(const parser::OmpDirectiveSpecification &);
178
179 void Enter(const parser::OmpMetadirectiveDirective &);
180 void Leave(const parser::OmpMetadirectiveDirective &);
183
184 void Enter(const parser::OmpContextSelector &);
185 void Leave(const parser::OmpContextSelector &);
186
187 template <typename A> void Enter(const parser::Statement<A> &);
188 void Leave(const parser::GotoStmt &);
189 void Leave(const parser::ComputedGotoStmt &);
190 void Leave(const parser::ArithmeticIfStmt &);
191 void Leave(const parser::AssignedGotoStmt &);
192 void Leave(const parser::AltReturnSpec &);
193 void Leave(const parser::ErrLabel &);
194 void Leave(const parser::EndLabel &);
195 void Leave(const parser::EorLabel &);
196
197#define GEN_FLANG_CLAUSE_CHECK_ENTER
198#include "llvm/Frontend/OpenMP/OMP.inc"
199
200private:
201 using LoopOrConstruct = std::variant<const parser::DoConstruct *,
203
204 // Most of these functions are defined in check-omp-structure.cpp, but
205 // some groups have their own files.
206
207 // check-omp-atomic.cpp
208 void CheckStorageOverlap(const evaluate::Expr<evaluate::SomeType> &,
210 void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source);
211 void CheckAtomicType(SymbolRef sym, parser::CharBlock source,
212 std::string_view name, bool checkTypeOnPointer = true);
213 void CheckAtomicVariable(const evaluate::Expr<evaluate::SomeType> &,
214 parser::CharBlock, bool checkTypeOnPointer = true);
215 std::pair<const parser::ExecutionPartConstruct *,
217 CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1,
219 void CheckAtomicCaptureAssignment(const evaluate::Assignment &capture,
220 const SomeExpr &atom, parser::CharBlock source);
221 void CheckAtomicReadAssignment(
222 const evaluate::Assignment &read, parser::CharBlock source);
223 void CheckAtomicWriteAssignment(
224 const evaluate::Assignment &write, parser::CharBlock source);
225 std::optional<evaluate::Assignment> CheckAtomicUpdateAssignment(
226 const evaluate::Assignment &update, parser::CharBlock source);
227 std::pair<bool, bool> CheckAtomicUpdateAssignmentRhs(const SomeExpr &atom,
228 const SomeExpr &rhs, parser::CharBlock source, bool suppressDiagnostics);
229 void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond,
230 parser::CharBlock condSource, const evaluate::Assignment &assign,
231 parser::CharBlock assignSource);
232 void CheckAtomicConditionalUpdateStmt(
233 const AnalyzedCondStmt &update, parser::CharBlock source);
234 void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x,
235 const parser::Block &body, parser::CharBlock source);
236 void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x,
237 const parser::Block &body, parser::CharBlock source);
238 void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x,
239 const parser::Block &body, parser::CharBlock source);
240 void CheckAtomicConditionalUpdateCapture(
241 const parser::OpenMPAtomicConstruct &x, const parser::Block &body,
242 parser::CharBlock source);
243 void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x);
244 void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x);
245 void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x);
246
247 // check-omp-loop.cpp
248 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
249 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
250 void CheckSIMDNest(const parser::OpenMPConstruct &x);
251 void CheckRectangularNest(const parser::OmpDirectiveSpecification &spec,
252 const omp::LoopSequence &nest);
253 void CheckNestedConstruct(const parser::OpenMPLoopConstruct &x);
254 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
255 void CheckIterationVariables(const parser::OpenMPLoopConstruct &x);
256 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
257 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
258 void CheckScanModifier(const parser::OmpClause::Reduction &x);
259 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
260
261 // check-omp-variant.cpp
262 void CheckOmpDeclareVariantDirective(
264 void CheckDeclareVariantUserConditions(const parser::OmpContextSelector &);
265 const std::list<parser::OmpTraitProperty> &GetTraitPropertyList(
267 std::optional<llvm::omp::Clause> GetClauseFromProperty(
269
270 void CheckTraitSelectorList(const std::list<parser::OmpTraitSelector> &);
271 void CheckContextSelectorSpecification(const parser::OmpContextSelector &);
272 void CheckTraitSetSelector(const parser::OmpTraitSetSelector &);
273 void CheckTraitScore(const parser::OmpTraitScore &);
274 bool VerifyTraitPropertyLists(
276 void CheckTraitSelector(
278 void CheckTraitADMO(
280 void CheckTraitCondition(
282 void CheckTraitDeviceNum(
284 void CheckTraitRequires(
286 void CheckTraitSimd(
288
289 // check-omp-structure.cpp
290 bool IsAllowedClause(llvm::omp::Clause clauseId);
291 bool CheckAllowedClause(llvm::omp::Clause clause);
292 void CheckArgumentObjectKind(const parser::OmpClause &x);
293 void CheckDirectiveSpelling(
294 parser::CharBlock spelling, llvm::omp::Directive id);
295 void CheckDirectiveDeprecation(const parser::OpenMPConstruct &x);
296 void AnalyzeObject(const parser::OmpObject &object);
297
298 const parser::OpenMPConstruct *GetCurrentConstruct() const;
299 void CheckSourceLabel(const parser::Label &);
300 void CheckLabelContext(const parser::CharBlock, const parser::CharBlock,
302 void ClearLabels();
303 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
304 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
305 const std::string &clauseName);
306 void CheckMultListItems();
307 void CheckStructureComponent(
308 const parser::OmpObject &object, llvm::omp::Clause clauseId);
309 void CheckStructureComponent(
310 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
311 bool HasInvalidWorksharingNesting(
312 const parser::OmpDirectiveName &name, const OmpDirectiveSet &);
313
314 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
315 bool IsNestedInDirective(llvm::omp::Directive directive);
316 bool IsCombinedParallelWorksharing(llvm::omp::Directive directive) const;
317 bool InTargetRegion();
318 void HasInvalidTeamsNesting(
319 const llvm::omp::Directive &dir, const parser::CharBlock &source);
320 bool HasRequires(llvm::omp::Clause req);
321 void CheckAllowedMapTypes(
322 parser::OmpMapType::Value, llvm::ArrayRef<parser::OmpMapType::Value>);
323
324 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
325 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
326
327 template < //
328 typename LessTy, typename RangeTy,
329 typename IterTy = decltype(std::declval<RangeTy>().begin())>
330 std::optional<IterTy> FindDuplicate(RangeTy &&);
331
332 void CheckDependList(const parser::DataRef &);
333 void CheckDoacross(const parser::OmpDoacross &doa);
334 void CheckDimsModifier(parser::CharBlock source, size_t numValues,
335 const parser::OmpDimsModifier &x);
336 void CheckTypeParamInquiry(
337 const parser::CharBlock &source, const parser::OmpObject &object);
338 void CheckTypeParamInquiry(
339 const parser::CharBlock &source, const parser::OmpObjectList &objects);
340 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
341 const parser::OmpObject &object, llvm::StringRef clause = "");
342 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
343 const parser::OmpObjectList &objList, llvm::StringRef clause = "");
344 void CheckThreadprivateOrDeclareTargetVar(const parser::Designator &);
345 void CheckThreadprivateOrDeclareTargetVar(const parser::Name &);
346 void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObject &);
347 void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObjectList &);
348 void CheckSymbolName(
349 const parser::CharBlock &source, const parser::OmpObject &object);
350 void CheckSymbolNames(
351 const parser::CharBlock &source, const parser::OmpObjectList &objList);
352 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
353 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
354 void CheckCrayPointee(const parser::OmpObjectList &objectList,
355 llvm::StringRef clause, bool suggestToUseCrayPointer = true);
356 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
357 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
358 void CheckCopyingPolymorphicAllocatable(
359 SymbolSourceMap &, const llvm::omp::Clause);
360 void CheckPrivateSymbolsInOuterCxt(
361 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
362 bool CheckTargetBlockOnlyTeams(const parser::Block &);
363 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
364 void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock);
365 void CheckIndividualAllocateDirective(
366 const parser::OmpAllocateDirective &x, bool isExecutable);
367 void CheckExecutableAllocateDirective(const parser::OmpAllocateDirective &x);
368
369 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
370 void CheckIteratorModifier(const parser::OmpIterator &x);
371
372 void CheckTargetNest(const parser::OpenMPConstruct &x);
373 void CheckTargetUpdate();
374 void CheckTaskgraph(const parser::OmpBlockConstruct &x);
375 void CheckDependenceType(const parser::OmpDependenceType::Value &x);
376 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
377 std::optional<llvm::omp::Directive> GetCancelType(
378 llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,
379 const std::optional<parser::OmpClauseList> &maybeClauses);
380 void CheckCancellationNest(
381 const parser::CharBlock &source, llvm::omp::Directive type);
382 void CheckReductionObjects(
383 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
384 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
385 parser::CharBlock source, llvm::omp::Clause clauseId);
386 void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
387 const parser::OmpReductionIdentifier &ident);
388 void CheckReductionModifier(const parser::OmpReductionModifier &);
389 void CheckLastprivateModifier(const parser::OmpLastprivateModifier &);
390 void CheckMasterNesting(const parser::OmpBlockConstruct &x);
391 void ChecksOnOrderedAsBlock();
392 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
393 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
394 void ChecksOnOrderedAsStandalone();
395 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
396 void CheckReductionArraySection(
397 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
398 void CheckArraySection(const parser::ArrayElement &arrayElement,
399 const parser::Name &name, const llvm::omp::Clause clause);
400 void CheckLastPartRefForArraySection(
401 const parser::Designator &designator, llvm::omp::Clause clauseId);
402 void CheckSharedBindingInOuterContext(
403 const parser::OmpObjectList &ompObjectList);
404 void CheckIfContiguous(const parser::OmpObject &object);
405 const parser::Name *GetObjectName(const parser::OmpObject &object);
406 void CheckInitOnDepobj(const parser::OpenMPDepobjConstruct &depobj,
407 const parser::OmpClause &initClause);
408 void CheckAllowedRequiresClause(llvm::omp::Clause clause);
409 void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);
410 void CheckTempDescriptorMappings();
411
412 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
413 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
414 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
415
416 bool deviceConstructFound_{false};
417 enum directiveNestType : int {
418 SIMDNest,
419 TargetBlockOnlyTeams,
420 TargetNest,
421 DeclarativeNest,
422 ContextSelectorNest,
423 MetadirectiveNest,
424 LastType = MetadirectiveNest,
425 };
426 int directiveNest_[LastType + 1] = {0};
427
428 std::set<std::pair<const Symbol *, const Symbol *>> declareVariantPairs_;
429
430 int allocateDirectiveLevel_{0};
431 parser::CharBlock visitedAtomicSource_;
432
433 // Track symbols with temporary stack descriptors mapped in TARGET ENTER DATA
434 // and symbols mapped in TARGET EXIT DATA within the current function scope.
435 // Used to warn about potential issues with mapping temporary descriptors.
436 std::multimap<const Symbol *, parser::CharBlock> tempDescriptorEnterMaps_;
437 std::set<const Symbol *> tempDescriptorExitMaps_;
438
439 // Stack of nested DO loops and OpenMP constructs.
440 // This is used to verify DO loop nest for DOACROSS, and branches into
441 // and out of OpenMP constructs.
442 std::vector<LoopOrConstruct> constructStack_;
443 // Scopes for scoping units.
444 std::vector<const Scope *> scopeStack_;
445 // Stack of directive specifications (except for SECTION).
446 // This is to allow visitor functions to see all specified clauses, since
447 // they are only recorded in DirectiveContext as they are processed.
448 std::vector<const parser::OmpDirectiveSpecification *> dirStack_;
449
450 enum class PartKind : int {
451 // There are also other "parts", such as internal-subprogram-part, etc,
452 // but we're keeping track of these two for now.
453 SpecificationPart,
454 ExecutionPart,
455 };
456 std::vector<PartKind> partStack_;
457
458 std::multimap<const parser::Label,
459 std::pair<parser::CharBlock, const parser::OpenMPConstruct *>>
460 sourceLabels_;
461 std::map<const parser::Label,
462 std::pair<parser::CharBlock, const parser::OpenMPConstruct *>>
463 targetLabels_;
464 parser::CharBlock currentStatementSource_;
465};
466
467template <typename A>
468void OmpStructureChecker::Enter(const parser::Statement<A> &statement) {
469 currentStatementSource_ = statement.source;
470 // Keep track of the labels in all the labelled statements
471 if (statement.label) {
472 auto label{statement.label.value()};
473 // Get the context to check if the labelled statement is in an
474 // enclosing OpenMP construct
475 auto *thisConstruct{GetCurrentConstruct()};
476 targetLabels_.emplace(
477 label, std::make_pair(currentStatementSource_, thisConstruct));
478 // Check if a statement that causes a jump to the 'label'
479 // has already been encountered
480 auto range{sourceLabels_.equal_range(label)};
481 for (auto it{range.first}; it != range.second; ++it) {
482 // Check if both the statement with 'label' and the statement that
483 // causes a jump to the 'label' are in the same scope
484 CheckLabelContext(it->second.first, currentStatementSource_,
485 it->second.second, thisConstruct);
486 }
487 }
488}
489
492template <typename LessTy, typename RangeTy, typename IterTy>
493std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
494 // Deal with iterators, since the actual elements may be rvalues (i.e.
495 // have no addresses), for example with custom-constructed ranges that
496 // are not simple c.begin()..c.end().
497 std::set<IterTy, LessTy> uniq;
498 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
499 if (!uniq.insert(it).second) {
500 return it;
501 }
502 }
503 return std::nullopt;
504}
505
506} // namespace Fortran::semantics
507#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
Definition enum-set.h:28
Definition expression.h:921
Definition common.h:215
Definition char-block.h:28
Definition check-directive-structure.h:208
Definition semantics.h:68
Definition FIRType.h:103
Definition parse-tree.h:3529
Definition parse-tree.h:1931
Definition parse-tree.h:3539
Definition parse-tree.h:2215
Definition parse-tree.h:3053
Definition parse-tree.h:2543
Definition parse-tree.h:1841
Definition parse-tree.h:1880
Definition parse-tree.h:2358
Definition parse-tree.h:559
Definition parse-tree.h:3173
Definition parse-tree.h:468
Definition parse-tree.h:2962
Definition parse-tree.h:2976
Definition parse-tree.h:2997
Definition parse-tree.h:592
Definition parse-tree.h:5356
Definition parse-tree.h:5214
Definition parse-tree.h:5203
Definition parse-tree.h:5145
Definition parse-tree.h:5155
Definition parse-tree.h:5114
Definition parse-tree.h:5098
Definition parse-tree.h:5283
Definition parse-tree.h:5300
Definition parse-tree.h:5275
Definition parse-tree.h:3565
Definition parse-tree.h:5121
Definition parse-tree.h:4545
Definition parse-tree.h:5150
Definition parse-tree.h:5225
Definition parse-tree.h:5188
Definition parse-tree.h:5309
Definition parse-tree.h:5168
Definition parse-tree.h:5182
Definition parse-tree.h:3610
Definition parse-tree.h:3598
Definition parse-tree.h:3654
Definition parse-tree.h:5316
Definition parse-tree.h:5322
Definition parse-tree.h:5382
Definition parse-tree.h:5387
Definition parse-tree.h:5424
Definition parse-tree.h:5508
Definition parse-tree.h:5372
Definition parse-tree.h:5435
Definition parse-tree.h:5449
Definition parse-tree.h:5465
Definition parse-tree.h:5473
Definition parse-tree.h:5526
Definition parse-tree.h:5494
Definition parse-tree.h:5240
Definition parse-tree.h:576
Definition parse-tree.h:456
Definition parse-tree.h:362
Definition parse-tree.h:3039
Definition parse-tree.h:3192
Definition parse-tree.h:4047
Definition parse-tree.h:4113
Definition parse-tree.h:4123
Definition parse-tree.h:4131
Definition parse-tree.h:4272
Definition parse-tree.h:3800
Definition parse-tree.h:3766
Definition parse-tree.h:3839
Definition parse-tree.h:3861
Definition check-omp-atomic.cpp:242
Definition openmp-utils.h:309