|  | //===--- SemaOpenACCClause.cpp - Semantic Analysis for OpenACC clause -----===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | /// \file | 
|  | /// This file implements semantic analysis for OpenACC clauses. | 
|  | /// | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "clang/AST/DeclCXX.h" | 
|  | #include "clang/AST/ExprCXX.h" | 
|  | #include "clang/AST/OpenACCClause.h" | 
|  | #include "clang/Basic/DiagnosticSema.h" | 
|  | #include "clang/Basic/OpenACCKinds.h" | 
|  | #include "clang/Sema/SemaOpenACC.h" | 
|  |  | 
|  | using namespace clang; | 
|  |  | 
|  | namespace { | 
|  | bool checkValidAfterDeviceType( | 
|  | SemaOpenACC &S, const OpenACCDeviceTypeClause &DeviceTypeClause, | 
|  | const SemaOpenACC::OpenACCParsedClause &NewClause) { | 
|  | // OpenACC3.3: Section 2.4: Clauses that precede any device_type clause are | 
|  | // default clauses.  Clauses that follow a device_type clause up to the end of | 
|  | // the directive or up to the next device_type clause are device-specific | 
|  | // clauses for the device types specified in the device_type argument. | 
|  | // | 
|  | // The above implies that despite what the individual text says, these are | 
|  | // valid. | 
|  | if (NewClause.getClauseKind() == OpenACCClauseKind::DType || | 
|  | NewClause.getClauseKind() == OpenACCClauseKind::DeviceType) | 
|  | return false; | 
|  |  | 
|  | // Implement check from OpenACC3.3: section 2.5.4: | 
|  | // Only the async, wait, num_gangs, num_workers, and vector_length clauses may | 
|  | // follow a device_type clause. | 
|  | if (isOpenACCComputeDirectiveKind(NewClause.getDirectiveKind())) { | 
|  | switch (NewClause.getClauseKind()) { | 
|  | case OpenACCClauseKind::Async: | 
|  | case OpenACCClauseKind::Wait: | 
|  | case OpenACCClauseKind::NumGangs: | 
|  | case OpenACCClauseKind::NumWorkers: | 
|  | case OpenACCClauseKind::VectorLength: | 
|  | return false; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } else if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Loop) { | 
|  | // Implement check from OpenACC3.3: section 2.9: | 
|  | // Only the collapse, gang, worker, vector, seq, independent, auto, and tile | 
|  | // clauses may follow a device_type clause. | 
|  | switch (NewClause.getClauseKind()) { | 
|  | case OpenACCClauseKind::Collapse: | 
|  | case OpenACCClauseKind::Gang: | 
|  | case OpenACCClauseKind::Worker: | 
|  | case OpenACCClauseKind::Vector: | 
|  | case OpenACCClauseKind::Seq: | 
|  | case OpenACCClauseKind::Independent: | 
|  | case OpenACCClauseKind::Auto: | 
|  | case OpenACCClauseKind::Tile: | 
|  | return false; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } else if (isOpenACCCombinedDirectiveKind(NewClause.getDirectiveKind())) { | 
|  | // This seems like it should be the union of 2.9 and 2.5.4 from above. | 
|  | switch (NewClause.getClauseKind()) { | 
|  | case OpenACCClauseKind::Async: | 
|  | case OpenACCClauseKind::Wait: | 
|  | case OpenACCClauseKind::NumGangs: | 
|  | case OpenACCClauseKind::NumWorkers: | 
|  | case OpenACCClauseKind::VectorLength: | 
|  | case OpenACCClauseKind::Collapse: | 
|  | case OpenACCClauseKind::Gang: | 
|  | case OpenACCClauseKind::Worker: | 
|  | case OpenACCClauseKind::Vector: | 
|  | case OpenACCClauseKind::Seq: | 
|  | case OpenACCClauseKind::Independent: | 
|  | case OpenACCClauseKind::Auto: | 
|  | case OpenACCClauseKind::Tile: | 
|  | return false; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } else if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Data) { | 
|  | // OpenACC3.3 section 2.6.5: Only the async and wait clauses may follow a | 
|  | // device_type clause. | 
|  | switch (NewClause.getClauseKind()) { | 
|  | case OpenACCClauseKind::Async: | 
|  | case OpenACCClauseKind::Wait: | 
|  | return false; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } else if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Set || | 
|  | NewClause.getDirectiveKind() == OpenACCDirectiveKind::Init || | 
|  | NewClause.getDirectiveKind() == OpenACCDirectiveKind::Shutdown) { | 
|  | // There are no restrictions on 'set', 'init', or 'shutdown'. | 
|  | return false; | 
|  | } else if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Update) { | 
|  | // OpenACC3.3 section 2.14.4: Only the async and wait clauses may follow a | 
|  | // device_type clause. | 
|  | switch (NewClause.getClauseKind()) { | 
|  | case OpenACCClauseKind::Async: | 
|  | case OpenACCClauseKind::Wait: | 
|  | return false; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } else if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Routine) { | 
|  | // OpenACC 3.3 section 2.15: Only the 'gang', 'worker', 'vector', 'seq', and | 
|  | // 'bind' clauses may follow a device_type clause. | 
|  | switch (NewClause.getClauseKind()) { | 
|  | case OpenACCClauseKind::Gang: | 
|  | case OpenACCClauseKind::Worker: | 
|  | case OpenACCClauseKind::Vector: | 
|  | case OpenACCClauseKind::Seq: | 
|  | case OpenACCClauseKind::Bind: | 
|  | return false; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | S.Diag(NewClause.getBeginLoc(), diag::err_acc_clause_after_device_type) | 
|  | << NewClause.getClauseKind() << DeviceTypeClause.getClauseKind() | 
|  | << NewClause.getDirectiveKind(); | 
|  | S.Diag(DeviceTypeClause.getBeginLoc(), | 
|  | diag::note_acc_active_applies_clause_here) | 
|  | << diag::ACCDeviceTypeApp::Active << DeviceTypeClause.getClauseKind(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // GCC looks through linkage specs, but not the other transparent declaration | 
|  | // contexts for 'declare' restrictions, so this helper function helps get us | 
|  | // through that. | 
|  | const DeclContext *removeLinkageSpecDC(const DeclContext *DC) { | 
|  | while (isa<LinkageSpecDecl>(DC)) | 
|  | DC = DC->getParent(); | 
|  |  | 
|  | return DC; | 
|  | } | 
|  |  | 
|  | class SemaOpenACCClauseVisitor { | 
|  | SemaOpenACC &SemaRef; | 
|  | ASTContext &Ctx; | 
|  | ArrayRef<const OpenACCClause *> ExistingClauses; | 
|  |  | 
|  | // OpenACC 3.3 2.9: | 
|  | //  A 'gang', 'worker', or 'vector' clause may not appear if a 'seq' clause | 
|  | //  appears. | 
|  | bool | 
|  | DiagGangWorkerVectorSeqConflict(SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop && | 
|  | !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) | 
|  | return false; | 
|  | assert(Clause.getClauseKind() == OpenACCClauseKind::Gang || | 
|  | Clause.getClauseKind() == OpenACCClauseKind::Worker || | 
|  | Clause.getClauseKind() == OpenACCClauseKind::Vector); | 
|  | const auto *Itr = | 
|  | llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSeqClause>); | 
|  |  | 
|  | if (Itr != ExistingClauses.end()) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine) | 
|  | << Clause.getClauseKind() << (*Itr)->getClauseKind() | 
|  | << Clause.getDirectiveKind(); | 
|  | SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here) | 
|  | << (*Itr)->getClauseKind(); | 
|  |  | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | OpenACCModifierKind | 
|  | CheckModifierList(SemaOpenACC::OpenACCParsedClause &Clause, | 
|  | OpenACCModifierKind Mods) { | 
|  | auto CheckSingle = [=](OpenACCModifierKind CurMods, | 
|  | OpenACCModifierKind ValidKinds, | 
|  | OpenACCModifierKind Bit) { | 
|  | if (!isOpenACCModifierBitSet(CurMods, Bit) || | 
|  | isOpenACCModifierBitSet(ValidKinds, Bit)) | 
|  | return CurMods; | 
|  |  | 
|  | SemaRef.Diag(Clause.getLParenLoc(), diag::err_acc_invalid_modifier) | 
|  | << Bit << Clause.getClauseKind(); | 
|  |  | 
|  | return CurMods ^ Bit; | 
|  | }; | 
|  | auto Check = [&](OpenACCModifierKind ValidKinds) { | 
|  | if ((Mods | ValidKinds) == ValidKinds) | 
|  | return Mods; | 
|  |  | 
|  | Mods = CheckSingle(Mods, ValidKinds, OpenACCModifierKind::Always); | 
|  | Mods = CheckSingle(Mods, ValidKinds, OpenACCModifierKind::AlwaysIn); | 
|  | Mods = CheckSingle(Mods, ValidKinds, OpenACCModifierKind::AlwaysOut); | 
|  | Mods = CheckSingle(Mods, ValidKinds, OpenACCModifierKind::Readonly); | 
|  | Mods = CheckSingle(Mods, ValidKinds, OpenACCModifierKind::Zero); | 
|  | Mods = CheckSingle(Mods, ValidKinds, OpenACCModifierKind::Capture); | 
|  | return Mods; | 
|  | }; | 
|  |  | 
|  | // The 'capture' modifier is only valid on copyin, copyout, and create on | 
|  | // structured data or compute constructs (which also includes combined). | 
|  | bool IsStructuredDataOrCompute = | 
|  | Clause.getDirectiveKind() == OpenACCDirectiveKind::Data || | 
|  | isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) || | 
|  | isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()); | 
|  |  | 
|  | switch (Clause.getClauseKind()) { | 
|  | default: | 
|  | llvm_unreachable("Only for copy, copyin, copyout, create"); | 
|  | case OpenACCClauseKind::Copy: | 
|  | case OpenACCClauseKind::PCopy: | 
|  | case OpenACCClauseKind::PresentOrCopy: | 
|  | // COPY: Capture always | 
|  | return Check(OpenACCModifierKind::Always | OpenACCModifierKind::AlwaysIn | | 
|  | OpenACCModifierKind::AlwaysOut | | 
|  | OpenACCModifierKind::Capture); | 
|  | case OpenACCClauseKind::CopyIn: | 
|  | case OpenACCClauseKind::PCopyIn: | 
|  | case OpenACCClauseKind::PresentOrCopyIn: | 
|  | // COPYIN: Capture only struct.data & compute | 
|  | return Check(OpenACCModifierKind::Always | OpenACCModifierKind::AlwaysIn | | 
|  | OpenACCModifierKind::Readonly | | 
|  | (IsStructuredDataOrCompute ? OpenACCModifierKind::Capture | 
|  | : OpenACCModifierKind::Invalid)); | 
|  | case OpenACCClauseKind::CopyOut: | 
|  | case OpenACCClauseKind::PCopyOut: | 
|  | case OpenACCClauseKind::PresentOrCopyOut: | 
|  | // COPYOUT: Capture only struct.data & compute | 
|  | return Check(OpenACCModifierKind::Always | | 
|  | OpenACCModifierKind::AlwaysOut | OpenACCModifierKind::Zero | | 
|  | (IsStructuredDataOrCompute ? OpenACCModifierKind::Capture | 
|  | : OpenACCModifierKind::Invalid)); | 
|  | case OpenACCClauseKind::Create: | 
|  | case OpenACCClauseKind::PCreate: | 
|  | case OpenACCClauseKind::PresentOrCreate: | 
|  | // CREATE: Capture only struct.data & compute | 
|  | return Check(OpenACCModifierKind::Zero | | 
|  | (IsStructuredDataOrCompute ? OpenACCModifierKind::Capture | 
|  | : OpenACCModifierKind::Invalid)); | 
|  | } | 
|  | llvm_unreachable("didn't return from switch above?"); | 
|  | } | 
|  |  | 
|  | // Helper for the 'routine' checks during 'new' clause addition. Precondition | 
|  | // is that we already know the new clause is one of the prohbiited ones. | 
|  | template <typename Pred> | 
|  | bool | 
|  | CheckValidRoutineNewClauseHelper(Pred HasPredicate, | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Routine) | 
|  | return false; | 
|  |  | 
|  | auto *FirstDeviceType = | 
|  | llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCDeviceTypeClause>); | 
|  |  | 
|  | if (FirstDeviceType == ExistingClauses.end()) { | 
|  | // If there isn't a device type yet, ANY duplicate is wrong. | 
|  |  | 
|  | auto *ExistingProhibitedClause = | 
|  | llvm::find_if(ExistingClauses, HasPredicate); | 
|  |  | 
|  | if (ExistingProhibitedClause == ExistingClauses.end()) | 
|  | return false; | 
|  |  | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine) | 
|  | << Clause.getClauseKind() | 
|  | << (*ExistingProhibitedClause)->getClauseKind() | 
|  | << Clause.getDirectiveKind(); | 
|  | SemaRef.Diag((*ExistingProhibitedClause)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*ExistingProhibitedClause)->getClauseKind(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // At this point we know that this is 'after' a device type. So this is an | 
|  | // error if: 1- there is one BEFORE the 'device_type' 2- there is one | 
|  | // between this and the previous 'device_type'. | 
|  |  | 
|  | auto *BeforeDeviceType = | 
|  | std::find_if(ExistingClauses.begin(), FirstDeviceType, HasPredicate); | 
|  | // If there is one before the device_type (and we know we are after a | 
|  | // device_type), than this is ill-formed. | 
|  | if (BeforeDeviceType != FirstDeviceType) { | 
|  | SemaRef.Diag( | 
|  | Clause.getBeginLoc(), | 
|  | diag::err_acc_clause_routine_cannot_combine_before_device_type) | 
|  | << Clause.getClauseKind() << (*BeforeDeviceType)->getClauseKind(); | 
|  | SemaRef.Diag((*BeforeDeviceType)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*BeforeDeviceType)->getClauseKind(); | 
|  | SemaRef.Diag((*FirstDeviceType)->getBeginLoc(), | 
|  | diag::note_acc_active_applies_clause_here) | 
|  | << diag::ACCDeviceTypeApp::Active | 
|  | << (*FirstDeviceType)->getClauseKind(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | auto LastDeviceTypeItr = | 
|  | std::find_if(ExistingClauses.rbegin(), ExistingClauses.rend(), | 
|  | llvm::IsaPred<OpenACCDeviceTypeClause>); | 
|  |  | 
|  | // We already know there is one in the list, so it is nonsensical to not | 
|  | // have one. | 
|  | assert(LastDeviceTypeItr != ExistingClauses.rend()); | 
|  |  | 
|  | // Get the device-type from-the-front (not reverse) iterator from the | 
|  | // reverse iterator. | 
|  | auto *LastDeviceType = LastDeviceTypeItr.base() - 1; | 
|  |  | 
|  | auto *ExistingProhibitedSinceLastDevice = | 
|  | std::find_if(LastDeviceType, ExistingClauses.end(), HasPredicate); | 
|  |  | 
|  | // No prohibited ones since the last device-type. | 
|  | if (ExistingProhibitedSinceLastDevice == ExistingClauses.end()) | 
|  | return false; | 
|  |  | 
|  | SemaRef.Diag(Clause.getBeginLoc(), | 
|  | diag::err_acc_clause_routine_cannot_combine_same_device_type) | 
|  | << Clause.getClauseKind() | 
|  | << (*ExistingProhibitedSinceLastDevice)->getClauseKind(); | 
|  | SemaRef.Diag((*ExistingProhibitedSinceLastDevice)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*ExistingProhibitedSinceLastDevice)->getClauseKind(); | 
|  | SemaRef.Diag((*LastDeviceType)->getBeginLoc(), | 
|  | diag::note_acc_active_applies_clause_here) | 
|  | << diag::ACCDeviceTypeApp::Active << (*LastDeviceType)->getClauseKind(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Routine has a pretty complicated set of rules for how device_type and the | 
|  | // gang, worker, vector, and seq clauses work.  So diagnose some of it here. | 
|  | bool CheckValidRoutineGangWorkerVectorSeqNewClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | if (Clause.getClauseKind() != OpenACCClauseKind::Gang && | 
|  | Clause.getClauseKind() != OpenACCClauseKind::Vector && | 
|  | Clause.getClauseKind() != OpenACCClauseKind::Worker && | 
|  | Clause.getClauseKind() != OpenACCClauseKind::Seq) | 
|  | return false; | 
|  | auto ProhibitedPred = llvm::IsaPred<OpenACCGangClause, OpenACCWorkerClause, | 
|  | OpenACCVectorClause, OpenACCSeqClause>; | 
|  |  | 
|  | return CheckValidRoutineNewClauseHelper(ProhibitedPred, Clause); | 
|  | } | 
|  |  | 
|  | // Bind should have similar rules on a routine as gang/worker/vector/seq, | 
|  | // except there is no 'must have 1' rule, so we can get all the checking done | 
|  | // here. | 
|  | bool | 
|  | CheckValidRoutineBindNewClause(SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | if (Clause.getClauseKind() != OpenACCClauseKind::Bind) | 
|  | return false; | 
|  |  | 
|  | auto HasBindPred = llvm::IsaPred<OpenACCBindClause>; | 
|  | return CheckValidRoutineNewClauseHelper(HasBindPred, Clause); | 
|  | } | 
|  |  | 
|  | // For 'tile' and 'collapse', only allow 1 per 'device_type'. | 
|  | // Also applies to num_worker, num_gangs, vector_length, and async. | 
|  | // This does introspection into the actual device-types to prevent duplicates | 
|  | // across device types as well. | 
|  | template <typename TheClauseTy> | 
|  | bool DisallowSinceLastDeviceType(SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | auto LastDeviceTypeItr = | 
|  | std::find_if(ExistingClauses.rbegin(), ExistingClauses.rend(), | 
|  | llvm::IsaPred<OpenACCDeviceTypeClause>); | 
|  |  | 
|  | auto LastSinceDevTy = | 
|  | std::find_if(ExistingClauses.rbegin(), LastDeviceTypeItr, | 
|  | llvm::IsaPred<TheClauseTy>); | 
|  |  | 
|  | // In this case there is a duplicate since the last device_type/lack of a | 
|  | // device_type.  Diagnose these as duplicates. | 
|  | if (LastSinceDevTy != LastDeviceTypeItr) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), | 
|  | diag::err_acc_clause_since_last_device_type) | 
|  | << Clause.getClauseKind() << Clause.getDirectiveKind() | 
|  | << (LastDeviceTypeItr != ExistingClauses.rend()); | 
|  |  | 
|  | SemaRef.Diag((*LastSinceDevTy)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*LastSinceDevTy)->getClauseKind(); | 
|  |  | 
|  | // Mention the last device_type as well. | 
|  | if (LastDeviceTypeItr != ExistingClauses.rend()) | 
|  | SemaRef.Diag((*LastDeviceTypeItr)->getBeginLoc(), | 
|  | diag::note_acc_active_applies_clause_here) | 
|  | << diag::ACCDeviceTypeApp::Active | 
|  | << (*LastDeviceTypeItr)->getClauseKind(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // If this isn't in a device_type, and we didn't diagnose that there are | 
|  | // dupes above, just give up, no sense in searching for previous device_type | 
|  | // regions as they don't exist. | 
|  | if (LastDeviceTypeItr == ExistingClauses.rend()) | 
|  | return false; | 
|  |  | 
|  | // The device-type that is active for us, so we can compare to the previous | 
|  | // ones. | 
|  | const auto &ActiveDeviceTypeClause = | 
|  | cast<OpenACCDeviceTypeClause>(**LastDeviceTypeItr); | 
|  |  | 
|  | auto PrevDeviceTypeItr = LastDeviceTypeItr; | 
|  | auto CurDevTypeItr = LastDeviceTypeItr; | 
|  |  | 
|  | while ((CurDevTypeItr = std::find_if( | 
|  | std::next(PrevDeviceTypeItr), ExistingClauses.rend(), | 
|  | llvm::IsaPred<OpenACCDeviceTypeClause>)) != | 
|  | ExistingClauses.rend()) { | 
|  | // At this point, we know that we have a region between two device_types, | 
|  | // as specified by CurDevTypeItr and PrevDeviceTypeItr. | 
|  |  | 
|  | auto CurClauseKindItr = std::find_if(PrevDeviceTypeItr, CurDevTypeItr, | 
|  | llvm::IsaPred<TheClauseTy>); | 
|  |  | 
|  | // There are no clauses of the current kind between these device_types, so | 
|  | // continue. | 
|  | if (CurClauseKindItr == CurDevTypeItr) { | 
|  | PrevDeviceTypeItr = CurDevTypeItr; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // At this point, we know that this device_type region has a collapse.  So | 
|  | // diagnose if the two device_types have any overlap in their | 
|  | // architectures. | 
|  | const auto &CurDeviceTypeClause = | 
|  | cast<OpenACCDeviceTypeClause>(**CurDevTypeItr); | 
|  |  | 
|  | for (const DeviceTypeArgument &arg : | 
|  | ActiveDeviceTypeClause.getArchitectures()) { | 
|  | for (const DeviceTypeArgument &prevArg : | 
|  | CurDeviceTypeClause.getArchitectures()) { | 
|  |  | 
|  | // This should catch duplicates * regions, duplicate same-text (thanks | 
|  | // to identifier equiv.) and case insensitive dupes. | 
|  | if (arg.getIdentifierInfo() == prevArg.getIdentifierInfo() || | 
|  | (arg.getIdentifierInfo() && prevArg.getIdentifierInfo() && | 
|  | StringRef{arg.getIdentifierInfo()->getName()}.equals_insensitive( | 
|  | prevArg.getIdentifierInfo()->getName()))) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), | 
|  | diag::err_acc_clause_conflicts_prev_dev_type) | 
|  | << Clause.getClauseKind() | 
|  | << (arg.getIdentifierInfo() ? arg.getIdentifierInfo()->getName() | 
|  | : "*"); | 
|  | // mention the active device type. | 
|  | SemaRef.Diag(ActiveDeviceTypeClause.getBeginLoc(), | 
|  | diag::note_acc_active_applies_clause_here) | 
|  | << diag::ACCDeviceTypeApp::Active | 
|  | << ActiveDeviceTypeClause.getClauseKind(); | 
|  | // mention the previous clause. | 
|  | SemaRef.Diag((*CurClauseKindItr)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*CurClauseKindItr)->getClauseKind(); | 
|  | // mention the previous device type. | 
|  | SemaRef.Diag(CurDeviceTypeClause.getBeginLoc(), | 
|  | diag::note_acc_active_applies_clause_here) | 
|  | << diag::ACCDeviceTypeApp::Applies | 
|  | << CurDeviceTypeClause.getClauseKind(); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | PrevDeviceTypeItr = CurDevTypeItr; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | public: | 
|  | SemaOpenACCClauseVisitor(SemaOpenACC &S, | 
|  | ArrayRef<const OpenACCClause *> ExistingClauses) | 
|  | : SemaRef(S), Ctx(S.getASTContext()), ExistingClauses(ExistingClauses) {} | 
|  |  | 
|  | OpenACCClause *Visit(SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | if (SemaRef.DiagnoseAllowedOnceClauses( | 
|  | Clause.getDirectiveKind(), Clause.getClauseKind(), | 
|  | Clause.getBeginLoc(), ExistingClauses) || | 
|  | SemaRef.DiagnoseExclusiveClauses(Clause.getDirectiveKind(), | 
|  | Clause.getClauseKind(), | 
|  | Clause.getBeginLoc(), ExistingClauses)) | 
|  | return nullptr; | 
|  | if (CheckValidRoutineGangWorkerVectorSeqNewClause(Clause) || | 
|  | CheckValidRoutineBindNewClause(Clause)) | 
|  | return nullptr; | 
|  |  | 
|  | switch (Clause.getClauseKind()) { | 
|  | case OpenACCClauseKind::Shortloop: | 
|  | llvm_unreachable("Shortloop shouldn't be generated in clang"); | 
|  | case OpenACCClauseKind::Invalid: | 
|  | return nullptr; | 
|  | #define VISIT_CLAUSE(CLAUSE_NAME)                                              \ | 
|  | case OpenACCClauseKind::CLAUSE_NAME:                                         \ | 
|  | return Visit##CLAUSE_NAME##Clause(Clause); | 
|  | #define CLAUSE_ALIAS(ALIAS, CLAUSE_NAME, DEPRECATED)                           \ | 
|  | case OpenACCClauseKind::ALIAS:                                               \ | 
|  | if (DEPRECATED)                                                              \ | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::warn_acc_deprecated_alias_name)   \ | 
|  | << Clause.getClauseKind() << OpenACCClauseKind::CLAUSE_NAME;           \ | 
|  | return Visit##CLAUSE_NAME##Clause(Clause); | 
|  | #include "clang/Basic/OpenACCClauses.def" | 
|  | } | 
|  | llvm_unreachable("Invalid clause kind"); | 
|  | } | 
|  |  | 
|  | #define VISIT_CLAUSE(CLAUSE_NAME)                                              \ | 
|  | OpenACCClause *Visit##CLAUSE_NAME##Clause(                                   \ | 
|  | SemaOpenACC::OpenACCParsedClause &Clause); | 
|  | #include "clang/Basic/OpenACCClauses.def" | 
|  | }; | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitDefaultClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // Don't add an invalid clause to the AST. | 
|  | if (Clause.getDefaultClauseKind() == OpenACCDefaultClauseKind::Invalid) | 
|  | return nullptr; | 
|  |  | 
|  | return OpenACCDefaultClause::Create( | 
|  | Ctx, Clause.getDefaultClauseKind(), Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitTileClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | if (DisallowSinceLastDeviceType<OpenACCTileClause>(Clause)) | 
|  | return nullptr; | 
|  |  | 
|  | llvm::SmallVector<Expr *> NewSizeExprs; | 
|  |  | 
|  | // Make sure these are all positive constant expressions or *. | 
|  | for (Expr *E : Clause.getIntExprs()) { | 
|  | ExprResult Res = SemaRef.CheckTileSizeExpr(E); | 
|  |  | 
|  | if (!Res.isUsable()) | 
|  | return nullptr; | 
|  |  | 
|  | NewSizeExprs.push_back(Res.get()); | 
|  | } | 
|  |  | 
|  | return OpenACCTileClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), NewSizeExprs, | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | // The parser has ensured that we have a proper condition expr, so there | 
|  | // isn't really much to do here. | 
|  |  | 
|  | // If the 'if' clause is true, it makes the 'self' clause have no effect, | 
|  | // diagnose that here.  This only applies on compute/combined constructs. | 
|  | if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Update) { | 
|  | const auto *Itr = | 
|  | llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSelfClause>); | 
|  | if (Itr != ExistingClauses.end()) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::warn_acc_if_self_conflict); | 
|  | SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here) | 
|  | << (*Itr)->getClauseKind(); | 
|  | } | 
|  | } | 
|  |  | 
|  | return OpenACCIfClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), | 
|  | Clause.getConditionExpr(), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitSelfClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | // If the 'if' clause is true, it makes the 'self' clause have no effect, | 
|  | // diagnose that here.  This only applies on compute/combined constructs. | 
|  | if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Update) | 
|  | return OpenACCSelfClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), Clause.getVarList(), | 
|  | Clause.getEndLoc()); | 
|  |  | 
|  | const auto *Itr = | 
|  | llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCIfClause>); | 
|  | if (Itr != ExistingClauses.end()) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::warn_acc_if_self_conflict); | 
|  | SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here) | 
|  | << (*Itr)->getClauseKind(); | 
|  | } | 
|  | return OpenACCSelfClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), | 
|  | Clause.getConditionExpr(), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitNumGangsClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | if (DisallowSinceLastDeviceType<OpenACCNumGangsClause>(Clause)) | 
|  | return nullptr; | 
|  |  | 
|  | // num_gangs requires at least 1 int expr in all forms.  Diagnose here, but | 
|  | // allow us to continue, an empty clause might be useful for future | 
|  | // diagnostics. | 
|  | if (Clause.getIntExprs().empty()) | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_num_gangs_num_args) | 
|  | << /*NoArgs=*/0; | 
|  |  | 
|  | unsigned MaxArgs = | 
|  | (Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel || | 
|  | Clause.getDirectiveKind() == OpenACCDirectiveKind::ParallelLoop) | 
|  | ? 3 | 
|  | : 1; | 
|  | // The max number of args differs between parallel and other constructs. | 
|  | // Again, allow us to continue for the purposes of future diagnostics. | 
|  | if (Clause.getIntExprs().size() > MaxArgs) | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_num_gangs_num_args) | 
|  | << /*NoArgs=*/1 << Clause.getDirectiveKind() << MaxArgs | 
|  | << Clause.getIntExprs().size(); | 
|  |  | 
|  | // OpenACC 3.3 Section 2.9.11: A reduction clause may not appear on a loop | 
|  | // directive that has a gang clause and is within a compute construct that has | 
|  | // a num_gangs clause with more than one explicit argument. | 
|  | if (Clause.getIntExprs().size() > 1 && | 
|  | isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) { | 
|  | auto *GangClauseItr = | 
|  | llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCGangClause>); | 
|  | auto *ReductionClauseItr = | 
|  | llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCReductionClause>); | 
|  |  | 
|  | if (GangClauseItr != ExistingClauses.end() && | 
|  | ReductionClauseItr != ExistingClauses.end()) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), | 
|  | diag::err_acc_gang_reduction_numgangs_conflict) | 
|  | << OpenACCClauseKind::Reduction << OpenACCClauseKind::Gang | 
|  | << Clause.getDirectiveKind() << /*is on combined directive=*/1; | 
|  | SemaRef.Diag((*ReductionClauseItr)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*ReductionClauseItr)->getClauseKind(); | 
|  | SemaRef.Diag((*GangClauseItr)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*GangClauseItr)->getClauseKind(); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | // OpenACC 3.3 Section 2.5.4: | 
|  | // A reduction clause may not appear on a parallel construct with a | 
|  | // num_gangs clause that has more than one argument. | 
|  | if ((Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel || | 
|  | Clause.getDirectiveKind() == OpenACCDirectiveKind::ParallelLoop) && | 
|  | Clause.getIntExprs().size() > 1) { | 
|  | auto *Parallel = | 
|  | llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCReductionClause>); | 
|  |  | 
|  | if (Parallel != ExistingClauses.end()) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), | 
|  | diag::err_acc_reduction_num_gangs_conflict) | 
|  | << /*>1 arg in first loc=*/1 << Clause.getClauseKind() | 
|  | << Clause.getDirectiveKind() << OpenACCClauseKind::Reduction; | 
|  | SemaRef.Diag((*Parallel)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*Parallel)->getClauseKind(); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | // OpenACC 3.3 Section 2.9.2: | 
|  | // An argument with no keyword or with the 'num' keyword is allowed only when | 
|  | // the 'num_gangs' does not appear on the 'kernel' construct. | 
|  | if (Clause.getDirectiveKind() == OpenACCDirectiveKind::KernelsLoop) { | 
|  | auto GangClauses = llvm::make_filter_range( | 
|  | ExistingClauses, llvm::IsaPred<OpenACCGangClause>); | 
|  |  | 
|  | for (auto *GC : GangClauses) { | 
|  | if (cast<OpenACCGangClause>(GC)->hasExprOfKind(OpenACCGangKind::Num)) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), | 
|  | diag::err_acc_num_arg_conflict_reverse) | 
|  | << OpenACCClauseKind::NumGangs << OpenACCClauseKind::Gang | 
|  | << /*Num argument*/ 1; | 
|  | SemaRef.Diag(GC->getBeginLoc(), diag::note_acc_previous_clause_here) | 
|  | << GC->getClauseKind(); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return OpenACCNumGangsClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getIntExprs(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitNumWorkersClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | if (DisallowSinceLastDeviceType<OpenACCNumWorkersClause>(Clause)) | 
|  | return nullptr; | 
|  |  | 
|  | // OpenACC 3.3 Section 2.9.2: | 
|  | // An argument is allowed only when the 'num_workers' does not appear on the | 
|  | // kernels construct. | 
|  | if (Clause.getDirectiveKind() == OpenACCDirectiveKind::KernelsLoop) { | 
|  | auto WorkerClauses = llvm::make_filter_range( | 
|  | ExistingClauses, llvm::IsaPred<OpenACCWorkerClause>); | 
|  |  | 
|  | for (auto *WC : WorkerClauses) { | 
|  | if (cast<OpenACCWorkerClause>(WC)->hasIntExpr()) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), | 
|  | diag::err_acc_num_arg_conflict_reverse) | 
|  | << OpenACCClauseKind::NumWorkers << OpenACCClauseKind::Worker | 
|  | << /*num argument*/ 0; | 
|  | SemaRef.Diag(WC->getBeginLoc(), diag::note_acc_previous_clause_here) | 
|  | << WC->getClauseKind(); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | assert(Clause.getIntExprs().size() == 1 && | 
|  | "Invalid number of expressions for NumWorkers"); | 
|  | return OpenACCNumWorkersClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getIntExprs()[0], | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitVectorLengthClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | if (DisallowSinceLastDeviceType<OpenACCVectorLengthClause>(Clause)) | 
|  | return nullptr; | 
|  |  | 
|  | // OpenACC 3.3 Section 2.9.4: | 
|  | // An argument is allowed only when the 'vector_length' does not appear on the | 
|  | // 'kernels' construct. | 
|  | if (Clause.getDirectiveKind() == OpenACCDirectiveKind::KernelsLoop) { | 
|  | auto VectorClauses = llvm::make_filter_range( | 
|  | ExistingClauses, llvm::IsaPred<OpenACCVectorClause>); | 
|  |  | 
|  | for (auto *VC : VectorClauses) { | 
|  | if (cast<OpenACCVectorClause>(VC)->hasIntExpr()) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), | 
|  | diag::err_acc_num_arg_conflict_reverse) | 
|  | << OpenACCClauseKind::VectorLength << OpenACCClauseKind::Vector | 
|  | << /*num argument*/ 0; | 
|  | SemaRef.Diag(VC->getBeginLoc(), diag::note_acc_previous_clause_here) | 
|  | << VC->getClauseKind(); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | assert(Clause.getIntExprs().size() == 1 && | 
|  | "Invalid number of expressions for NumWorkers"); | 
|  | return OpenACCVectorLengthClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getIntExprs()[0], | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitAsyncClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | if (DisallowSinceLastDeviceType<OpenACCAsyncClause>(Clause)) | 
|  | return nullptr; | 
|  |  | 
|  | assert(Clause.getNumIntExprs() < 2 && | 
|  | "Invalid number of expressions for Async"); | 
|  | return OpenACCAsyncClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), | 
|  | Clause.getNumIntExprs() != 0 ? Clause.getIntExprs()[0] : nullptr, | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceNumClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | assert(Clause.getNumIntExprs() == 1 && | 
|  | "Invalid number of expressions for device_num"); | 
|  | return OpenACCDeviceNumClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getIntExprs()[0], | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitDefaultAsyncClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | assert(Clause.getNumIntExprs() == 1 && | 
|  | "Invalid number of expressions for default_async"); | 
|  | return OpenACCDefaultAsyncClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getIntExprs()[0], | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitPrivateClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, so there | 
|  | // really isn't anything to do here. GCC does some duplicate-finding, though | 
|  | // it isn't apparent in the standard where this is justified. | 
|  |  | 
|  | return OpenACCPrivateClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), | 
|  | Clause.getVarList(), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitFirstPrivateClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, so there | 
|  | // really isn't anything to do here. GCC does some duplicate-finding, though | 
|  | // it isn't apparent in the standard where this is justified. | 
|  |  | 
|  | return OpenACCFirstPrivateClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitNoCreateClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, so there | 
|  | // really isn't anything to do here. GCC does some duplicate-finding, though | 
|  | // it isn't apparent in the standard where this is justified. | 
|  |  | 
|  | return OpenACCNoCreateClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), | 
|  | Clause.getVarList(), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitPresentClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, so there | 
|  | // really isn't anything to do here. GCC does some duplicate-finding, though | 
|  | // it isn't apparent in the standard where this is justified. | 
|  |  | 
|  | // 'declare' has some restrictions that need to be enforced separately, so | 
|  | // check it here. | 
|  | if (SemaRef.CheckDeclareClause(Clause, OpenACCModifierKind::Invalid)) | 
|  | return nullptr; | 
|  |  | 
|  | return OpenACCPresentClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), | 
|  | Clause.getVarList(), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitHostClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, so there | 
|  | // really isn't anything to do here. GCC does some duplicate-finding, though | 
|  | // it isn't apparent in the standard where this is justified. | 
|  |  | 
|  | return OpenACCHostClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), Clause.getVarList(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, so there | 
|  | // really isn't anything to do here. GCC does some duplicate-finding, though | 
|  | // it isn't apparent in the standard where this is justified. | 
|  |  | 
|  | return OpenACCDeviceClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), Clause.getVarList(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, so there | 
|  | // really isn't anything to do here. GCC does some duplicate-finding, though | 
|  | // it isn't apparent in the standard where this is justified. | 
|  |  | 
|  | OpenACCModifierKind NewMods = | 
|  | CheckModifierList(Clause, Clause.getModifierList()); | 
|  |  | 
|  | // 'declare' has some restrictions that need to be enforced separately, so | 
|  | // check it here. | 
|  | if (SemaRef.CheckDeclareClause(Clause, NewMods)) | 
|  | return nullptr; | 
|  |  | 
|  | return OpenACCCopyClause::Create( | 
|  | Ctx, Clause.getClauseKind(), Clause.getBeginLoc(), Clause.getLParenLoc(), | 
|  | Clause.getModifierList(), Clause.getVarList(), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitLinkClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // 'declare' has some restrictions that need to be enforced separately, so | 
|  | // check it here. | 
|  | if (SemaRef.CheckDeclareClause(Clause, OpenACCModifierKind::Invalid)) | 
|  | return nullptr; | 
|  |  | 
|  | Clause.setVarListDetails(SemaRef.CheckLinkClauseVarList(Clause.getVarList()), | 
|  | OpenACCModifierKind::Invalid); | 
|  |  | 
|  | return OpenACCLinkClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), Clause.getVarList(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceResidentClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // 'declare' has some restrictions that need to be enforced separately, so | 
|  | // check it here. | 
|  | if (SemaRef.CheckDeclareClause(Clause, OpenACCModifierKind::Invalid)) | 
|  | return nullptr; | 
|  |  | 
|  | return OpenACCDeviceResidentClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyInClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, so there | 
|  | // really isn't anything to do here. GCC does some duplicate-finding, though | 
|  | // it isn't apparent in the standard where this is justified. | 
|  |  | 
|  | OpenACCModifierKind NewMods = | 
|  | CheckModifierList(Clause, Clause.getModifierList()); | 
|  |  | 
|  | // 'declare' has some restrictions that need to be enforced separately, so | 
|  | // check it here. | 
|  | if (SemaRef.CheckDeclareClause(Clause, NewMods)) | 
|  | return nullptr; | 
|  |  | 
|  | return OpenACCCopyInClause::Create( | 
|  | Ctx, Clause.getClauseKind(), Clause.getBeginLoc(), Clause.getLParenLoc(), | 
|  | Clause.getModifierList(), Clause.getVarList(), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyOutClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, so there | 
|  | // really isn't anything to do here. GCC does some duplicate-finding, though | 
|  | // it isn't apparent in the standard where this is justified. | 
|  |  | 
|  | OpenACCModifierKind NewMods = | 
|  | CheckModifierList(Clause, Clause.getModifierList()); | 
|  |  | 
|  | // 'declare' has some restrictions that need to be enforced separately, so | 
|  | // check it here. | 
|  | if (SemaRef.CheckDeclareClause(Clause, NewMods)) | 
|  | return nullptr; | 
|  |  | 
|  | return OpenACCCopyOutClause::Create( | 
|  | Ctx, Clause.getClauseKind(), Clause.getBeginLoc(), Clause.getLParenLoc(), | 
|  | Clause.getModifierList(), Clause.getVarList(), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitCreateClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, so there | 
|  | // really isn't anything to do here. GCC does some duplicate-finding, though | 
|  | // it isn't apparent in the standard where this is justified. | 
|  |  | 
|  | OpenACCModifierKind NewMods = | 
|  | CheckModifierList(Clause, Clause.getModifierList()); | 
|  |  | 
|  | // 'declare' has some restrictions that need to be enforced separately, so | 
|  | // check it here. | 
|  | if (SemaRef.CheckDeclareClause(Clause, NewMods)) | 
|  | return nullptr; | 
|  |  | 
|  | return OpenACCCreateClause::Create( | 
|  | Ctx, Clause.getClauseKind(), Clause.getBeginLoc(), Clause.getLParenLoc(), | 
|  | Clause.getModifierList(), Clause.getVarList(), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitAttachClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, but we | 
|  | // still have to make sure it is a pointer type. | 
|  | llvm::SmallVector<Expr *> VarList{Clause.getVarList()}; | 
|  | llvm::erase_if(VarList, [&](Expr *E) { | 
|  | return SemaRef.CheckVarIsPointerType(OpenACCClauseKind::Attach, E); | 
|  | }); | 
|  | Clause.setVarListDetails(VarList, OpenACCModifierKind::Invalid); | 
|  | return OpenACCAttachClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), Clause.getVarList(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitDetachClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, but we | 
|  | // still have to make sure it is a pointer type. | 
|  | llvm::SmallVector<Expr *> VarList{Clause.getVarList()}; | 
|  | llvm::erase_if(VarList, [&](Expr *E) { | 
|  | return SemaRef.CheckVarIsPointerType(OpenACCClauseKind::Detach, E); | 
|  | }); | 
|  | Clause.setVarListDetails(VarList, OpenACCModifierKind::Invalid); | 
|  | return OpenACCDetachClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), Clause.getVarList(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitDeleteClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, so there | 
|  | // really isn't anything to do here. GCC does some duplicate-finding, though | 
|  | // it isn't apparent in the standard where this is justified. | 
|  | return OpenACCDeleteClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), Clause.getVarList(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitUseDeviceClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable or array, so nothing | 
|  | // left to do here. | 
|  | return OpenACCUseDeviceClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitDevicePtrClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // ActOnVar ensured that everything is a valid variable reference, but we | 
|  | // still have to make sure it is a pointer type. | 
|  | llvm::SmallVector<Expr *> VarList{Clause.getVarList()}; | 
|  | llvm::erase_if(VarList, [&](Expr *E) { | 
|  | return SemaRef.CheckVarIsPointerType(OpenACCClauseKind::DevicePtr, E); | 
|  | }); | 
|  | Clause.setVarListDetails(VarList, OpenACCModifierKind::Invalid); | 
|  |  | 
|  | // 'declare' has some restrictions that need to be enforced separately, so | 
|  | // check it here. | 
|  | if (SemaRef.CheckDeclareClause(Clause, OpenACCModifierKind::Invalid)) | 
|  | return nullptr; | 
|  |  | 
|  | return OpenACCDevicePtrClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitWaitClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | return OpenACCWaitClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getDevNumExpr(), | 
|  | Clause.getQueuesLoc(), Clause.getQueueIdExprs(), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceTypeClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | // Based on discussions, having more than 1 'architecture' on a 'set' is | 
|  | // nonsensical, so we're going to fix the standard to reflect this.  Implement | 
|  | // the limitation, since the Dialect requires this. | 
|  | if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Set && | 
|  | Clause.getDeviceTypeArchitectures().size() > 1) { | 
|  | SemaRef.Diag(Clause.getDeviceTypeArchitectures()[1].getLoc(), | 
|  | diag::err_acc_device_type_multiple_archs); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // The list of valid device_type values. Flang also has these hardcoded in | 
|  | // openacc_parsers.cpp, as there does not seem to be a reliable backend | 
|  | // source. The list below is sourced from Flang, though NVC++ supports only | 
|  | // 'nvidia', 'host', 'multicore', and 'default'. | 
|  | const std::array<llvm::StringLiteral, 6> ValidValues{ | 
|  | "default", "nvidia", "acc_device_nvidia", "radeon", "host", "multicore"}; | 
|  | // As an optimization, we have a manually maintained list of valid values | 
|  | // below, rather than trying to calculate from above. These should be kept in | 
|  | // sync if/when the above list ever changes. | 
|  | std::string ValidValuesString = | 
|  | "'default', 'nvidia', 'acc_device_nvidia', 'radeon', 'host', 'multicore'"; | 
|  |  | 
|  | llvm::SmallVector<DeviceTypeArgument> Architectures{ | 
|  | Clause.getDeviceTypeArchitectures()}; | 
|  |  | 
|  | // The parser has ensured that we either have a single entry of just '*' | 
|  | // (represented by a nullptr IdentifierInfo), or a list. | 
|  |  | 
|  | bool Diagnosed = false; | 
|  | auto FilterPred = [&](const DeviceTypeArgument &Arch) { | 
|  | // The '*' case. | 
|  | if (!Arch.getIdentifierInfo()) | 
|  | return false; | 
|  | return llvm::find_if(ValidValues, [&](StringRef RHS) { | 
|  | return Arch.getIdentifierInfo()->getName().equals_insensitive(RHS); | 
|  | }) == ValidValues.end(); | 
|  | }; | 
|  |  | 
|  | auto Diagnose = [&](const DeviceTypeArgument &Arch) { | 
|  | Diagnosed = SemaRef.Diag(Arch.getLoc(), diag::err_acc_invalid_default_type) | 
|  | << Arch.getIdentifierInfo() << Clause.getClauseKind() | 
|  | << ValidValuesString; | 
|  | }; | 
|  |  | 
|  | // There aren't stable enumertor versions of 'for-each-then-erase', so do it | 
|  | // here.  We DO keep track of whether we diagnosed something to make sure we | 
|  | // don't do the 'erase_if' in the event that the first list didn't find | 
|  | // anything. | 
|  | llvm::for_each(llvm::make_filter_range(Architectures, FilterPred), Diagnose); | 
|  | if (Diagnosed) | 
|  | llvm::erase_if(Architectures, FilterPred); | 
|  |  | 
|  | return OpenACCDeviceTypeClause::Create( | 
|  | Ctx, Clause.getClauseKind(), Clause.getBeginLoc(), Clause.getLParenLoc(), | 
|  | Architectures, Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitAutoClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | return OpenACCAutoClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitNoHostClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | return OpenACCNoHostClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitIndependentClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | return OpenACCIndependentClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | ExprResult CheckGangStaticExpr(SemaOpenACC &S, Expr *E) { | 
|  | if (isa<OpenACCAsteriskSizeExpr>(E)) | 
|  | return E; | 
|  | return S.ActOnIntExpr(OpenACCDirectiveKind::Invalid, OpenACCClauseKind::Gang, | 
|  | E->getBeginLoc(), E); | 
|  | } | 
|  |  | 
|  | bool IsOrphanLoop(OpenACCDirectiveKind DK, OpenACCDirectiveKind AssocKind) { | 
|  | return DK == OpenACCDirectiveKind::Loop && | 
|  | AssocKind == OpenACCDirectiveKind::Invalid; | 
|  | } | 
|  |  | 
|  | bool HasAssocKind(OpenACCDirectiveKind DK, OpenACCDirectiveKind AssocKind) { | 
|  | return DK == OpenACCDirectiveKind::Loop && | 
|  | AssocKind != OpenACCDirectiveKind::Invalid; | 
|  | } | 
|  |  | 
|  | ExprResult DiagIntArgInvalid(SemaOpenACC &S, Expr *E, OpenACCGangKind GK, | 
|  | OpenACCClauseKind CK, OpenACCDirectiveKind DK, | 
|  | OpenACCDirectiveKind AssocKind) { | 
|  | S.Diag(E->getBeginLoc(), diag::err_acc_int_arg_invalid) | 
|  | << GK << CK << IsOrphanLoop(DK, AssocKind) << DK | 
|  | << HasAssocKind(DK, AssocKind) << AssocKind; | 
|  | return ExprError(); | 
|  | } | 
|  | ExprResult DiagIntArgInvalid(SemaOpenACC &S, Expr *E, StringRef TagKind, | 
|  | OpenACCClauseKind CK, OpenACCDirectiveKind DK, | 
|  | OpenACCDirectiveKind AssocKind) { | 
|  | S.Diag(E->getBeginLoc(), diag::err_acc_int_arg_invalid) | 
|  | << TagKind << CK << IsOrphanLoop(DK, AssocKind) << DK | 
|  | << HasAssocKind(DK, AssocKind) << AssocKind; | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | ExprResult CheckGangDimExpr(SemaOpenACC &S, Expr *E) { | 
|  | // OpenACC 3.3 2.9.2: When the parent compute construct is a parallel | 
|  | // construct, or an orphaned loop construct, the gang clause behaves as | 
|  | // follows. ... The dim argument must be a constant positive integer value | 
|  | // 1, 2, or 3. | 
|  | // -also- | 
|  | // OpenACC 3.3 2.15: The 'dim' argument must be a constant positive integer | 
|  | // with value 1, 2, or 3. | 
|  | if (!E) | 
|  | return ExprError(); | 
|  | ExprResult Res = S.ActOnIntExpr(OpenACCDirectiveKind::Invalid, | 
|  | OpenACCClauseKind::Gang, E->getBeginLoc(), E); | 
|  |  | 
|  | if (!Res.isUsable()) | 
|  | return Res; | 
|  |  | 
|  | if (Res.get()->isInstantiationDependent()) | 
|  | return Res; | 
|  |  | 
|  | std::optional<llvm::APSInt> ICE = | 
|  | Res.get()->getIntegerConstantExpr(S.getASTContext()); | 
|  |  | 
|  | if (!ICE || *ICE <= 0 || ICE > 3) { | 
|  | S.Diag(Res.get()->getBeginLoc(), diag::err_acc_gang_dim_value) | 
|  | << ICE.has_value() << ICE.value_or(llvm::APSInt{}).getExtValue(); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | return ExprResult{ | 
|  | ConstantExpr::Create(S.getASTContext(), Res.get(), APValue{*ICE})}; | 
|  | } | 
|  |  | 
|  | ExprResult CheckGangParallelExpr(SemaOpenACC &S, OpenACCDirectiveKind DK, | 
|  | OpenACCDirectiveKind AssocKind, | 
|  | OpenACCGangKind GK, Expr *E) { | 
|  | switch (GK) { | 
|  | case OpenACCGangKind::Static: | 
|  | return CheckGangStaticExpr(S, E); | 
|  | case OpenACCGangKind::Num: | 
|  | // OpenACC 3.3 2.9.2: When the parent compute construct is a parallel | 
|  | // construct, or an orphaned loop construct, the gang clause behaves as | 
|  | // follows. ... The num argument is not allowed. | 
|  | return DiagIntArgInvalid(S, E, GK, OpenACCClauseKind::Gang, DK, AssocKind); | 
|  | case OpenACCGangKind::Dim: | 
|  | return CheckGangDimExpr(S, E); | 
|  | } | 
|  | llvm_unreachable("Unknown gang kind in gang parallel check"); | 
|  | } | 
|  |  | 
|  | ExprResult CheckGangKernelsExpr(SemaOpenACC &S, | 
|  | ArrayRef<const OpenACCClause *> ExistingClauses, | 
|  | OpenACCDirectiveKind DK, | 
|  | OpenACCDirectiveKind AssocKind, | 
|  | OpenACCGangKind GK, Expr *E) { | 
|  | switch (GK) { | 
|  | // OpenACC 3.3 2.9.2: When the parent compute construct is a kernels | 
|  | // construct, the gang clause behaves as follows. ... The dim argument is | 
|  | // not allowed. | 
|  | case OpenACCGangKind::Dim: | 
|  | return DiagIntArgInvalid(S, E, GK, OpenACCClauseKind::Gang, DK, AssocKind); | 
|  | case OpenACCGangKind::Num: { | 
|  | // OpenACC 3.3 2.9.2: When the parent compute construct is a kernels | 
|  | // construct, the gang clause behaves as follows. ... An argument with no | 
|  | // keyword or with num keyword is only allowed when num_gangs does not | 
|  | // appear on the kernels construct. ... The region of a loop with the gang | 
|  | // clause may not contain another loop with a gang clause unless within a | 
|  | // nested compute region. | 
|  |  | 
|  | // If this is a 'combined' construct, search the list of existing clauses. | 
|  | // Else we need to search the containing 'kernel'. | 
|  | auto Collection = isOpenACCCombinedDirectiveKind(DK) | 
|  | ? ExistingClauses | 
|  | : S.getActiveComputeConstructInfo().Clauses; | 
|  |  | 
|  | const auto *Itr = | 
|  | llvm::find_if(Collection, llvm::IsaPred<OpenACCNumGangsClause>); | 
|  |  | 
|  | if (Itr != Collection.end()) { | 
|  | S.Diag(E->getBeginLoc(), diag::err_acc_num_arg_conflict) | 
|  | << "num" << OpenACCClauseKind::Gang << DK | 
|  | << HasAssocKind(DK, AssocKind) << AssocKind | 
|  | << OpenACCClauseKind::NumGangs; | 
|  |  | 
|  | S.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here) | 
|  | << (*Itr)->getClauseKind(); | 
|  | return ExprError(); | 
|  | } | 
|  | return ExprResult{E}; | 
|  | } | 
|  | case OpenACCGangKind::Static: | 
|  | return CheckGangStaticExpr(S, E); | 
|  | } | 
|  | llvm_unreachable("Unknown gang kind in gang kernels check"); | 
|  | } | 
|  |  | 
|  | ExprResult CheckGangSerialExpr(SemaOpenACC &S, OpenACCDirectiveKind DK, | 
|  | OpenACCDirectiveKind AssocKind, | 
|  | OpenACCGangKind GK, Expr *E) { | 
|  | switch (GK) { | 
|  | // 'dim' and 'num' don't really make sense on serial, and GCC rejects them | 
|  | // too, so we disallow them too. | 
|  | case OpenACCGangKind::Dim: | 
|  | case OpenACCGangKind::Num: | 
|  | return DiagIntArgInvalid(S, E, GK, OpenACCClauseKind::Gang, DK, AssocKind); | 
|  | case OpenACCGangKind::Static: | 
|  | return CheckGangStaticExpr(S, E); | 
|  | } | 
|  | llvm_unreachable("Unknown gang kind in gang serial check"); | 
|  | } | 
|  |  | 
|  | ExprResult CheckGangRoutineExpr(SemaOpenACC &S, OpenACCDirectiveKind DK, | 
|  | OpenACCDirectiveKind AssocKind, | 
|  | OpenACCGangKind GK, Expr *E) { | 
|  | switch (GK) { | 
|  | // Only 'dim' is allowed on a routine, so diallow num and static. | 
|  | case OpenACCGangKind::Num: | 
|  | case OpenACCGangKind::Static: | 
|  | return DiagIntArgInvalid(S, E, GK, OpenACCClauseKind::Gang, DK, AssocKind); | 
|  | case OpenACCGangKind::Dim: | 
|  | return CheckGangDimExpr(S, E); | 
|  | } | 
|  | llvm_unreachable("Unknown gang kind in gang serial check"); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitVectorClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | if (DiagGangWorkerVectorSeqConflict(Clause)) | 
|  | return nullptr; | 
|  |  | 
|  | Expr *IntExpr = | 
|  | Clause.getNumIntExprs() != 0 ? Clause.getIntExprs()[0] : nullptr; | 
|  | if (IntExpr) { | 
|  | switch (Clause.getDirectiveKind()) { | 
|  | default: | 
|  | llvm_unreachable("Invalid directive kind for this clause"); | 
|  | case OpenACCDirectiveKind::Loop: | 
|  | switch (SemaRef.getActiveComputeConstructInfo().Kind) { | 
|  | case OpenACCDirectiveKind::Invalid: | 
|  | case OpenACCDirectiveKind::Parallel: | 
|  | case OpenACCDirectiveKind::ParallelLoop: | 
|  | // No restriction on when 'parallel' can contain an argument. | 
|  | break; | 
|  | case OpenACCDirectiveKind::Serial: | 
|  | case OpenACCDirectiveKind::SerialLoop: | 
|  | // GCC disallows this, and there is no real good reason for us to permit | 
|  | // it, so disallow until we come up with a use case that makes sense. | 
|  | DiagIntArgInvalid(SemaRef, IntExpr, "length", OpenACCClauseKind::Vector, | 
|  | Clause.getDirectiveKind(), | 
|  | SemaRef.getActiveComputeConstructInfo().Kind); | 
|  | IntExpr = nullptr; | 
|  | break; | 
|  | case OpenACCDirectiveKind::Kernels: | 
|  | case OpenACCDirectiveKind::KernelsLoop: { | 
|  | const auto *Itr = | 
|  | llvm::find_if(SemaRef.getActiveComputeConstructInfo().Clauses, | 
|  | llvm::IsaPred<OpenACCVectorLengthClause>); | 
|  | if (Itr != SemaRef.getActiveComputeConstructInfo().Clauses.end()) { | 
|  | SemaRef.Diag(IntExpr->getBeginLoc(), diag::err_acc_num_arg_conflict) | 
|  | << "length" << OpenACCClauseKind::Vector | 
|  | << Clause.getDirectiveKind() | 
|  | << HasAssocKind(Clause.getDirectiveKind(), | 
|  | SemaRef.getActiveComputeConstructInfo().Kind) | 
|  | << SemaRef.getActiveComputeConstructInfo().Kind | 
|  | << OpenACCClauseKind::VectorLength; | 
|  | SemaRef.Diag((*Itr)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*Itr)->getClauseKind(); | 
|  |  | 
|  | IntExpr = nullptr; | 
|  | } | 
|  | break; | 
|  | } | 
|  | default: | 
|  | llvm_unreachable("Non compute construct in active compute construct"); | 
|  | } | 
|  | break; | 
|  | case OpenACCDirectiveKind::KernelsLoop: { | 
|  | const auto *Itr = llvm::find_if(ExistingClauses, | 
|  | llvm::IsaPred<OpenACCVectorLengthClause>); | 
|  | if (Itr != ExistingClauses.end()) { | 
|  | SemaRef.Diag(IntExpr->getBeginLoc(), diag::err_acc_num_arg_conflict) | 
|  | << "length" << OpenACCClauseKind::Vector | 
|  | << Clause.getDirectiveKind() | 
|  | << HasAssocKind(Clause.getDirectiveKind(), | 
|  | SemaRef.getActiveComputeConstructInfo().Kind) | 
|  | << SemaRef.getActiveComputeConstructInfo().Kind | 
|  | << OpenACCClauseKind::VectorLength; | 
|  | SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here) | 
|  | << (*Itr)->getClauseKind(); | 
|  |  | 
|  | IntExpr = nullptr; | 
|  | } | 
|  | break; | 
|  | } | 
|  | case OpenACCDirectiveKind::SerialLoop: | 
|  | case OpenACCDirectiveKind::Routine: | 
|  | DiagIntArgInvalid(SemaRef, IntExpr, "length", OpenACCClauseKind::Vector, | 
|  | Clause.getDirectiveKind(), | 
|  | SemaRef.getActiveComputeConstructInfo().Kind); | 
|  | IntExpr = nullptr; | 
|  | break; | 
|  | case OpenACCDirectiveKind::ParallelLoop: | 
|  | break; | 
|  | case OpenACCDirectiveKind::Invalid: | 
|  | // This can happen when the directive was not recognized, but we continued | 
|  | // anyway.  Since there is a lot of stuff that can happen (including | 
|  | // 'allow anything' in the parallel loop case), just skip all checking and | 
|  | // continue. | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Loop) { | 
|  | // OpenACC 3.3 2.9.4: The region of a loop with a 'vector' clause may not | 
|  | // contain a loop with a gang, worker, or vector clause unless within a | 
|  | // nested compute region. | 
|  | if (SemaRef.LoopVectorClauseLoc.isValid()) { | 
|  | // This handles the 'inner loop' diagnostic, but we cannot set that we're | 
|  | // on one of these until we get to the end of the construct. | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_in_clause_region) | 
|  | << OpenACCClauseKind::Vector << OpenACCClauseKind::Vector | 
|  | << /*skip kernels construct info*/ 0; | 
|  | SemaRef.Diag(SemaRef.LoopVectorClauseLoc, | 
|  | diag::note_acc_previous_clause_here) | 
|  | << "vector"; | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | return OpenACCVectorClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), IntExpr, | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitWorkerClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | if (DiagGangWorkerVectorSeqConflict(Clause)) | 
|  | return nullptr; | 
|  |  | 
|  | Expr *IntExpr = | 
|  | Clause.getNumIntExprs() != 0 ? Clause.getIntExprs()[0] : nullptr; | 
|  |  | 
|  | if (IntExpr) { | 
|  | switch (Clause.getDirectiveKind()) { | 
|  | default: | 
|  | llvm_unreachable("Invalid directive kind for this clause"); | 
|  | case OpenACCDirectiveKind::Invalid: | 
|  | // This can happen in cases where the directive was not recognized but we | 
|  | // continued anyway.  Kernels allows kind of any integer argument, so we | 
|  | // can assume it is that (rather than marking the argument invalid like | 
|  | // with parallel/serial/routine), and just continue as if nothing | 
|  | // happened.  We'll skip the 'kernels' checking vs num-workers, since this | 
|  | // MIGHT be something else. | 
|  | break; | 
|  | case OpenACCDirectiveKind::Loop: | 
|  | switch (SemaRef.getActiveComputeConstructInfo().Kind) { | 
|  | case OpenACCDirectiveKind::Invalid: | 
|  | case OpenACCDirectiveKind::ParallelLoop: | 
|  | case OpenACCDirectiveKind::SerialLoop: | 
|  | case OpenACCDirectiveKind::Parallel: | 
|  | case OpenACCDirectiveKind::Serial: | 
|  | DiagIntArgInvalid(SemaRef, IntExpr, OpenACCGangKind::Num, | 
|  | OpenACCClauseKind::Worker, Clause.getDirectiveKind(), | 
|  | SemaRef.getActiveComputeConstructInfo().Kind); | 
|  | IntExpr = nullptr; | 
|  | break; | 
|  | case OpenACCDirectiveKind::KernelsLoop: | 
|  | case OpenACCDirectiveKind::Kernels: { | 
|  | const auto *Itr = | 
|  | llvm::find_if(SemaRef.getActiveComputeConstructInfo().Clauses, | 
|  | llvm::IsaPred<OpenACCNumWorkersClause>); | 
|  | if (Itr != SemaRef.getActiveComputeConstructInfo().Clauses.end()) { | 
|  | SemaRef.Diag(IntExpr->getBeginLoc(), diag::err_acc_num_arg_conflict) | 
|  | << "num" << OpenACCClauseKind::Worker << Clause.getDirectiveKind() | 
|  | << HasAssocKind(Clause.getDirectiveKind(), | 
|  | SemaRef.getActiveComputeConstructInfo().Kind) | 
|  | << SemaRef.getActiveComputeConstructInfo().Kind | 
|  | << OpenACCClauseKind::NumWorkers; | 
|  | SemaRef.Diag((*Itr)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*Itr)->getClauseKind(); | 
|  |  | 
|  | IntExpr = nullptr; | 
|  | } | 
|  | break; | 
|  | } | 
|  | default: | 
|  | llvm_unreachable("Non compute construct in active compute construct"); | 
|  | } | 
|  | break; | 
|  | case OpenACCDirectiveKind::ParallelLoop: | 
|  | case OpenACCDirectiveKind::SerialLoop: | 
|  | case OpenACCDirectiveKind::Routine: | 
|  | DiagIntArgInvalid(SemaRef, IntExpr, OpenACCGangKind::Num, | 
|  | OpenACCClauseKind::Worker, Clause.getDirectiveKind(), | 
|  | SemaRef.getActiveComputeConstructInfo().Kind); | 
|  | IntExpr = nullptr; | 
|  | break; | 
|  | case OpenACCDirectiveKind::KernelsLoop: { | 
|  | const auto *Itr = llvm::find_if(ExistingClauses, | 
|  | llvm::IsaPred<OpenACCNumWorkersClause>); | 
|  | if (Itr != ExistingClauses.end()) { | 
|  | SemaRef.Diag(IntExpr->getBeginLoc(), diag::err_acc_num_arg_conflict) | 
|  | << "num" << OpenACCClauseKind::Worker << Clause.getDirectiveKind() | 
|  | << HasAssocKind(Clause.getDirectiveKind(), | 
|  | SemaRef.getActiveComputeConstructInfo().Kind) | 
|  | << SemaRef.getActiveComputeConstructInfo().Kind | 
|  | << OpenACCClauseKind::NumWorkers; | 
|  | SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here) | 
|  | << (*Itr)->getClauseKind(); | 
|  |  | 
|  | IntExpr = nullptr; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Loop) { | 
|  | // OpenACC 3.3 2.9.3: The region of a loop with a 'worker' clause may not | 
|  | // contain a loop with a gang or worker clause unless within a nested | 
|  | // compute region. | 
|  | if (SemaRef.LoopWorkerClauseLoc.isValid()) { | 
|  | // This handles the 'inner loop' diagnostic, but we cannot set that we're | 
|  | // on one of these until we get to the end of the construct. | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_in_clause_region) | 
|  | << OpenACCClauseKind::Worker << OpenACCClauseKind::Worker | 
|  | << /*skip kernels construct info*/ 0; | 
|  | SemaRef.Diag(SemaRef.LoopWorkerClauseLoc, | 
|  | diag::note_acc_previous_clause_here) | 
|  | << "worker"; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // OpenACC 3.3 2.9.4: The region of a loop with a 'vector' clause may not | 
|  | // contain a loop with a gang, worker, or vector clause unless within a | 
|  | // nested compute region. | 
|  | if (SemaRef.LoopVectorClauseLoc.isValid()) { | 
|  | // This handles the 'inner loop' diagnostic, but we cannot set that we're | 
|  | // on one of these until we get to the end of the construct. | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_in_clause_region) | 
|  | << OpenACCClauseKind::Worker << OpenACCClauseKind::Vector | 
|  | << /*skip kernels construct info*/ 0; | 
|  | SemaRef.Diag(SemaRef.LoopVectorClauseLoc, | 
|  | diag::note_acc_previous_clause_here) | 
|  | << "vector"; | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | return OpenACCWorkerClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), IntExpr, | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitGangClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | if (DiagGangWorkerVectorSeqConflict(Clause)) | 
|  | return nullptr; | 
|  |  | 
|  | // OpenACC 3.3 Section 2.9.11: A reduction clause may not appear on a loop | 
|  | // directive that has a gang clause and is within a compute construct that has | 
|  | // a num_gangs clause with more than one explicit argument. | 
|  | if ((Clause.getDirectiveKind() == OpenACCDirectiveKind::Loop && | 
|  | SemaRef.getActiveComputeConstructInfo().Kind != | 
|  | OpenACCDirectiveKind::Invalid) || | 
|  | isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) { | 
|  | // num_gangs clause on the active compute construct. | 
|  | auto ActiveComputeConstructContainer = | 
|  | isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) | 
|  | ? ExistingClauses | 
|  | : SemaRef.getActiveComputeConstructInfo().Clauses; | 
|  | auto *NumGangsClauseItr = llvm::find_if( | 
|  | ActiveComputeConstructContainer, llvm::IsaPred<OpenACCNumGangsClause>); | 
|  |  | 
|  | if (NumGangsClauseItr != ActiveComputeConstructContainer.end() && | 
|  | cast<OpenACCNumGangsClause>(*NumGangsClauseItr)->getIntExprs().size() > | 
|  | 1) { | 
|  | auto *ReductionClauseItr = | 
|  | llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCReductionClause>); | 
|  |  | 
|  | if (ReductionClauseItr != ExistingClauses.end()) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), | 
|  | diag::err_acc_gang_reduction_numgangs_conflict) | 
|  | << OpenACCClauseKind::Gang << OpenACCClauseKind::Reduction | 
|  | << Clause.getDirectiveKind() | 
|  | << isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()); | 
|  | SemaRef.Diag((*ReductionClauseItr)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*ReductionClauseItr)->getClauseKind(); | 
|  | SemaRef.Diag((*NumGangsClauseItr)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*NumGangsClauseItr)->getClauseKind(); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | llvm::SmallVector<OpenACCGangKind> GangKinds; | 
|  | llvm::SmallVector<Expr *> IntExprs; | 
|  |  | 
|  | // Store the existing locations, so we can do duplicate checking.  Index is | 
|  | // the int-value of the OpenACCGangKind enum. | 
|  | SourceLocation ExistingElemLoc[3]; | 
|  |  | 
|  | for (unsigned I = 0; I < Clause.getIntExprs().size(); ++I) { | 
|  | OpenACCGangKind GK = Clause.getGangKinds()[I]; | 
|  | ExprResult ER = | 
|  | SemaRef.CheckGangExpr(ExistingClauses, Clause.getDirectiveKind(), GK, | 
|  | Clause.getIntExprs()[I]); | 
|  |  | 
|  | if (!ER.isUsable()) | 
|  | continue; | 
|  |  | 
|  | // OpenACC 3.3 2.9: 'gang-arg-list' may have at most one num, one dim, and | 
|  | // one static argument. | 
|  | if (ExistingElemLoc[static_cast<unsigned>(GK)].isValid()) { | 
|  | SemaRef.Diag(ER.get()->getBeginLoc(), diag::err_acc_gang_multiple_elt) | 
|  | << static_cast<unsigned>(GK); | 
|  | SemaRef.Diag(ExistingElemLoc[static_cast<unsigned>(GK)], | 
|  | diag::note_acc_previous_expr_here); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | ExistingElemLoc[static_cast<unsigned>(GK)] = ER.get()->getBeginLoc(); | 
|  | GangKinds.push_back(GK); | 
|  | IntExprs.push_back(ER.get()); | 
|  | } | 
|  |  | 
|  | if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Loop) { | 
|  | // OpenACC 3.3 2.9.2: When the parent compute construct is a kernels | 
|  | // construct, the gang clause behaves as follows. ... The region of a loop | 
|  | // with a gang clause may not contain another loop with a gang clause unless | 
|  | // within a nested compute region. | 
|  | if (SemaRef.LoopGangClauseOnKernel.Loc.isValid()) { | 
|  | // This handles the 'inner loop' diagnostic, but we cannot set that we're | 
|  | // on one of these until we get to the end of the construct. | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_in_clause_region) | 
|  | << OpenACCClauseKind::Gang << OpenACCClauseKind::Gang | 
|  | << /*kernels construct info*/ 1 | 
|  | << SemaRef.LoopGangClauseOnKernel.DirKind; | 
|  | SemaRef.Diag(SemaRef.LoopGangClauseOnKernel.Loc, | 
|  | diag::note_acc_previous_clause_here) | 
|  | << "gang"; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // OpenACC 3.3 2.9.3: The region of a loop with a 'worker' clause may not | 
|  | // contain a loop with a gang or worker clause unless within a nested | 
|  | // compute region. | 
|  | if (SemaRef.LoopWorkerClauseLoc.isValid()) { | 
|  | // This handles the 'inner loop' diagnostic, but we cannot set that we're | 
|  | // on one of these until we get to the end of the construct. | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_in_clause_region) | 
|  | << OpenACCClauseKind::Gang << OpenACCClauseKind::Worker | 
|  | << /*!kernels construct info*/ 0; | 
|  | SemaRef.Diag(SemaRef.LoopWorkerClauseLoc, | 
|  | diag::note_acc_previous_clause_here) | 
|  | << "worker"; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // OpenACC 3.3 2.9.4: The region of a loop with a 'vector' clause may not | 
|  | // contain a loop with a gang, worker, or vector clause unless within a | 
|  | // nested compute region. | 
|  | if (SemaRef.LoopVectorClauseLoc.isValid()) { | 
|  | // This handles the 'inner loop' diagnostic, but we cannot set that we're | 
|  | // on one of these until we get to the end of the construct. | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_in_clause_region) | 
|  | << OpenACCClauseKind::Gang << OpenACCClauseKind::Vector | 
|  | << /*!kernels construct info*/ 0; | 
|  | SemaRef.Diag(SemaRef.LoopVectorClauseLoc, | 
|  | diag::note_acc_previous_clause_here) | 
|  | << "vector"; | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | return SemaRef.CheckGangClause(Clause.getDirectiveKind(), ExistingClauses, | 
|  | Clause.getBeginLoc(), Clause.getLParenLoc(), | 
|  | GangKinds, IntExprs, Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitFinalizeClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // There isn't anything to do here, this is only valid on one construct, and | 
|  | // has no associated rules. | 
|  | return OpenACCFinalizeClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitIfPresentClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // There isn't anything to do here, this is only valid on one construct, and | 
|  | // has no associated rules. | 
|  | return OpenACCIfPresentClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitSeqClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // OpenACC 3.3 2.9: | 
|  | //  A 'gang', 'worker', or 'vector' clause may not appear if a 'seq' clause | 
|  | //  appears. | 
|  | if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Loop || | 
|  | isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) { | 
|  | const auto *Itr = llvm::find_if( | 
|  | ExistingClauses, llvm::IsaPred<OpenACCGangClause, OpenACCVectorClause, | 
|  | OpenACCWorkerClause>); | 
|  | if (Itr != ExistingClauses.end()) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine) | 
|  | << Clause.getClauseKind() << (*Itr)->getClauseKind() | 
|  | << Clause.getDirectiveKind(); | 
|  | SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here) | 
|  | << (*Itr)->getClauseKind(); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | return OpenACCSeqClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitReductionClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  | // OpenACC 3.3 Section 2.9.11: A reduction clause may not appear on a loop | 
|  | // directive that has a gang clause and is within a compute construct that has | 
|  | // a num_gangs clause with more than one explicit argument. | 
|  | if ((Clause.getDirectiveKind() == OpenACCDirectiveKind::Loop && | 
|  | SemaRef.getActiveComputeConstructInfo().Kind != | 
|  | OpenACCDirectiveKind::Invalid) || | 
|  | isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) { | 
|  | // num_gangs clause on the active compute construct. | 
|  | auto ActiveComputeConstructContainer = | 
|  | isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) | 
|  | ? ExistingClauses | 
|  | : SemaRef.getActiveComputeConstructInfo().Clauses; | 
|  | auto *NumGangsClauseItr = llvm::find_if( | 
|  | ActiveComputeConstructContainer, llvm::IsaPred<OpenACCNumGangsClause>); | 
|  |  | 
|  | if (NumGangsClauseItr != ActiveComputeConstructContainer.end() && | 
|  | cast<OpenACCNumGangsClause>(*NumGangsClauseItr)->getIntExprs().size() > | 
|  | 1) { | 
|  | auto *GangClauseItr = | 
|  | llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCGangClause>); | 
|  |  | 
|  | if (GangClauseItr != ExistingClauses.end()) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), | 
|  | diag::err_acc_gang_reduction_numgangs_conflict) | 
|  | << OpenACCClauseKind::Reduction << OpenACCClauseKind::Gang | 
|  | << Clause.getDirectiveKind() | 
|  | << isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()); | 
|  | SemaRef.Diag((*GangClauseItr)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*GangClauseItr)->getClauseKind(); | 
|  | SemaRef.Diag((*NumGangsClauseItr)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*NumGangsClauseItr)->getClauseKind(); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // OpenACC3.3 Section 2.9.11: If a variable is involved in a reduction that | 
|  | // spans multiple nested loops where two or more of those loops have | 
|  | // associated loop directives, a reduction clause containing that variable | 
|  | // must appear on each of those loop directives. | 
|  | // | 
|  | // This can't really be implemented in the CFE, as this requires a level of | 
|  | // rechability/useage analysis that we're not really wanting to get into. | 
|  | // Additionally, I'm alerted that this restriction is one that the middle-end | 
|  | // can just 'figure out' as an extension and isn't really necessary. | 
|  | // | 
|  | // OpenACC3.3 Section 2.9.11: Every 'var' in a reduction clause appearing on | 
|  | // an orphaned loop construct must be private. | 
|  | // | 
|  | // This again is something we cannot really diagnose, as it requires we see | 
|  | // all the uses/scopes of all variables referenced.  The middle end/MLIR might | 
|  | // be able to diagnose this. | 
|  |  | 
|  | // OpenACC 3.3 Section 2.5.4: | 
|  | // A reduction clause may not appear on a parallel construct with a | 
|  | // num_gangs clause that has more than one argument. | 
|  | if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel || | 
|  | Clause.getDirectiveKind() == OpenACCDirectiveKind::ParallelLoop) { | 
|  | auto NumGangsClauses = llvm::make_filter_range( | 
|  | ExistingClauses, llvm::IsaPred<OpenACCNumGangsClause>); | 
|  |  | 
|  | for (auto *NGC : NumGangsClauses) { | 
|  | unsigned NumExprs = | 
|  | cast<OpenACCNumGangsClause>(NGC)->getIntExprs().size(); | 
|  |  | 
|  | if (NumExprs > 1) { | 
|  | SemaRef.Diag(Clause.getBeginLoc(), | 
|  | diag::err_acc_reduction_num_gangs_conflict) | 
|  | << /*>1 arg in first loc=*/0 << Clause.getClauseKind() | 
|  | << Clause.getDirectiveKind() << OpenACCClauseKind::NumGangs; | 
|  | SemaRef.Diag(NGC->getBeginLoc(), diag::note_acc_previous_clause_here) | 
|  | << NGC->getClauseKind(); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | SmallVector<Expr *> ValidVars; | 
|  |  | 
|  | for (Expr *Var : Clause.getVarList()) { | 
|  | ExprResult Res = SemaRef.CheckReductionVar(Clause.getDirectiveKind(), | 
|  | Clause.getReductionOp(), Var); | 
|  |  | 
|  | if (Res.isUsable()) | 
|  | ValidVars.push_back(Res.get()); | 
|  | } | 
|  |  | 
|  | return SemaRef.CheckReductionClause( | 
|  | ExistingClauses, Clause.getDirectiveKind(), Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), Clause.getReductionOp(), ValidVars, | 
|  | Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitCollapseClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | if (DisallowSinceLastDeviceType<OpenACCCollapseClause>(Clause)) | 
|  | return nullptr; | 
|  |  | 
|  | ExprResult LoopCount = SemaRef.CheckCollapseLoopCount(Clause.getLoopCount()); | 
|  |  | 
|  | if (!LoopCount.isUsable()) | 
|  | return nullptr; | 
|  |  | 
|  | return OpenACCCollapseClause::Create(Ctx, Clause.getBeginLoc(), | 
|  | Clause.getLParenLoc(), Clause.isForce(), | 
|  | LoopCount.get(), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACCClauseVisitor::VisitBindClause( | 
|  | SemaOpenACC::OpenACCParsedClause &Clause) { | 
|  |  | 
|  | if (std::holds_alternative<StringLiteral *>(Clause.getBindDetails())) | 
|  | return OpenACCBindClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), | 
|  | std::get<StringLiteral *>(Clause.getBindDetails()), Clause.getEndLoc()); | 
|  | return OpenACCBindClause::Create( | 
|  | Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), | 
|  | std::get<IdentifierInfo *>(Clause.getBindDetails()), Clause.getEndLoc()); | 
|  | } | 
|  |  | 
|  | // Return true if the two vars refer to the same variable, for the purposes of | 
|  | // equality checking. | 
|  | bool areVarsEqual(Expr *VarExpr1, Expr *VarExpr2) { | 
|  | if (VarExpr1->isInstantiationDependent() || | 
|  | VarExpr2->isInstantiationDependent()) | 
|  | return false; | 
|  |  | 
|  | VarExpr1 = VarExpr1->IgnoreParenCasts(); | 
|  | VarExpr2 = VarExpr2->IgnoreParenCasts(); | 
|  |  | 
|  | // Legal expressions can be: Scalar variable reference, sub-array, array | 
|  | // element, or composite variable member. | 
|  |  | 
|  | // Sub-array. | 
|  | if (isa<ArraySectionExpr>(VarExpr1)) { | 
|  | auto *Expr2AS = dyn_cast<ArraySectionExpr>(VarExpr2); | 
|  | if (!Expr2AS) | 
|  | return false; | 
|  |  | 
|  | auto *Expr1AS = cast<ArraySectionExpr>(VarExpr1); | 
|  |  | 
|  | if (!areVarsEqual(Expr1AS->getBase(), Expr2AS->getBase())) | 
|  | return false; | 
|  | // We could possibly check to see if the ranges aren't overlapping, but it | 
|  | // isn't clear that the rules allow this. | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Array-element. | 
|  | if (isa<ArraySubscriptExpr>(VarExpr1)) { | 
|  | auto *Expr2AS = dyn_cast<ArraySubscriptExpr>(VarExpr2); | 
|  | if (!Expr2AS) | 
|  | return false; | 
|  |  | 
|  | auto *Expr1AS = cast<ArraySubscriptExpr>(VarExpr1); | 
|  |  | 
|  | if (!areVarsEqual(Expr1AS->getBase(), Expr2AS->getBase())) | 
|  | return false; | 
|  |  | 
|  | // We could possibly check to see if the elements referenced aren't the | 
|  | // same, but it isn't clear by reading of the standard that this is allowed | 
|  | // (and that the 'var' refered to isn't the array). | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Scalar variable reference, or composite variable. | 
|  | if (isa<DeclRefExpr>(VarExpr1)) { | 
|  | auto *Expr2DRE = dyn_cast<DeclRefExpr>(VarExpr2); | 
|  | if (!Expr2DRE) | 
|  | return false; | 
|  |  | 
|  | auto *Expr1DRE = cast<DeclRefExpr>(VarExpr1); | 
|  |  | 
|  | return Expr1DRE->getDecl()->getMostRecentDecl() == | 
|  | Expr2DRE->getDecl()->getMostRecentDecl(); | 
|  | } | 
|  |  | 
|  | llvm_unreachable("Unknown variable type encountered"); | 
|  | } | 
|  | } // namespace | 
|  |  | 
|  | OpenACCClause * | 
|  | SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses, | 
|  | OpenACCParsedClause &Clause) { | 
|  | if (Clause.getClauseKind() == OpenACCClauseKind::Invalid) | 
|  | return nullptr; | 
|  |  | 
|  | if (DiagnoseAllowedClauses(Clause.getDirectiveKind(), Clause.getClauseKind(), | 
|  | Clause.getBeginLoc())) | 
|  | return nullptr; | 
|  | //// Diagnose that we don't support this clause on this directive. | 
|  | // if (!doesClauseApplyToDirective(Clause.getDirectiveKind(), | 
|  | //                                 Clause.getClauseKind())) { | 
|  | //   Diag(Clause.getBeginLoc(), diag::err_acc_clause_appertainment) | 
|  | //       << Clause.getDirectiveKind() << Clause.getClauseKind(); | 
|  | //   return nullptr; | 
|  | // } | 
|  |  | 
|  | if (const auto *DevTypeClause = llvm::find_if( | 
|  | ExistingClauses, llvm::IsaPred<OpenACCDeviceTypeClause>); | 
|  | DevTypeClause != ExistingClauses.end()) { | 
|  | if (checkValidAfterDeviceType( | 
|  | *this, *cast<OpenACCDeviceTypeClause>(*DevTypeClause), Clause)) | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | SemaOpenACCClauseVisitor Visitor{*this, ExistingClauses}; | 
|  | OpenACCClause *Result = Visitor.Visit(Clause); | 
|  | assert((!Result || Result->getClauseKind() == Clause.getClauseKind()) && | 
|  | "Created wrong clause?"); | 
|  |  | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | /// OpenACC 3.3 section 2.5.15: | 
|  | /// At a mininmum, the supported data types include ... the numerical data types | 
|  | /// in C, C++, and Fortran. | 
|  | /// | 
|  | /// If the reduction var is a composite variable, each | 
|  | /// member of the composite variable must be a supported datatype for the | 
|  | /// reduction operation. | 
|  | ExprResult SemaOpenACC::CheckReductionVar(OpenACCDirectiveKind DirectiveKind, | 
|  | OpenACCReductionOperator ReductionOp, | 
|  | Expr *VarExpr) { | 
|  | VarExpr = VarExpr->IgnoreParenCasts(); | 
|  |  | 
|  | auto TypeIsValid = [](QualType Ty) { | 
|  | return Ty->isDependentType() || Ty->isScalarType(); | 
|  | }; | 
|  |  | 
|  | if (isa<ArraySectionExpr>(VarExpr)) { | 
|  | Expr *ASExpr = VarExpr; | 
|  | QualType BaseTy = ArraySectionExpr::getBaseOriginalType(ASExpr); | 
|  | QualType EltTy = getASTContext().getBaseElementType(BaseTy); | 
|  |  | 
|  | if (!TypeIsValid(EltTy)) { | 
|  | Diag(VarExpr->getExprLoc(), diag::err_acc_reduction_type) | 
|  | << EltTy << /*Sub array base type*/ 1; | 
|  | return ExprError(); | 
|  | } | 
|  | } else if (auto *RD = VarExpr->getType()->getAsRecordDecl()) { | 
|  | if (!RD->isStruct() && !RD->isClass()) { | 
|  | Diag(VarExpr->getExprLoc(), diag::err_acc_reduction_composite_type) | 
|  | << /*not class or struct*/ 0 << VarExpr->getType(); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | if (!RD->isCompleteDefinition()) { | 
|  | Diag(VarExpr->getExprLoc(), diag::err_acc_reduction_composite_type) | 
|  | << /*incomplete*/ 1 << VarExpr->getType(); | 
|  | return ExprError(); | 
|  | } | 
|  | if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD); | 
|  | CXXRD && !CXXRD->isAggregate()) { | 
|  | Diag(VarExpr->getExprLoc(), diag::err_acc_reduction_composite_type) | 
|  | << /*aggregate*/ 2 << VarExpr->getType(); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | for (FieldDecl *FD : RD->fields()) { | 
|  | if (!TypeIsValid(FD->getType())) { | 
|  | Diag(VarExpr->getExprLoc(), | 
|  | diag::err_acc_reduction_composite_member_type); | 
|  | Diag(FD->getLocation(), diag::note_acc_reduction_composite_member_loc); | 
|  | return ExprError(); | 
|  | } | 
|  | } | 
|  | } else if (!TypeIsValid(VarExpr->getType())) { | 
|  | Diag(VarExpr->getExprLoc(), diag::err_acc_reduction_type) | 
|  | << VarExpr->getType() << /*Sub array base type*/ 0; | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | // OpenACC3.3: 2.9.11: Reduction clauses on nested constructs for the same | 
|  | // reduction 'var' must have the same reduction operator. | 
|  | if (!VarExpr->isInstantiationDependent()) { | 
|  |  | 
|  | for (const OpenACCReductionClause *RClause : ActiveReductionClauses) { | 
|  | if (RClause->getReductionOp() == ReductionOp) | 
|  | break; | 
|  |  | 
|  | for (Expr *OldVarExpr : RClause->getVarList()) { | 
|  | if (OldVarExpr->isInstantiationDependent()) | 
|  | continue; | 
|  |  | 
|  | if (areVarsEqual(VarExpr, OldVarExpr)) { | 
|  | Diag(VarExpr->getExprLoc(), diag::err_reduction_op_mismatch) | 
|  | << ReductionOp << RClause->getReductionOp(); | 
|  | Diag(OldVarExpr->getExprLoc(), diag::note_acc_previous_clause_here) | 
|  | << RClause->getClauseKind(); | 
|  | return ExprError(); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return VarExpr; | 
|  | } | 
|  |  | 
|  | ExprResult SemaOpenACC::CheckTileSizeExpr(Expr *SizeExpr) { | 
|  | if (!SizeExpr) | 
|  | return ExprError(); | 
|  |  | 
|  | assert((SizeExpr->isInstantiationDependent() || | 
|  | SizeExpr->getType()->isIntegerType()) && | 
|  | "size argument non integer?"); | 
|  |  | 
|  | // If dependent, or an asterisk, the expression is fine. | 
|  | if (SizeExpr->isInstantiationDependent() || | 
|  | isa<OpenACCAsteriskSizeExpr>(SizeExpr)) | 
|  | return ExprResult{SizeExpr}; | 
|  |  | 
|  | std::optional<llvm::APSInt> ICE = | 
|  | SizeExpr->getIntegerConstantExpr(getASTContext()); | 
|  |  | 
|  | // OpenACC 3.3 2.9.8 | 
|  | // where each tile size is a constant positive integer expression or asterisk. | 
|  | if (!ICE || *ICE <= 0) { | 
|  | Diag(SizeExpr->getBeginLoc(), diag::err_acc_size_expr_value) | 
|  | << ICE.has_value() << ICE.value_or(llvm::APSInt{}).getExtValue(); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | return ExprResult{ | 
|  | ConstantExpr::Create(getASTContext(), SizeExpr, APValue{*ICE})}; | 
|  | } | 
|  |  | 
|  | ExprResult SemaOpenACC::CheckCollapseLoopCount(Expr *LoopCount) { | 
|  | if (!LoopCount) | 
|  | return ExprError(); | 
|  |  | 
|  | assert((LoopCount->isInstantiationDependent() || | 
|  | LoopCount->getType()->isIntegerType()) && | 
|  | "Loop argument non integer?"); | 
|  |  | 
|  | // If this is dependent, there really isn't anything we can check. | 
|  | if (LoopCount->isInstantiationDependent()) | 
|  | return ExprResult{LoopCount}; | 
|  |  | 
|  | std::optional<llvm::APSInt> ICE = | 
|  | LoopCount->getIntegerConstantExpr(getASTContext()); | 
|  |  | 
|  | // OpenACC 3.3: 2.9.1 | 
|  | // The argument to the collapse clause must be a constant positive integer | 
|  | // expression. | 
|  | if (!ICE || *ICE <= 0) { | 
|  | Diag(LoopCount->getBeginLoc(), diag::err_acc_collapse_loop_count) | 
|  | << ICE.has_value() << ICE.value_or(llvm::APSInt{}).getExtValue(); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | return ExprResult{ | 
|  | ConstantExpr::Create(getASTContext(), LoopCount, APValue{*ICE})}; | 
|  | } | 
|  |  | 
|  | ExprResult | 
|  | SemaOpenACC::CheckGangExpr(ArrayRef<const OpenACCClause *> ExistingClauses, | 
|  | OpenACCDirectiveKind DK, OpenACCGangKind GK, | 
|  | Expr *E) { | 
|  | // There are two cases for the enforcement here: the 'current' directive is a | 
|  | // 'loop', where we need to check the active compute construct kind, or the | 
|  | // current directive is a 'combined' construct, where we have to check the | 
|  | // current one. | 
|  | switch (DK) { | 
|  | case OpenACCDirectiveKind::ParallelLoop: | 
|  | return CheckGangParallelExpr(*this, DK, ActiveComputeConstructInfo.Kind, GK, | 
|  | E); | 
|  | case OpenACCDirectiveKind::SerialLoop: | 
|  | return CheckGangSerialExpr(*this, DK, ActiveComputeConstructInfo.Kind, GK, | 
|  | E); | 
|  | case OpenACCDirectiveKind::KernelsLoop: | 
|  | return CheckGangKernelsExpr(*this, ExistingClauses, DK, | 
|  | ActiveComputeConstructInfo.Kind, GK, E); | 
|  | case OpenACCDirectiveKind::Routine: | 
|  | return CheckGangRoutineExpr(*this, DK, ActiveComputeConstructInfo.Kind, GK, | 
|  | E); | 
|  | case OpenACCDirectiveKind::Loop: | 
|  | switch (ActiveComputeConstructInfo.Kind) { | 
|  | case OpenACCDirectiveKind::Invalid: | 
|  | case OpenACCDirectiveKind::Parallel: | 
|  | case OpenACCDirectiveKind::ParallelLoop: | 
|  | return CheckGangParallelExpr(*this, DK, ActiveComputeConstructInfo.Kind, | 
|  | GK, E); | 
|  | case OpenACCDirectiveKind::SerialLoop: | 
|  | case OpenACCDirectiveKind::Serial: | 
|  | return CheckGangSerialExpr(*this, DK, ActiveComputeConstructInfo.Kind, GK, | 
|  | E); | 
|  | case OpenACCDirectiveKind::KernelsLoop: | 
|  | case OpenACCDirectiveKind::Kernels: | 
|  | return CheckGangKernelsExpr(*this, ExistingClauses, DK, | 
|  | ActiveComputeConstructInfo.Kind, GK, E); | 
|  | default: | 
|  | llvm_unreachable("Non compute construct in active compute construct?"); | 
|  | } | 
|  | case OpenACCDirectiveKind::Invalid: | 
|  | // This can happen in cases where the the directive was not recognized but | 
|  | // we continued anyway. Since the validity checking is all-over the place | 
|  | // (it can be a star/integer, or a constant expr depending on the tag), we | 
|  | // just give up and return an ExprError here. | 
|  | return ExprError(); | 
|  | default: | 
|  | llvm_unreachable("Invalid directive kind for a Gang clause"); | 
|  | } | 
|  | llvm_unreachable("Compute construct directive not handled?"); | 
|  | } | 
|  |  | 
|  | OpenACCClause * | 
|  | SemaOpenACC::CheckGangClause(OpenACCDirectiveKind DirKind, | 
|  | ArrayRef<const OpenACCClause *> ExistingClauses, | 
|  | SourceLocation BeginLoc, SourceLocation LParenLoc, | 
|  | ArrayRef<OpenACCGangKind> GangKinds, | 
|  | ArrayRef<Expr *> IntExprs, SourceLocation EndLoc) { | 
|  | // Reduction isn't possible on 'routine' so we don't bother checking it here. | 
|  | if (DirKind != OpenACCDirectiveKind::Routine) { | 
|  | // OpenACC 3.3 2.9.11: A reduction clause may not appear on a loop directive | 
|  | // that has a gang clause with a dim: argument whose value is greater | 
|  | // than 1. | 
|  | const auto *ReductionItr = | 
|  | llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCReductionClause>); | 
|  |  | 
|  | if (ReductionItr != ExistingClauses.end()) { | 
|  | const auto GangZip = llvm::zip_equal(GangKinds, IntExprs); | 
|  | const auto GangItr = llvm::find_if(GangZip, [](const auto &Tuple) { | 
|  | return std::get<0>(Tuple) == OpenACCGangKind::Dim; | 
|  | }); | 
|  |  | 
|  | if (GangItr != GangZip.end()) { | 
|  | const Expr *DimExpr = std::get<1>(*GangItr); | 
|  |  | 
|  | assert((DimExpr->isInstantiationDependent() || | 
|  | isa<ConstantExpr>(DimExpr)) && | 
|  | "Improperly formed gang argument"); | 
|  | if (const auto *DimVal = dyn_cast<ConstantExpr>(DimExpr); | 
|  | DimVal && DimVal->getResultAsAPSInt() > 1) { | 
|  | Diag(DimVal->getBeginLoc(), diag::err_acc_gang_reduction_conflict) | 
|  | << /*gang/reduction=*/0 << DirKind; | 
|  | Diag((*ReductionItr)->getBeginLoc(), | 
|  | diag::note_acc_previous_clause_here) | 
|  | << (*ReductionItr)->getClauseKind(); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return OpenACCGangClause::Create(getASTContext(), BeginLoc, LParenLoc, | 
|  | GangKinds, IntExprs, EndLoc); | 
|  | } | 
|  |  | 
|  | OpenACCClause *SemaOpenACC::CheckReductionClause( | 
|  | ArrayRef<const OpenACCClause *> ExistingClauses, | 
|  | OpenACCDirectiveKind DirectiveKind, SourceLocation BeginLoc, | 
|  | SourceLocation LParenLoc, OpenACCReductionOperator ReductionOp, | 
|  | ArrayRef<Expr *> Vars, SourceLocation EndLoc) { | 
|  | if (DirectiveKind == OpenACCDirectiveKind::Loop || | 
|  | isOpenACCCombinedDirectiveKind(DirectiveKind)) { | 
|  | // OpenACC 3.3 2.9.11: A reduction clause may not appear on a loop directive | 
|  | // that has a gang clause with a dim: argument whose value is greater | 
|  | // than 1. | 
|  | const auto GangClauses = llvm::make_filter_range( | 
|  | ExistingClauses, llvm::IsaPred<OpenACCGangClause>); | 
|  |  | 
|  | for (auto *GC : GangClauses) { | 
|  | const auto *GangClause = cast<OpenACCGangClause>(GC); | 
|  | for (unsigned I = 0; I < GangClause->getNumExprs(); ++I) { | 
|  | std::pair<OpenACCGangKind, const Expr *> EPair = GangClause->getExpr(I); | 
|  | if (EPair.first != OpenACCGangKind::Dim) | 
|  | continue; | 
|  |  | 
|  | if (const auto *DimVal = dyn_cast<ConstantExpr>(EPair.second); | 
|  | DimVal && DimVal->getResultAsAPSInt() > 1) { | 
|  | Diag(BeginLoc, diag::err_acc_gang_reduction_conflict) | 
|  | << /*reduction/gang=*/1 << DirectiveKind; | 
|  | Diag(GangClause->getBeginLoc(), diag::note_acc_previous_clause_here) | 
|  | << GangClause->getClauseKind(); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | auto *Ret = OpenACCReductionClause::Create( | 
|  | getASTContext(), BeginLoc, LParenLoc, ReductionOp, Vars, EndLoc); | 
|  | return Ret; | 
|  | } | 
|  |  | 
|  | llvm::SmallVector<Expr *> | 
|  | SemaOpenACC::CheckLinkClauseVarList(ArrayRef<Expr *> VarExprs) { | 
|  | const DeclContext *DC = removeLinkageSpecDC(getCurContext()); | 
|  |  | 
|  | // Link has no special restrictions on its var list unless it is not at NS/TU | 
|  | // scope. | 
|  | if (isa<NamespaceDecl, TranslationUnitDecl>(DC)) | 
|  | return llvm::SmallVector<Expr *>(VarExprs); | 
|  |  | 
|  | llvm::SmallVector<Expr *> NewVarList; | 
|  |  | 
|  | for (Expr *VarExpr : VarExprs) { | 
|  | if (isa<DependentScopeDeclRefExpr, CXXDependentScopeMemberExpr>(VarExpr)) { | 
|  | NewVarList.push_back(VarExpr); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Field decls can't be global, nor extern, and declare can't refer to | 
|  | // non-static fields in class-scope, so this always fails the scope check. | 
|  | // BUT for now we add this so it gets diagnosed by the general 'declare' | 
|  | // rules. | 
|  | if (isa<MemberExpr>(VarExpr)) { | 
|  | NewVarList.push_back(VarExpr); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | const auto *DRE = cast<DeclRefExpr>(VarExpr); | 
|  | const VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl()); | 
|  |  | 
|  | if (!Var || !Var->hasExternalStorage()) | 
|  | Diag(VarExpr->getBeginLoc(), diag::err_acc_link_not_extern); | 
|  | else | 
|  | NewVarList.push_back(VarExpr); | 
|  | } | 
|  |  | 
|  | return NewVarList; | 
|  | } | 
|  | bool SemaOpenACC::CheckDeclareClause(SemaOpenACC::OpenACCParsedClause &Clause, | 
|  | OpenACCModifierKind Mods) { | 
|  |  | 
|  | if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Declare) | 
|  | return false; | 
|  |  | 
|  | const DeclContext *DC = removeLinkageSpecDC(getCurContext()); | 
|  |  | 
|  | // Whether this is 'create', 'copyin', 'deviceptr', 'device_resident', or | 
|  | // 'link', which have 2 special rules. | 
|  | bool IsSpecialClause = | 
|  | Clause.getClauseKind() == OpenACCClauseKind::Create || | 
|  | Clause.getClauseKind() == OpenACCClauseKind::CopyIn || | 
|  | Clause.getClauseKind() == OpenACCClauseKind::DevicePtr || | 
|  | Clause.getClauseKind() == OpenACCClauseKind::DeviceResident || | 
|  | Clause.getClauseKind() == OpenACCClauseKind::Link; | 
|  |  | 
|  | // OpenACC 3.3 2.13: | 
|  | // In C or C++ global or namespace scope, only 'create', | 
|  | // 'copyin', 'deviceptr', 'device_resident', or 'link' clauses are | 
|  | // allowed. | 
|  | if (!IsSpecialClause && isa<NamespaceDecl, TranslationUnitDecl>(DC)) { | 
|  | return Diag(Clause.getBeginLoc(), diag::err_acc_declare_clause_at_global) | 
|  | << Clause.getClauseKind(); | 
|  | } | 
|  |  | 
|  | llvm::SmallVector<Expr *> FilteredVarList; | 
|  | const DeclaratorDecl *CurDecl = nullptr; | 
|  | for (Expr *VarExpr : Clause.getVarList()) { | 
|  | if (isa<DependentScopeDeclRefExpr, CXXDependentScopeMemberExpr>(VarExpr)) { | 
|  | // There isn't really anything we can do here, so we add them anyway and | 
|  | // we can check them again when we instantiate this. | 
|  | } else if (const auto *MemExpr = dyn_cast<MemberExpr>(VarExpr)) { | 
|  | FieldDecl *FD = | 
|  | cast<FieldDecl>(MemExpr->getMemberDecl()->getCanonicalDecl()); | 
|  | CurDecl = FD; | 
|  |  | 
|  | if (removeLinkageSpecDC( | 
|  | FD->getLexicalDeclContext()->getPrimaryContext()) != DC) { | 
|  | Diag(MemExpr->getBeginLoc(), diag::err_acc_declare_same_scope) | 
|  | << Clause.getClauseKind(); | 
|  | continue; | 
|  | } | 
|  | } else { | 
|  | const auto *DRE = cast<DeclRefExpr>(VarExpr); | 
|  | if (const auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) { | 
|  | CurDecl = Var->getCanonicalDecl(); | 
|  |  | 
|  | // OpenACC3.3 2.13: | 
|  | // A 'declare' directive must be in the same scope as the declaration of | 
|  | // any var that appears in the clauses of the directive or any scope | 
|  | // within a C/C++ function. | 
|  | // We can't really check 'scope' here, so we check declaration context, | 
|  | // which is a reasonable approximation, but misses scopes inside of | 
|  | // functions. | 
|  | if (removeLinkageSpecDC( | 
|  | Var->getLexicalDeclContext()->getPrimaryContext()) != DC) { | 
|  | Diag(VarExpr->getBeginLoc(), diag::err_acc_declare_same_scope) | 
|  | << Clause.getClauseKind(); | 
|  | continue; | 
|  | } | 
|  | // OpenACC3.3 2.13: | 
|  | // C and C++ extern variables may only appear in 'create', | 
|  | // 'copyin', 'deviceptr', 'device_resident', or 'link' clauses on a | 
|  | // 'declare' directive. | 
|  | if (!IsSpecialClause && Var->hasExternalStorage()) { | 
|  | Diag(VarExpr->getBeginLoc(), diag::err_acc_declare_extern) | 
|  | << Clause.getClauseKind(); | 
|  | continue; | 
|  | } | 
|  | } | 
|  |  | 
|  | // OpenACC3.3 2.13: | 
|  | // A var may appear at most once in all the clauses of declare | 
|  | // directives for a function, subroutine, program, or module. | 
|  |  | 
|  | if (CurDecl) { | 
|  | auto [Itr, Inserted] = DeclareVarReferences.try_emplace(CurDecl); | 
|  | if (!Inserted) { | 
|  | Diag(VarExpr->getBeginLoc(), diag::err_acc_multiple_references) | 
|  | << Clause.getClauseKind(); | 
|  | Diag(Itr->second, diag::note_acc_previous_reference); | 
|  | continue; | 
|  | } else { | 
|  | Itr->second = VarExpr->getBeginLoc(); | 
|  | } | 
|  | } | 
|  | } | 
|  | FilteredVarList.push_back(VarExpr); | 
|  | } | 
|  |  | 
|  | Clause.setVarListDetails(FilteredVarList, Mods); | 
|  | return false; | 
|  | } |