diff --git a/flang/lib/Semantics/check-acc-structure.cpp b/flang/lib/Semantics/check-acc-structure.cpp index ff2fce261cd46..e8d55aa9bdd2e 100644 --- a/flang/lib/Semantics/check-acc-structure.cpp +++ b/flang/lib/Semantics/check-acc-structure.cpp @@ -342,15 +342,12 @@ 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) @@ -358,11 +355,9 @@ 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(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(Seq, ACCC_seq) @@ -375,6 +370,39 @@ CHECK_SIMPLE_CLAUSE(Worker, ACCC_worker) CHECK_SIMPLE_CLAUSE(Write, ACCC_write) CHECK_SIMPLE_CLAUSE(Unknown, ACCC_unknown) +void AccStructureChecker::CheckMultipleOccurrenceInDeclare( + const parser::AccObjectList &list, llvm::acc::Clause clause) { + if (GetContext().directive != llvm::acc::Directive::ACCD_declare) + return; + for (const auto &object : list.v) { + std::visit( + Fortran::common::visitors{ + [&](const Fortran::parser::Designator &designator) { + if (const auto *name = getDesignatorNameIfDataRef(designator)) { + if (declareSymbols.contains(&name->symbol->GetUltimate())) { + context_.Say(GetContext().clauseSource, + "'%s' in the %s clause is already present in another " + "clause in this module"_err_en_US, + name->symbol->name(), + parser::ToUpperCaseLetters( + llvm::acc::getOpenACCClauseName(clause).str())); + } + declareSymbols.insert(&name->symbol->GetUltimate()); + } + }, + [&](const Fortran::parser::Name &name) { + // TODO: check common block + }}, + object.u); + } +} + +void AccStructureChecker::CheckMultipleOccurrenceInDeclare( + const parser::AccObjectListWithModifier &list, llvm::acc::Clause clause) { + const auto &objectList = std::get(list.t); + CheckMultipleOccurrenceInDeclare(objectList, clause); +} + void AccStructureChecker::Enter(const parser::AccClause::Create &c) { CheckAllowed(llvm::acc::Clause::ACCC_create); const auto &modifierClause{c.v}; @@ -399,6 +427,8 @@ void AccStructureChecker::Enter(const parser::AccClause::Create &c) { ContextDirectiveAsFortran()); } } + CheckMultipleOccurrenceInDeclare( + modifierClause, llvm::acc::Clause::ACCC_create); } void AccStructureChecker::Enter(const parser::AccClause::Copyin &c) { @@ -419,6 +449,8 @@ void AccStructureChecker::Enter(const parser::AccClause::Copyin &c) { ContextDirectiveAsFortran()); } } + CheckMultipleOccurrenceInDeclare( + modifierClause, llvm::acc::Clause::ACCC_copyin); } void AccStructureChecker::Enter(const parser::AccClause::Copyout &c) { @@ -448,6 +480,8 @@ void AccStructureChecker::Enter(const parser::AccClause::Copyout &c) { ContextDirectiveAsFortran()); } } + CheckMultipleOccurrenceInDeclare( + modifierClause, llvm::acc::Clause::ACCC_copyout); } void AccStructureChecker::Enter(const parser::AccClause::Gang &g) { @@ -563,8 +597,46 @@ void AccStructureChecker::Enter(const parser::AccClause::Collapse &x) { llvm::acc::Clause::ACCC_collapse, collapseValue); } -llvm::StringRef AccStructureChecker::getClauseName(llvm::acc::Clause clause) { - return llvm::acc::getOpenACCClauseName(clause); +void AccStructureChecker::Enter(const parser::AccClause::Present &x) { + CheckAllowed(llvm::acc::Clause::ACCC_present); + CheckMultipleOccurrenceInDeclare(x.v, llvm::acc::Clause::ACCC_present); +} + +void AccStructureChecker::Enter(const parser::AccClause::Copy &x) { + CheckAllowed(llvm::acc::Clause::ACCC_copy); + CheckMultipleOccurrenceInDeclare(x.v, llvm::acc::Clause::ACCC_copy); +} + +void AccStructureChecker::Enter(const parser::AccClause::Deviceptr &x) { + CheckAllowed(llvm::acc::Clause::ACCC_deviceptr); + CheckMultipleOccurrenceInDeclare(x.v, llvm::acc::Clause::ACCC_deviceptr); +} + +void AccStructureChecker::Enter(const parser::AccClause::DeviceResident &x) { + CheckAllowed(llvm::acc::Clause::ACCC_device_resident); + CheckMultipleOccurrenceInDeclare( + x.v, llvm::acc::Clause::ACCC_device_resident); +} + +void AccStructureChecker::Enter(const parser::AccClause::Link &x) { + CheckAllowed(llvm::acc::Clause::ACCC_link); + CheckMultipleOccurrenceInDeclare(x.v, llvm::acc::Clause::ACCC_link); +} + +void AccStructureChecker::Enter(const parser::Module &) { + declareSymbols.clear(); +} + +void AccStructureChecker::Enter(const parser::FunctionSubprogram &x) { + declareSymbols.clear(); +} + +void AccStructureChecker::Enter(const parser::SubroutineSubprogram &) { + declareSymbols.clear(); +} + +void AccStructureChecker::Enter(const parser::SeparateModuleSubprogram &) { + declareSymbols.clear(); } llvm::StringRef AccStructureChecker::getDirectiveName( @@ -572,4 +644,8 @@ llvm::StringRef AccStructureChecker::getDirectiveName( return llvm::acc::getOpenACCDirectiveName(directive); } +llvm::StringRef AccStructureChecker::getClauseName(llvm::acc::Clause clause) { + return llvm::acc::getOpenACCClauseName(clause); +} + } // namespace Fortran::semantics diff --git a/flang/lib/Semantics/check-acc-structure.h b/flang/lib/Semantics/check-acc-structure.h index 42745a6ca69a1..8c0d7150dd47b 100644 --- a/flang/lib/Semantics/check-acc-structure.h +++ b/flang/lib/Semantics/check-acc-structure.h @@ -18,6 +18,7 @@ #include "flang/Common/enum-set.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/semantics.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/Frontend/OpenACC/ACC.h.inc" using AccDirectiveSet = Fortran::common::EnumSet declareSymbols; }; } // namespace Fortran::semantics diff --git a/flang/lib/Semantics/semantics.cpp b/flang/lib/Semantics/semantics.cpp index 6a52d31295393..f2be4465083d6 100644 --- a/flang/lib/Semantics/semantics.cpp +++ b/flang/lib/Semantics/semantics.cpp @@ -166,8 +166,6 @@ using StatementSemanticsPass2 = SemanticsVisitor; -using StatementSemanticsPass3 = - SemanticsVisitor; static bool PerformStatementSemantics( SemanticsContext &context, parser::Program &program) { @@ -178,10 +176,14 @@ static bool PerformStatementSemantics( StatementSemanticsPass1{context}.Walk(program); StatementSemanticsPass2 pass2{context}; pass2.Walk(program); - if (context.languageFeatures().IsEnabled(common::LanguageFeature::OpenACC) || - context.languageFeatures().IsEnabled(common::LanguageFeature::OpenMP) || - context.languageFeatures().IsEnabled(common::LanguageFeature::CUDA)) { - StatementSemanticsPass3{context}.Walk(program); + if (context.languageFeatures().IsEnabled(common::LanguageFeature::OpenACC)) { + SemanticsVisitor{context}.Walk(program); + } + if (context.languageFeatures().IsEnabled(common::LanguageFeature::OpenMP)) { + SemanticsVisitor{context}.Walk(program); + } + if (context.languageFeatures().IsEnabled(common::LanguageFeature::CUDA)) { + SemanticsVisitor{context}.Walk(program); } if (!context.AnyFatalError()) { pass2.CompileDataInitializationsIntoInitializers(); diff --git a/flang/test/Semantics/OpenACC/acc-declare-validity.f90 b/flang/test/Semantics/OpenACC/acc-declare-validity.f90 index 6fa3b33bb2ccd..c0333d78dd9f7 100644 --- a/flang/test/Semantics/OpenACC/acc-declare-validity.f90 +++ b/flang/test/Semantics/OpenACC/acc-declare-validity.f90 @@ -7,31 +7,34 @@ module openacc_declare_validity implicit none - real(8), dimension(10) :: aa, bb, ab, cc + real(8), dimension(10) :: aa, bb, ab, ac, ad, ae, af, cc, dd !ERROR: At least one clause is required on the DECLARE directive !$acc declare !$acc declare create(aa, bb) + !ERROR: 'aa' in the CREATE clause is already present in another clause in this module + !$acc declare create(aa) + !$acc declare link(ab) !$acc declare device_resident(cc) !ERROR: COPYOUT clause is not allowed on the DECLARE directive in module declaration section - !$acc declare copyout(ab) + !$acc declare copyout(ac) !ERROR: COPY clause is not allowed on the DECLARE directive in module declaration section - !$acc declare copy(ab) + !$acc declare copy(af) !ERROR: PRESENT clause is not allowed on the DECLARE directive in module declaration section - !$acc declare present(ab) + !$acc declare present(ad) !ERROR: DEVICEPTR clause is not allowed on the DECLARE directive in module declaration section - !$acc declare deviceptr(ab) + !$acc declare deviceptr(ae) !ERROR: The ZERO modifier is not allowed for the CREATE clause on the DECLARE directive - !$acc declare create(zero: aa) + !$acc declare create(zero: dd) contains @@ -39,6 +42,8 @@ subroutine sub1(cc, dd) real(8) :: cc(:) real(8) :: dd(:) !$acc declare present(cc, dd) + !ERROR: 'cc' in the CREATE clause is already present in another clause in this module + !$acc declare create(cc) end subroutine sub1 function fct1(ee, ff, gg, hh, ii)