
Flang diverges from the llvm coding style in that it requires braces around the bodies of if/while/etc statements, even when the body is a single statement. This commit adds the readability-braces-around-statements check to flang's clang-tidy config file. Hopefully the premerge bots will pick it up and report violations in Phabricator. We also explicitly disable the check in the directories corresponding to the Lower and Optimizer libraries, which rely heavily on mlir and llvm and therefore follow their coding style. Likewise for the tools directory. We also fix any outstanding violations in the runtime and in lib/Semantics. Differential Revision: https://reviews.llvm.org/D104100
442 lines
17 KiB
C++
442 lines
17 KiB
C++
//===-- lib/Semantics/check-acc-structure.cpp -----------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "check-acc-structure.h"
|
|
#include "flang/Parser/parse-tree.h"
|
|
#include "flang/Semantics/tools.h"
|
|
|
|
#define CHECK_SIMPLE_CLAUSE(X, Y) \
|
|
void AccStructureChecker::Enter(const parser::AccClause::X &) { \
|
|
CheckAllowed(llvm::acc::Clause::Y); \
|
|
}
|
|
|
|
#define CHECK_REQ_SCALAR_INT_CONSTANT_CLAUSE(X, Y) \
|
|
void AccStructureChecker::Enter(const parser::AccClause::X &c) { \
|
|
CheckAllowed(llvm::acc::Clause::Y); \
|
|
RequiresConstantPositiveParameter(llvm::acc::Clause::Y, c.v); \
|
|
}
|
|
|
|
namespace Fortran::semantics {
|
|
|
|
static constexpr inline AccClauseSet
|
|
computeConstructOnlyAllowedAfterDeviceTypeClauses{
|
|
llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait,
|
|
llvm::acc::Clause::ACCC_num_gangs, llvm::acc::Clause::ACCC_num_workers,
|
|
llvm::acc::Clause::ACCC_vector_length};
|
|
|
|
static constexpr inline AccClauseSet loopOnlyAllowedAfterDeviceTypeClauses{
|
|
llvm::acc::Clause::ACCC_auto, llvm::acc::Clause::ACCC_collapse,
|
|
llvm::acc::Clause::ACCC_independent, llvm::acc::Clause::ACCC_gang,
|
|
llvm::acc::Clause::ACCC_seq, llvm::acc::Clause::ACCC_tile,
|
|
llvm::acc::Clause::ACCC_vector, llvm::acc::Clause::ACCC_worker};
|
|
|
|
static constexpr inline AccClauseSet updateOnlyAllowedAfterDeviceTypeClauses{
|
|
llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait};
|
|
|
|
static constexpr inline AccClauseSet routineOnlyAllowedAfterDeviceTypeClauses{
|
|
llvm::acc::Clause::ACCC_bind, llvm::acc::Clause::ACCC_gang,
|
|
llvm::acc::Clause::ACCC_vector, llvm::acc::Clause::ACCC_worker};
|
|
|
|
bool AccStructureChecker::CheckAllowedModifier(llvm::acc::Clause clause) {
|
|
if (GetContext().directive == llvm::acc::ACCD_enter_data ||
|
|
GetContext().directive == llvm::acc::ACCD_exit_data) {
|
|
context_.Say(GetContext().clauseSource,
|
|
"Modifier is not allowed for the %s clause "
|
|
"on the %s directive"_err_en_US,
|
|
parser::ToUpperCaseLetters(getClauseName(clause).str()),
|
|
ContextDirectiveAsFortran());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool AccStructureChecker::IsComputeConstruct(
|
|
llvm::acc::Directive directive) const {
|
|
return directive == llvm::acc::ACCD_parallel ||
|
|
directive == llvm::acc::ACCD_parallel_loop ||
|
|
directive == llvm::acc::ACCD_serial ||
|
|
directive == llvm::acc::ACCD_serial_loop ||
|
|
directive == llvm::acc::ACCD_kernels ||
|
|
directive == llvm::acc::ACCD_kernels_loop;
|
|
}
|
|
|
|
bool AccStructureChecker::IsInsideComputeConstruct() const {
|
|
if (dirContext_.size() <= 1) {
|
|
return false;
|
|
}
|
|
|
|
// Check all nested context skipping the first one.
|
|
for (std::size_t i = dirContext_.size() - 1; i > 0; --i) {
|
|
if (IsComputeConstruct(dirContext_[i - 1].directive)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void AccStructureChecker::CheckNotInComputeConstruct() {
|
|
if (IsInsideComputeConstruct()) {
|
|
context_.Say(GetContext().directiveSource,
|
|
"Directive %s may not be called within a compute region"_err_en_US,
|
|
ContextDirectiveAsFortran());
|
|
}
|
|
}
|
|
|
|
void AccStructureChecker::Enter(const parser::AccClause &x) {
|
|
SetContextClause(x);
|
|
}
|
|
|
|
void AccStructureChecker::Leave(const parser::AccClauseList &) {}
|
|
|
|
void AccStructureChecker::Enter(const parser::OpenACCBlockConstruct &x) {
|
|
const auto &beginBlockDir{std::get<parser::AccBeginBlockDirective>(x.t)};
|
|
const auto &endBlockDir{std::get<parser::AccEndBlockDirective>(x.t)};
|
|
const auto &beginAccBlockDir{
|
|
std::get<parser::AccBlockDirective>(beginBlockDir.t)};
|
|
|
|
CheckMatching(beginAccBlockDir, endBlockDir.v);
|
|
PushContextAndClauseSets(beginAccBlockDir.source, beginAccBlockDir.v);
|
|
}
|
|
|
|
void AccStructureChecker::Leave(const parser::OpenACCBlockConstruct &x) {
|
|
const auto &beginBlockDir{std::get<parser::AccBeginBlockDirective>(x.t)};
|
|
const auto &blockDir{std::get<parser::AccBlockDirective>(beginBlockDir.t)};
|
|
const parser::Block &block{std::get<parser::Block>(x.t)};
|
|
switch (blockDir.v) {
|
|
case llvm::acc::Directive::ACCD_kernels:
|
|
case llvm::acc::Directive::ACCD_parallel:
|
|
case llvm::acc::Directive::ACCD_serial:
|
|
// Restriction - line 1004-1005
|
|
CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
|
|
computeConstructOnlyAllowedAfterDeviceTypeClauses);
|
|
// Restriction - line 1001
|
|
CheckNoBranching(block, GetContext().directive, blockDir.source);
|
|
break;
|
|
case llvm::acc::Directive::ACCD_data:
|
|
// Restriction - line 1249-1250
|
|
CheckRequireAtLeastOneOf();
|
|
break;
|
|
case llvm::acc::Directive::ACCD_host_data:
|
|
// Restriction - line 1746
|
|
CheckRequireAtLeastOneOf();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
dirContext_.pop_back();
|
|
}
|
|
|
|
void AccStructureChecker::Enter(
|
|
const parser::OpenACCStandaloneDeclarativeConstruct &x) {
|
|
const auto &declarativeDir{std::get<parser::AccDeclarativeDirective>(x.t)};
|
|
PushContextAndClauseSets(declarativeDir.source, declarativeDir.v);
|
|
}
|
|
|
|
void AccStructureChecker::Leave(
|
|
const parser::OpenACCStandaloneDeclarativeConstruct &x) {
|
|
// Restriction - line 2409
|
|
CheckAtLeastOneClause();
|
|
|
|
// Restriction - line 2417-2418 - In a Fortran module declaration section,
|
|
// only create, copyin, device_resident, and link clauses are allowed.
|
|
const auto &declarativeDir{std::get<parser::AccDeclarativeDirective>(x.t)};
|
|
const auto &scope{context_.FindScope(declarativeDir.source)};
|
|
const Scope &containingScope{GetProgramUnitContaining(scope)};
|
|
if (containingScope.kind() == Scope::Kind::Module) {
|
|
for (auto cl : GetContext().actualClauses) {
|
|
if (cl != llvm::acc::Clause::ACCC_create &&
|
|
cl != llvm::acc::Clause::ACCC_copyin &&
|
|
cl != llvm::acc::Clause::ACCC_device_resident &&
|
|
cl != llvm::acc::Clause::ACCC_link) {
|
|
context_.Say(GetContext().directiveSource,
|
|
"%s clause is not allowed on the %s directive in module "
|
|
"declaration "
|
|
"section"_err_en_US,
|
|
parser::ToUpperCaseLetters(
|
|
llvm::acc::getOpenACCClauseName(cl).str()),
|
|
ContextDirectiveAsFortran());
|
|
}
|
|
}
|
|
}
|
|
dirContext_.pop_back();
|
|
}
|
|
|
|
void AccStructureChecker::Enter(const parser::OpenACCCombinedConstruct &x) {
|
|
const auto &beginCombinedDir{
|
|
std::get<parser::AccBeginCombinedDirective>(x.t)};
|
|
const auto &combinedDir{
|
|
std::get<parser::AccCombinedDirective>(beginCombinedDir.t)};
|
|
|
|
// check matching, End directive is optional
|
|
if (const auto &endCombinedDir{
|
|
std::get<std::optional<parser::AccEndCombinedDirective>>(x.t)}) {
|
|
CheckMatching<parser::AccCombinedDirective>(combinedDir, endCombinedDir->v);
|
|
}
|
|
|
|
PushContextAndClauseSets(combinedDir.source, combinedDir.v);
|
|
}
|
|
|
|
void AccStructureChecker::Leave(const parser::OpenACCCombinedConstruct &x) {
|
|
const auto &beginBlockDir{std::get<parser::AccBeginCombinedDirective>(x.t)};
|
|
const auto &combinedDir{
|
|
std::get<parser::AccCombinedDirective>(beginBlockDir.t)};
|
|
switch (combinedDir.v) {
|
|
case llvm::acc::Directive::ACCD_kernels_loop:
|
|
case llvm::acc::Directive::ACCD_parallel_loop:
|
|
case llvm::acc::Directive::ACCD_serial_loop:
|
|
// Restriction - line 1004-1005
|
|
CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
|
|
computeConstructOnlyAllowedAfterDeviceTypeClauses);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
dirContext_.pop_back();
|
|
}
|
|
|
|
void AccStructureChecker::Enter(const parser::OpenACCLoopConstruct &x) {
|
|
const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)};
|
|
const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)};
|
|
PushContextAndClauseSets(loopDir.source, loopDir.v);
|
|
}
|
|
|
|
void AccStructureChecker::Leave(const parser::OpenACCLoopConstruct &x) {
|
|
const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)};
|
|
const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)};
|
|
if (loopDir.v == llvm::acc::Directive::ACCD_loop) {
|
|
// Restriction - line 1818-1819
|
|
CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
|
|
loopOnlyAllowedAfterDeviceTypeClauses);
|
|
// Restriction - line 1834
|
|
CheckNotAllowedIfClause(llvm::acc::Clause::ACCC_seq,
|
|
{llvm::acc::Clause::ACCC_gang, llvm::acc::Clause::ACCC_vector,
|
|
llvm::acc::Clause::ACCC_worker});
|
|
}
|
|
dirContext_.pop_back();
|
|
}
|
|
|
|
void AccStructureChecker::Enter(const parser::OpenACCStandaloneConstruct &x) {
|
|
const auto &standaloneDir{std::get<parser::AccStandaloneDirective>(x.t)};
|
|
PushContextAndClauseSets(standaloneDir.source, standaloneDir.v);
|
|
}
|
|
|
|
void AccStructureChecker::Leave(const parser::OpenACCStandaloneConstruct &x) {
|
|
const auto &standaloneDir{std::get<parser::AccStandaloneDirective>(x.t)};
|
|
switch (standaloneDir.v) {
|
|
case llvm::acc::Directive::ACCD_enter_data:
|
|
case llvm::acc::Directive::ACCD_exit_data:
|
|
// Restriction - line 1310-1311 (ENTER DATA)
|
|
// Restriction - line 1312-1313 (EXIT DATA)
|
|
CheckRequireAtLeastOneOf();
|
|
break;
|
|
case llvm::acc::Directive::ACCD_set:
|
|
// Restriction - line 2610
|
|
CheckRequireAtLeastOneOf();
|
|
// Restriction - line 2602
|
|
CheckNotInComputeConstruct();
|
|
break;
|
|
case llvm::acc::Directive::ACCD_update:
|
|
// Restriction - line 2636
|
|
CheckRequireAtLeastOneOf();
|
|
// Restriction - line 2669
|
|
CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
|
|
updateOnlyAllowedAfterDeviceTypeClauses);
|
|
break;
|
|
case llvm::acc::Directive::ACCD_init:
|
|
case llvm::acc::Directive::ACCD_shutdown:
|
|
// Restriction - line 2525 (INIT)
|
|
// Restriction - line 2561 (SHUTDOWN)
|
|
CheckNotInComputeConstruct();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
dirContext_.pop_back();
|
|
}
|
|
|
|
void AccStructureChecker::Enter(const parser::OpenACCRoutineConstruct &x) {
|
|
PushContextAndClauseSets(x.source, llvm::acc::Directive::ACCD_routine);
|
|
const auto &optName{std::get<std::optional<parser::Name>>(x.t)};
|
|
if (!optName) {
|
|
const auto &verbatim{std::get<parser::Verbatim>(x.t)};
|
|
const auto &scope{context_.FindScope(verbatim.source)};
|
|
const Scope &containingScope{GetProgramUnitContaining(scope)};
|
|
if (containingScope.kind() == Scope::Kind::Module) {
|
|
context_.Say(GetContext().directiveSource,
|
|
"ROUTINE directive without name must appear within the specification "
|
|
"part of a subroutine or function definition, or within an interface "
|
|
"body for a subroutine or function in an interface block"_err_en_US);
|
|
}
|
|
}
|
|
}
|
|
void AccStructureChecker::Leave(const parser::OpenACCRoutineConstruct &) {
|
|
// Restriction - line 2790
|
|
CheckRequireAtLeastOneOf();
|
|
// Restriction - line 2788-2789
|
|
CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
|
|
routineOnlyAllowedAfterDeviceTypeClauses);
|
|
dirContext_.pop_back();
|
|
}
|
|
|
|
void AccStructureChecker::Enter(const parser::OpenACCWaitConstruct &x) {
|
|
const auto &verbatim{std::get<parser::Verbatim>(x.t)};
|
|
PushContextAndClauseSets(verbatim.source, llvm::acc::Directive::ACCD_wait);
|
|
}
|
|
void AccStructureChecker::Leave(const parser::OpenACCWaitConstruct &x) {
|
|
dirContext_.pop_back();
|
|
}
|
|
|
|
void AccStructureChecker::Enter(const parser::OpenACCAtomicConstruct &x) {
|
|
PushContextAndClauseSets(x.source, llvm::acc::Directive::ACCD_atomic);
|
|
}
|
|
void AccStructureChecker::Leave(const parser::OpenACCAtomicConstruct &x) {
|
|
dirContext_.pop_back();
|
|
}
|
|
|
|
void AccStructureChecker::Enter(const parser::OpenACCCacheConstruct &x) {
|
|
const auto &verbatim = std::get<parser::Verbatim>(x.t);
|
|
PushContextAndClauseSets(verbatim.source, llvm::acc::Directive::ACCD_cache);
|
|
SetContextDirectiveSource(verbatim.source);
|
|
}
|
|
void AccStructureChecker::Leave(const parser::OpenACCCacheConstruct &x) {
|
|
dirContext_.pop_back();
|
|
}
|
|
|
|
// Clause checkers
|
|
CHECK_REQ_SCALAR_INT_CONSTANT_CLAUSE(Collapse, ACCC_collapse)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Auto, ACCC_auto)
|
|
CHECK_SIMPLE_CLAUSE(Async, ACCC_async)
|
|
CHECK_SIMPLE_CLAUSE(Attach, ACCC_attach)
|
|
CHECK_SIMPLE_CLAUSE(Bind, ACCC_bind)
|
|
CHECK_SIMPLE_CLAUSE(Capture, ACCC_capture)
|
|
CHECK_SIMPLE_CLAUSE(Copy, ACCC_copy)
|
|
CHECK_SIMPLE_CLAUSE(Default, ACCC_default)
|
|
CHECK_SIMPLE_CLAUSE(DefaultAsync, ACCC_default_async)
|
|
CHECK_SIMPLE_CLAUSE(Delete, ACCC_delete)
|
|
CHECK_SIMPLE_CLAUSE(Detach, ACCC_detach)
|
|
CHECK_SIMPLE_CLAUSE(Device, ACCC_device)
|
|
CHECK_SIMPLE_CLAUSE(DeviceNum, ACCC_device_num)
|
|
CHECK_SIMPLE_CLAUSE(Deviceptr, ACCC_deviceptr)
|
|
CHECK_SIMPLE_CLAUSE(DeviceResident, ACCC_device_resident)
|
|
CHECK_SIMPLE_CLAUSE(DeviceType, ACCC_device_type)
|
|
CHECK_SIMPLE_CLAUSE(Finalize, ACCC_finalize)
|
|
CHECK_SIMPLE_CLAUSE(Firstprivate, ACCC_firstprivate)
|
|
CHECK_SIMPLE_CLAUSE(Gang, ACCC_gang)
|
|
CHECK_SIMPLE_CLAUSE(Host, ACCC_host)
|
|
CHECK_SIMPLE_CLAUSE(If, ACCC_if)
|
|
CHECK_SIMPLE_CLAUSE(IfPresent, ACCC_if_present)
|
|
CHECK_SIMPLE_CLAUSE(Independent, ACCC_independent)
|
|
CHECK_SIMPLE_CLAUSE(Link, ACCC_link)
|
|
CHECK_SIMPLE_CLAUSE(NoCreate, ACCC_no_create)
|
|
CHECK_SIMPLE_CLAUSE(Nohost, ACCC_nohost)
|
|
CHECK_SIMPLE_CLAUSE(NumGangs, ACCC_num_gangs)
|
|
CHECK_SIMPLE_CLAUSE(NumWorkers, ACCC_num_workers)
|
|
CHECK_SIMPLE_CLAUSE(Present, ACCC_present)
|
|
CHECK_SIMPLE_CLAUSE(Private, ACCC_private)
|
|
CHECK_SIMPLE_CLAUSE(Read, ACCC_read)
|
|
CHECK_SIMPLE_CLAUSE(Reduction, ACCC_reduction)
|
|
CHECK_SIMPLE_CLAUSE(Seq, ACCC_seq)
|
|
CHECK_SIMPLE_CLAUSE(Tile, ACCC_tile)
|
|
CHECK_SIMPLE_CLAUSE(UseDevice, ACCC_use_device)
|
|
CHECK_SIMPLE_CLAUSE(Vector, ACCC_vector)
|
|
CHECK_SIMPLE_CLAUSE(VectorLength, ACCC_vector_length)
|
|
CHECK_SIMPLE_CLAUSE(Wait, ACCC_wait)
|
|
CHECK_SIMPLE_CLAUSE(Worker, ACCC_worker)
|
|
CHECK_SIMPLE_CLAUSE(Write, ACCC_write)
|
|
CHECK_SIMPLE_CLAUSE(Unknown, ACCC_unknown)
|
|
|
|
void AccStructureChecker::Enter(const parser::AccClause::Create &c) {
|
|
CheckAllowed(llvm::acc::Clause::ACCC_create);
|
|
const auto &modifierClause{c.v};
|
|
if (const auto &modifier{
|
|
std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) {
|
|
if (modifier->v != parser::AccDataModifier::Modifier::Zero) {
|
|
context_.Say(GetContext().clauseSource,
|
|
"Only the ZERO modifier is allowed for the %s clause "
|
|
"on the %s directive"_err_en_US,
|
|
parser::ToUpperCaseLetters(
|
|
llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_create)
|
|
.str()),
|
|
ContextDirectiveAsFortran());
|
|
}
|
|
}
|
|
}
|
|
|
|
void AccStructureChecker::Enter(const parser::AccClause::Copyin &c) {
|
|
CheckAllowed(llvm::acc::Clause::ACCC_copyin);
|
|
const auto &modifierClause{c.v};
|
|
if (const auto &modifier{
|
|
std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) {
|
|
if (CheckAllowedModifier(llvm::acc::Clause::ACCC_copyin)) {
|
|
return;
|
|
}
|
|
if (modifier->v != parser::AccDataModifier::Modifier::ReadOnly) {
|
|
context_.Say(GetContext().clauseSource,
|
|
"Only the READONLY modifier is allowed for the %s clause "
|
|
"on the %s directive"_err_en_US,
|
|
parser::ToUpperCaseLetters(
|
|
llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_copyin)
|
|
.str()),
|
|
ContextDirectiveAsFortran());
|
|
}
|
|
}
|
|
}
|
|
|
|
void AccStructureChecker::Enter(const parser::AccClause::Copyout &c) {
|
|
CheckAllowed(llvm::acc::Clause::ACCC_copyout);
|
|
const auto &modifierClause{c.v};
|
|
if (const auto &modifier{
|
|
std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) {
|
|
if (CheckAllowedModifier(llvm::acc::Clause::ACCC_copyout)) {
|
|
return;
|
|
}
|
|
if (modifier->v != parser::AccDataModifier::Modifier::Zero) {
|
|
context_.Say(GetContext().clauseSource,
|
|
"Only the ZERO modifier is allowed for the %s clause "
|
|
"on the %s directive"_err_en_US,
|
|
parser::ToUpperCaseLetters(
|
|
llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_copyout)
|
|
.str()),
|
|
ContextDirectiveAsFortran());
|
|
}
|
|
}
|
|
}
|
|
|
|
void AccStructureChecker::Enter(const parser::AccClause::Self &x) {
|
|
CheckAllowed(llvm::acc::Clause::ACCC_self);
|
|
const parser::AccSelfClause &accSelfClause = x.v;
|
|
if (GetContext().directive == llvm::acc::Directive::ACCD_update &&
|
|
std::holds_alternative<std::optional<parser::ScalarLogicalExpr>>(
|
|
accSelfClause.u)) {
|
|
context_.Say(GetContext().clauseSource,
|
|
"SELF clause on the %s directive must have a var-list"_err_en_US,
|
|
ContextDirectiveAsFortran());
|
|
} else if (GetContext().directive != llvm::acc::Directive::ACCD_update &&
|
|
std::holds_alternative<parser::AccObjectList>(accSelfClause.u)) {
|
|
const auto &accObjectList =
|
|
std::get<parser::AccObjectList>(accSelfClause.u);
|
|
if (accObjectList.v.size() != 1) {
|
|
context_.Say(GetContext().clauseSource,
|
|
"SELF clause on the %s directive only accepts optional scalar logical"
|
|
" expression"_err_en_US,
|
|
ContextDirectiveAsFortran());
|
|
}
|
|
}
|
|
}
|
|
|
|
llvm::StringRef AccStructureChecker::getClauseName(llvm::acc::Clause clause) {
|
|
return llvm::acc::getOpenACCClauseName(clause);
|
|
}
|
|
|
|
llvm::StringRef AccStructureChecker::getDirectiveName(
|
|
llvm::acc::Directive directive) {
|
|
return llvm::acc::getOpenACCDirectiveName(directive);
|
|
}
|
|
|
|
} // namespace Fortran::semantics
|