diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -66,6 +66,7 @@ NODE(parser, AccClause) #define GEN_FLANG_DUMP_PARSE_TREE_CLAUSES #include "llvm/Frontend/OpenACC/ACC.cpp.inc" + NODE(parser, AccBindClause) NODE(parser, AccDefaultClause) NODE_ENUM(parser::AccDefaultClause, Arg) NODE(parser, AccClauseList) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3818,6 +3818,12 @@ }; // OpenACC Clauses +struct AccBindClause { + UNION_CLASS_BOILERPLATE(AccBindClause); + std::variant u; + CharBlock source; +}; + struct AccDefaultClause { ENUM_CLASS(Arg, None, Present) WRAPPER_CLASS_BOILERPLATE(AccDefaultClause, Arg); @@ -4008,7 +4014,8 @@ struct OpenACCDeclarativeConstruct { UNION_CLASS_BOILERPLATE(OpenACCDeclarativeConstruct); CharBlock source; - std::variant u; + std::variant + u; }; // OpenACC directives enclosing do loop @@ -4028,8 +4035,8 @@ struct OpenACCConstruct { UNION_CLASS_BOILERPLATE(OpenACCConstruct); std::variant + OpenACCLoopConstruct, OpenACCStandaloneConstruct, OpenACCCacheConstruct, + OpenACCWaitConstruct, OpenACCAtomicConstruct> u; }; diff --git a/flang/lib/Parser/openacc-parsers.cpp b/flang/lib/Parser/openacc-parsers.cpp --- a/flang/lib/Parser/openacc-parsers.cpp +++ b/flang/lib/Parser/openacc-parsers.cpp @@ -28,8 +28,8 @@ maybe(parenthesized(scalarIntExpr)))) || "ATTACH" >> construct(construct( parenthesized(Parser{}))) || - "BIND" >> - construct(construct(parenthesized(name))) || + "BIND" >> construct( + construct(Parser{})) || "CAPTURE" >> construct(construct()) || "COLLAPSE" >> construct(construct( parenthesized(scalarIntConstantExpr))) || @@ -171,6 +171,10 @@ ".EQV." >> pure(AccReductionOperator::Operator::Eqv), ".NEQV." >> pure(AccReductionOperator::Operator::Neqv))))) +// 2.15.1 Bind clause +TYPE_PARSER(sourced(construct(parenthesized(name))) || + sourced(construct(parenthesized(scalarDefaultCharExpr)))) + // 2.5.14 Default clause TYPE_PARSER(construct( parenthesized(first("NONE" >> pure(AccDefaultClause::Arg::None), @@ -286,8 +290,10 @@ sourced(Parser{}), Parser{})) TYPE_PARSER( - startAccLine >> sourced(construct( - Parser{}))) + startAccLine >> first(sourced(construct( + Parser{})), + sourced(construct( + Parser{})))) // OpenACC constructs TYPE_CONTEXT_PARSER("OpenACC construct"_en_US, @@ -296,7 +302,6 @@ construct(Parser{}), construct(Parser{}), construct(Parser{}), - construct(Parser{}), construct(Parser{}), construct(Parser{}), construct(Parser{}))) diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -1839,6 +1839,15 @@ void Unparse(const AccDataModifier::Modifier &x) { Word(AccDataModifier::EnumToString(x)); } + void Unparse(const AccBindClause &x) { + std::visit(common::visitors{ + [&](const Name &y) { Put('('), Walk(y), Put(')'); }, + [&](const ScalarDefaultCharExpr &y) { + Put('('), Walk(y), Put(')'); + }, + }, + x.u); + } void Unparse(const AccDefaultClause &x) { switch (x.v) { case AccDefaultClause::Arg::None: diff --git a/flang/lib/Semantics/check-acc-structure.cpp b/flang/lib/Semantics/check-acc-structure.cpp --- a/flang/lib/Semantics/check-acc-structure.cpp +++ b/flang/lib/Semantics/check-acc-structure.cpp @@ -213,6 +213,18 @@ void AccStructureChecker::Enter(const parser::OpenACCRoutineConstruct &x) { PushContextAndClauseSets(x.source, llvm::acc::Directive::ACCD_routine); + const auto &optName{std::get>(x.t)}; + if (!optName) { + const auto &verbatim{std::get(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 " + "port 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 - 2409 diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -114,16 +114,17 @@ template bool Pre(const A &) { return true; } template void Post(const A &) {} - bool Pre(const parser::SpecificationPart &x) { - Walk(std::get>(x.t)); - return false; - } - bool Pre(const parser::OpenACCBlockConstruct &); void Post(const parser::OpenACCBlockConstruct &) { PopContext(); } bool Pre(const parser::OpenACCCombinedConstruct &); void Post(const parser::OpenACCCombinedConstruct &) { PopContext(); } + bool Pre(const parser::OpenACCDeclarativeConstruct &); + void Post(const parser::OpenACCDeclarativeConstruct &) { PopContext(); } + + bool Pre(const parser::OpenACCRoutineConstruct &); + bool Pre(const parser::AccBindClause &); + void Post(const parser::AccBeginBlockDirective &) { GetContext().withinConstruct = true; } @@ -207,6 +208,7 @@ void ResolveAccObject(const parser::AccObject &, Symbol::Flag); Symbol *ResolveAcc(const parser::Name &, Symbol::Flag, Scope &); Symbol *ResolveAcc(Symbol &, Symbol::Flag, Scope &); + Symbol *ResolveName(const parser::Name &); Symbol *ResolveAccCommonBlockName(const parser::Name *); Symbol *DeclareOrMarkOtherAccessEntity(const parser::Name &, Symbol::Flag); Symbol *DeclareOrMarkOtherAccessEntity(Symbol &, Symbol::Flag); @@ -440,6 +442,21 @@ return true; } +bool AccAttributeVisitor::Pre(const parser::OpenACCDeclarativeConstruct &x) { + if (const auto *declConstruct{ + std::get_if(&x.u)}) { + const auto &declDir{ + std::get(declConstruct->t)}; + PushContext(declDir.source, llvm::acc::Directive::ACCD_declare); + } else if (const auto *routineConstruct{ + std::get_if(&x.u)}) { + const auto &verbatim{std::get(routineConstruct->t)}; + PushContext(verbatim.source, llvm::acc::Directive::ACCD_routine); + } + ClearDataSharingAttributeObjects(); + return true; +} + bool AccAttributeVisitor::Pre(const parser::OpenACCLoopConstruct &x) { const auto &beginDir{std::get(x.t)}; const auto &loopDir{std::get(beginDir.t)}; @@ -471,6 +488,29 @@ return true; } +Symbol *AccAttributeVisitor::ResolveName(const parser::Name &name) { + Symbol *prev{currScope().FindSymbol(name.source)}; + if (prev != name.symbol) { + name.symbol = prev; + } + return prev; +} + +bool AccAttributeVisitor::Pre(const parser::OpenACCRoutineConstruct &x) { + const auto &optName{std::get>(x.t)}; + if (optName) { + ResolveName(*optName); + } + return true; +} + +bool AccAttributeVisitor::Pre(const parser::AccBindClause &x) { + if (const auto *name{std::get_if(&x.u)}) { + ResolveName(*name); + } + return true; +} + bool AccAttributeVisitor::Pre(const parser::OpenACCCombinedConstruct &x) { const auto &beginBlockDir{std::get(x.t)}; const auto &combinedDir{ diff --git a/flang/test/Semantics/acc-clause-validity.f90 b/flang/test/Semantics/acc-clause-validity.f90 --- a/flang/test/Semantics/acc-clause-validity.f90 +++ b/flang/test/Semantics/acc-clause-validity.f90 @@ -677,18 +677,4 @@ !ERROR: Only array element or subarray are allowed in CACHE directive !$acc cache(/i/) - contains - - subroutine sub1(a) - real :: a(:) - !ERROR: At least one of GANG, SEQ, VECTOR, WORKER clause must appear on the ROUTINE directive - !$acc routine - end subroutine sub1 - - subroutine sub2(a) - real :: a(:) - !ERROR: Clause NOHOST is not allowed after clause DEVICE_TYPE on the ROUTINE directive - !$acc routine seq device_type(*) nohost - end subroutine sub2 - end program openacc_clause_validity diff --git a/flang/test/Semantics/acc-routine-validity.f90 b/flang/test/Semantics/acc-routine-validity.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/acc-routine-validity.f90 @@ -0,0 +1,79 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenacc + +! Check OpenACC clause validity for the following construct and directive: +! 2.15.1 routine + +module openacc_routine_validity + implicit none + + !$acc routine(sub3) seq + + !$acc routine(fct2) vector + + !ERROR: At least one of GANG, SEQ, VECTOR, WORKER clause must appear on the ROUTINE directive + !$acc routine(sub3) + + !ERROR: ROUTINE directive without name must appear within the specification port of a subroutine or function definition, or within an interface body for a subroutine or function in an interface block + !$acc routine seq + + !ERROR: Internal: no symbol found for 'dummy' + !$acc routine(dummy) seq + +contains + + subroutine sub1(a) + real :: a(:) + !ERROR: At least one of GANG, SEQ, VECTOR, WORKER clause must appear on the ROUTINE directive + !$acc routine + end subroutine sub1 + + subroutine sub2(a) + real :: a(:) + !ERROR: Clause NOHOST is not allowed after clause DEVICE_TYPE on the ROUTINE directive + !$acc routine seq device_type(*) nohost + end subroutine sub2 + + subroutine sub3(a) + real :: a(:) + end subroutine sub3 + + subroutine sub4(a) + real :: a(:) + !$acc routine seq + end subroutine sub4 + + subroutine sub5(a) + real :: a(:) + !$acc routine(sub5) seq + end subroutine sub5 + + function fct1(a) + integer :: fct1 + real :: a(:) + !$acc routine vector nohost + end function fct1 + + function fct2(a) + integer :: fct2 + real :: a(:) + end function fct2 + + function fct3(a) + integer :: fct3 + real :: a(:) + !$acc routine seq bind(fct2) + end function fct3 + + function fct4(a) + integer :: fct4 + real :: a(:) + !$acc routine seq bind("_fct4") + end function fct4 + + subroutine sub6(a) + real :: a(:) + !ERROR: Internal: no symbol found for 'dummy_sub' + !$acc routine seq bind(dummy_sub) + end subroutine sub6 + +end module openacc_routine_validity diff --git a/llvm/include/llvm/Frontend/OpenACC/ACC.td b/llvm/include/llvm/Frontend/OpenACC/ACC.td --- a/llvm/include/llvm/Frontend/OpenACC/ACC.td +++ b/llvm/include/llvm/Frontend/OpenACC/ACC.td @@ -48,7 +48,7 @@ // 2.15.1 def ACCC_Bind : Clause<"bind"> { - let flangClassValue = "Name"; + let flangClassValue = "AccBindClause"; } // 2.12