@@ -624,11 +624,6 @@ template <typename Checker> struct DirectiveSpellingVisitor {
624624 checker_ (std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_assumes);
625625 return false ;
626626 }
627- bool Pre (const parser::OpenMPDeclareTargetConstruct &x) {
628- checker_ (
629- std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_declare_target);
630- return false ;
631- }
632627 bool Pre (const parser::OpenMPGroupprivate &x) {
633628 checker_ (x.v .DirName ().source , Directive::OMPD_groupprivate);
634629 return false ;
@@ -1615,38 +1610,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Allocate &x) {
16151610 }
16161611}
16171612
1618- void OmpStructureChecker::Enter (const parser::OmpDeclareTargetWithClause &x) {
1619- SetClauseSets (llvm::omp::Directive::OMPD_declare_target);
1620- }
1621-
1622- void OmpStructureChecker::Leave (const parser::OmpDeclareTargetWithClause &x) {
1623- if (x.v .v .size () > 0 ) {
1624- const parser::OmpClause *enterClause =
1625- FindClause (llvm::omp::Clause::OMPC_enter);
1626- const parser::OmpClause *toClause = FindClause (llvm::omp::Clause::OMPC_to);
1627- const parser::OmpClause *linkClause =
1628- FindClause (llvm::omp::Clause::OMPC_link);
1629- const parser::OmpClause *indirectClause =
1630- FindClause (llvm::omp::Clause::OMPC_indirect);
1631- if (!enterClause && !toClause && !linkClause) {
1632- context_.Say (x.source ,
1633- " If the DECLARE TARGET directive has a clause, it must contain at least one ENTER clause or LINK clause" _err_en_US);
1634- }
1635- if (indirectClause && !enterClause) {
1636- context_.Say (x.source ,
1637- " The INDIRECT clause cannot be used without the ENTER clause with the DECLARE TARGET directive." _err_en_US);
1638- }
1639- unsigned version{context_.langOptions ().OpenMPVersion };
1640- if (toClause && version >= 52 ) {
1641- context_.Warn (common::UsageWarning::OpenMPUsage, toClause->source ,
1642- " The usage of TO clause on DECLARE TARGET directive has been deprecated. Use ENTER clause instead." _warn_en_US);
1643- }
1644- if (indirectClause) {
1645- CheckAllowedClause (llvm::omp::Clause::OMPC_indirect);
1646- }
1647- }
1648- }
1649-
16501613void OmpStructureChecker::Enter (const parser::OpenMPDeclareMapperConstruct &x) {
16511614 const parser::OmpDirectiveName &dirName{x.v .DirName ()};
16521615 PushContextAndClauseSets (dirName.source , dirName.v );
@@ -1698,42 +1661,6 @@ void OmpStructureChecker::Leave(
16981661 dirContext_.pop_back ();
16991662}
17001663
1701- void OmpStructureChecker::Enter (const parser::OpenMPDeclareTargetConstruct &x) {
1702- const auto &dir{std::get<parser::Verbatim>(x.t )};
1703- PushContext (dir.source , llvm::omp::Directive::OMPD_declare_target);
1704- }
1705-
1706- void OmpStructureChecker::Enter (const parser::OmpDeclareTargetWithList &x) {
1707- SymbolSourceMap symbols;
1708- GetSymbolsInObjectList (x.v , symbols);
1709- for (auto &[symbol, source] : symbols) {
1710- const GenericDetails *genericDetails = symbol->detailsIf <GenericDetails>();
1711- if (genericDetails) {
1712- context_.Say (source,
1713- " The procedure '%s' in DECLARE TARGET construct cannot be a generic name." _err_en_US,
1714- symbol->name ());
1715- genericDetails->specific ();
1716- }
1717- if (IsProcedurePointer (*symbol)) {
1718- context_.Say (source,
1719- " The procedure '%s' in DECLARE TARGET construct cannot be a procedure pointer." _err_en_US,
1720- symbol->name ());
1721- }
1722- const SubprogramDetails *entryDetails =
1723- symbol->detailsIf <SubprogramDetails>();
1724- if (entryDetails && entryDetails->entryScope ()) {
1725- context_.Say (source,
1726- " The procedure '%s' in DECLARE TARGET construct cannot be an entry name." _err_en_US,
1727- symbol->name ());
1728- }
1729- if (IsStmtFunction (*symbol)) {
1730- context_.Say (source,
1731- " The procedure '%s' in DECLARE TARGET construct cannot be a statement function." _err_en_US,
1732- symbol->name ());
1733- }
1734- }
1735- }
1736-
17371664void OmpStructureChecker::CheckSymbolName (
17381665 const parser::CharBlock &source, const parser::OmpObject &object) {
17391666 common::visit (
@@ -1766,62 +1693,138 @@ void OmpStructureChecker::CheckSymbolNames(
17661693 }
17671694}
17681695
1696+ void OmpStructureChecker::Enter (const parser::OpenMPDeclareTargetConstruct &x) {
1697+ const parser::OmpDirectiveName &dirName{x.v .DirName ()};
1698+ PushContext (dirName.source , dirName.v );
1699+
1700+ // Check if arguments are extended-list-items.
1701+ for (const parser::OmpArgument &arg : x.v .Arguments ().v ) {
1702+ const Symbol *symbol{GetArgumentSymbol (arg)};
1703+ if (!symbol) {
1704+ context_.Say (arg.source ,
1705+ " An argument to the DECLARE TARGET directive should be an extended-list-item" _err_en_US);
1706+ continue ;
1707+ }
1708+ const GenericDetails *genericDetails = symbol->detailsIf <GenericDetails>();
1709+ if (genericDetails) {
1710+ context_.Say (arg.source ,
1711+ " The procedure '%s' in DECLARE TARGET construct cannot be a generic name." _err_en_US,
1712+ symbol->name ());
1713+ genericDetails->specific ();
1714+ }
1715+ if (IsProcedurePointer (*symbol)) {
1716+ context_.Say (arg.source ,
1717+ " The procedure '%s' in DECLARE TARGET construct cannot be a procedure pointer." _err_en_US,
1718+ symbol->name ());
1719+ }
1720+ const SubprogramDetails *entryDetails =
1721+ symbol->detailsIf <SubprogramDetails>();
1722+ if (entryDetails && entryDetails->entryScope ()) {
1723+ context_.Say (arg.source ,
1724+ " The procedure '%s' in DECLARE TARGET construct cannot be an entry name." _err_en_US,
1725+ symbol->name ());
1726+ }
1727+ if (IsStmtFunction (*symbol)) {
1728+ context_.Say (arg.source ,
1729+ " The procedure '%s' in DECLARE TARGET construct cannot be a statement function." _err_en_US,
1730+ symbol->name ());
1731+ }
1732+ }
1733+
1734+ // Check if there are arguments or clauses, but not both.
1735+ if (!x.v .Clauses ().v .empty ()) {
1736+ if (!x.v .Arguments ().v .empty ()) {
1737+ context_.Say (x.source ,
1738+ " DECLARE TARGET directive can have argument or clauses, but not both" _err_en_US);
1739+ }
1740+ SetClauseSets (llvm::omp::Directive::OMPD_declare_target);
1741+ }
1742+ }
1743+
17691744void OmpStructureChecker::Leave (const parser::OpenMPDeclareTargetConstruct &x) {
1770- const auto &dir{std::get< parser::Verbatim>(x. t )};
1771- const auto &spec{std::get<parser::OmpDeclareTargetSpecifier>(x. t )};
1745+ const parser::OmpDirectiveName &dirName{x. v . DirName ( )};
1746+
17721747 // Handle both forms of DECLARE TARGET.
17731748 // - Extended list: It behaves as if there was an ENTER/TO clause with the
17741749 // list of objects as argument. It accepts no explicit clauses.
17751750 // - With clauses.
1776- if (const auto *objectList{parser::Unwrap<parser::OmpObjectList>(spec.u )}) {
1777- deviceConstructFound_ = true ;
1778- CheckSymbolNames (dir.source , *objectList);
1779- CheckVarIsNotPartOfAnotherVar (dir.source , *objectList);
1780- CheckThreadprivateOrDeclareTargetVar (*objectList);
1781- } else if (const auto *clauseList{
1782- parser::Unwrap<parser::OmpClauseList>(spec.u )}) {
1783- bool toClauseFound{false }, deviceTypeClauseFound{false },
1784- enterClauseFound{false };
1785- for (const auto &clause : clauseList->v ) {
1786- common::visit (
1787- common::visitors{
1788- [&](const parser::OmpClause::To &toClause) {
1789- toClauseFound = true ;
1790- auto &objList{std::get<parser::OmpObjectList>(toClause.v .t )};
1791- CheckSymbolNames (dir.source , objList);
1792- CheckVarIsNotPartOfAnotherVar (dir.source , objList);
1793- CheckThreadprivateOrDeclareTargetVar (objList);
1794- },
1795- [&](const parser::OmpClause::Link &linkClause) {
1796- CheckSymbolNames (dir.source , linkClause.v );
1797- CheckVarIsNotPartOfAnotherVar (dir.source , linkClause.v );
1798- CheckThreadprivateOrDeclareTargetVar (linkClause.v );
1799- },
1800- [&](const parser::OmpClause::Enter &enterClause) {
1801- enterClauseFound = true ;
1802- auto &objList{std::get<parser::OmpObjectList>(enterClause.v .t )};
1803- CheckSymbolNames (dir.source , objList);
1804- CheckVarIsNotPartOfAnotherVar (dir.source , objList);
1805- CheckThreadprivateOrDeclareTargetVar (objList);
1806- },
1807- [&](const parser::OmpClause::DeviceType &deviceTypeClause) {
1808- deviceTypeClauseFound = true ;
1809- if (deviceTypeClause.v .v !=
1810- parser::OmpDeviceTypeClause::DeviceTypeDescription::Host) {
1811- // Function / subroutine explicitly marked as runnable by the
1812- // target device.
1813- deviceConstructFound_ = true ;
1814- }
1815- },
1816- [&](const auto &) {},
1817- },
1818- clause.u );
1751+ for (const parser::OmpArgument &arg : x.v .Arguments ().v ) {
1752+ if (auto *object{GetArgumentObject (arg)}) {
1753+ deviceConstructFound_ = true ;
1754+ CheckSymbolName (dirName.source , *object);
1755+ CheckVarIsNotPartOfAnotherVar (dirName.source , *object);
1756+ CheckThreadprivateOrDeclareTargetVar (*object);
1757+ }
1758+ }
18191759
1820- if ((toClauseFound || enterClauseFound) && !deviceTypeClauseFound) {
1821- deviceConstructFound_ = true ;
1822- }
1760+ if (!x.v .Clauses ().v .empty ()) {
1761+ const parser::OmpClause *enterClause =
1762+ FindClause (llvm::omp::Clause::OMPC_enter);
1763+ const parser::OmpClause *toClause = FindClause (llvm::omp::Clause::OMPC_to);
1764+ const parser::OmpClause *linkClause =
1765+ FindClause (llvm::omp::Clause::OMPC_link);
1766+ const parser::OmpClause *indirectClause =
1767+ FindClause (llvm::omp::Clause::OMPC_indirect);
1768+ if (!enterClause && !toClause && !linkClause) {
1769+ context_.Say (x.source ,
1770+ " If the DECLARE TARGET directive has a clause, it must contain at least one ENTER clause or LINK clause" _err_en_US);
1771+ }
1772+ if (indirectClause && !enterClause) {
1773+ context_.Say (x.source ,
1774+ " The INDIRECT clause cannot be used without the ENTER clause with the DECLARE TARGET directive." _err_en_US);
1775+ }
1776+ unsigned version{context_.langOptions ().OpenMPVersion };
1777+ if (toClause && version >= 52 ) {
1778+ context_.Warn (common::UsageWarning::OpenMPUsage, toClause->source ,
1779+ " The usage of TO clause on DECLARE TARGET directive has been deprecated. Use ENTER clause instead." _warn_en_US);
1780+ }
1781+ if (indirectClause) {
1782+ CheckAllowedClause (llvm::omp::Clause::OMPC_indirect);
18231783 }
18241784 }
1785+
1786+ bool toClauseFound{false }, deviceTypeClauseFound{false },
1787+ enterClauseFound{false };
1788+ for (const parser::OmpClause &clause : x.v .Clauses ().v ) {
1789+ common::visit (
1790+ common::visitors{
1791+ [&](const parser::OmpClause::To &toClause) {
1792+ toClauseFound = true ;
1793+ auto &objList{std::get<parser::OmpObjectList>(toClause.v .t )};
1794+ CheckSymbolNames (dirName.source , objList);
1795+ CheckVarIsNotPartOfAnotherVar (dirName.source , objList);
1796+ CheckThreadprivateOrDeclareTargetVar (objList);
1797+ },
1798+ [&](const parser::OmpClause::Link &linkClause) {
1799+ CheckSymbolNames (dirName.source , linkClause.v );
1800+ CheckVarIsNotPartOfAnotherVar (dirName.source , linkClause.v );
1801+ CheckThreadprivateOrDeclareTargetVar (linkClause.v );
1802+ },
1803+ [&](const parser::OmpClause::Enter &enterClause) {
1804+ enterClauseFound = true ;
1805+ auto &objList{std::get<parser::OmpObjectList>(enterClause.v .t )};
1806+ CheckSymbolNames (dirName.source , objList);
1807+ CheckVarIsNotPartOfAnotherVar (dirName.source , objList);
1808+ CheckThreadprivateOrDeclareTargetVar (objList);
1809+ },
1810+ [&](const parser::OmpClause::DeviceType &deviceTypeClause) {
1811+ deviceTypeClauseFound = true ;
1812+ if (deviceTypeClause.v .v !=
1813+ parser::OmpDeviceTypeClause::DeviceTypeDescription::Host) {
1814+ // Function / subroutine explicitly marked as runnable by the
1815+ // target device.
1816+ deviceConstructFound_ = true ;
1817+ }
1818+ },
1819+ [&](const auto &) {},
1820+ },
1821+ clause.u );
1822+
1823+ if ((toClauseFound || enterClauseFound) && !deviceTypeClauseFound) {
1824+ deviceConstructFound_ = true ;
1825+ }
1826+ }
1827+
18251828 dirContext_.pop_back ();
18261829}
18271830
0 commit comments