@@ -89,30 +89,31 @@ bool AccStructureChecker::CheckAllowedModifier(llvm::acc::Clause clause) {
8989 return false ;
9090}
9191
92- bool AccStructureChecker::IsComputeConstruct (
93- llvm::acc::Directive directive) const {
94- return directive == llvm::acc::ACCD_parallel ||
95- directive == llvm::acc::ACCD_parallel_loop ||
96- directive == llvm::acc::ACCD_serial ||
97- directive == llvm::acc::ACCD_serial_loop ||
98- directive == llvm::acc::ACCD_kernels ||
99- directive == llvm::acc::ACCD_kernels_loop;
100- }
101-
102- bool AccStructureChecker::IsInsideComputeConstruct () const {
103- if (dirContext_.size () <= 1 ) {
92+ bool AccStructureChecker::IsInsideDirectiveContext (
93+ std::function<bool (llvm::acc::Directive)> pred, bool skipFirst) const {
94+ std::size_t contextSize{dirContext_.size ()};
95+ std::size_t skipFirstOffset{skipFirst ? 1u : 0u };
96+ // Short circuit if there are no contexts to check.
97+ if (contextSize <= skipFirstOffset) {
10498 return false ;
10599 }
106-
107- // Check all nested context skipping the first one.
108- for (std::size_t i = dirContext_.size () - 1 ; i > 0 ; --i) {
109- if (IsComputeConstruct (dirContext_[i - 1 ].directive )) {
100+ // Check contexts from innermost to outermost.
101+ for (std::size_t i{contextSize - skipFirstOffset}; i > 0u ; --i) {
102+ if (pred (dirContext_[i - 1 ].directive )) {
110103 return true ;
111104 }
112105 }
113106 return false ;
114107}
115108
109+ bool AccStructureChecker::IsInsideComputeConstruct () const {
110+ return IsInsideDirectiveContext (IsComputeConstruct, /* skipFirst=*/ true );
111+ }
112+
113+ bool AccStructureChecker::IsInsideLoopConstruct () const {
114+ return IsInsideDirectiveContext (IsLoopConstruct);
115+ }
116+
116117void AccStructureChecker::CheckNotInComputeConstruct () {
117118 if (IsInsideComputeConstruct ()) {
118119 context_.Say (GetContext ().directiveSource ,
@@ -363,10 +364,28 @@ void AccStructureChecker::Enter(const parser::OpenACCCacheConstruct &x) {
363364 const auto &verbatim = std::get<parser::Verbatim>(x.t );
364365 PushContextAndClauseSets (verbatim.source , llvm::acc::Directive::ACCD_cache);
365366 SetContextDirectiveSource (verbatim.source );
366- if (loopNestLevel == 0 ) {
367+ if (loopNests. size () == 0 ) {
367368 context_.Say (verbatim.source ,
368369 " The CACHE directive must be inside a loop" _err_en_US);
369370 }
371+
372+ for (std::size_t i{0 }; i < loopNests.size (); i++) {
373+ if (const parser::DoConstruct *doConstruct{loopNests[i]}) {
374+ if (!doConstruct->GetLoopControl ()) {
375+ context_
376+ .Say (std::get<parser::Statement<parser::NonLabelDoStmt>>(
377+ doConstruct->t )
378+ .source ,
379+ " DO loop with CACHE directive must have loop control" _err_en_US)
380+ .Attach (verbatim.source ,
381+ " This CACHE directive implies a LOOP directive" _because_en_US);
382+ }
383+ // Remove the do construct from the loopNests vector after checking so
384+ // that if there are multiple cache directives the loop isn't checked
385+ // again.
386+ loopNests[i] = nullptr ;
387+ }
388+ }
370389}
371390void AccStructureChecker::Leave (const parser::OpenACCCacheConstruct &x) {
372391 dirContext_.pop_back ();
@@ -814,12 +833,19 @@ void AccStructureChecker::Enter(const parser::SeparateModuleSubprogram &) {
814833 declareSymbols.clear ();
815834}
816835
817- void AccStructureChecker::Enter (const parser::DoConstruct &) {
818- ++loopNestLevel;
836+ void AccStructureChecker::Enter (const parser::DoConstruct &x) {
837+ // If the current context is alread is an loop construct it has already been
838+ // checked. Otherwise if there is a cache directive in the loop we will check
839+ // to make sure it has a loop control clause.
840+ if (IsInsideLoopConstruct ()) {
841+ loopNests.push_back (nullptr );
842+ } else {
843+ loopNests.push_back (&x);
844+ }
819845}
820846
821- void AccStructureChecker::Leave (const parser::DoConstruct &) {
822- --loopNestLevel ;
847+ void AccStructureChecker::Leave (const parser::DoConstruct &x ) {
848+ loopNests. pop_back () ;
823849}
824850
825851llvm::StringRef AccStructureChecker::getDirectiveName (
0 commit comments