@@ -1073,19 +1073,62 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCollapseClause(
10731073
10741074SemaOpenACC::SemaOpenACC (Sema &S) : SemaBase(S) {}
10751075
1076- SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII (SemaOpenACC &S,
1077- OpenACCDirectiveKind DK)
1076+ SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII (
1077+ SemaOpenACC &S, OpenACCDirectiveKind DK,
1078+ ArrayRef<const OpenACCClause *> UnInstClauses,
1079+ ArrayRef<OpenACCClause *> Clauses)
10781080 : SemaRef(S), WasInsideComputeConstruct(S.InsideComputeConstruct),
1079- DirKind(DK) {
1081+ DirKind(DK), LoopRAII(SemaRef) {
10801082 // Compute constructs end up taking their 'loop'.
10811083 if (DirKind == OpenACCDirectiveKind::Parallel ||
10821084 DirKind == OpenACCDirectiveKind::Serial ||
10831085 DirKind == OpenACCDirectiveKind::Kernels) {
10841086 SemaRef.InsideComputeConstruct = true ;
10851087 SemaRef.ParentlessLoopConstructs .swap (ParentlessLoopConstructs);
1088+ } else if (DirKind == OpenACCDirectiveKind::Loop) {
1089+ SetCollapseInfoBeforeAssociatedStmt (UnInstClauses, Clauses);
10861090 }
10871091}
10881092
1093+ void SemaOpenACC::AssociatedStmtRAII::SetCollapseInfoBeforeAssociatedStmt (
1094+ ArrayRef<const OpenACCClause *> UnInstClauses,
1095+ ArrayRef<OpenACCClause *> Clauses) {
1096+ // We make sure to take an optional list of uninstantiated clauses, so that
1097+ // we can check to make sure we don't 'double diagnose' in the event that
1098+ // the value of 'N' was not dependent in a template. We also ensure during
1099+ // Sema that there is only 1 collapse on each construct, so we can count on
1100+ // the fact that if both find a 'collapse', that they are the same one.
1101+ auto *CollapseClauseItr =
1102+ llvm::find_if (Clauses, llvm::IsaPred<OpenACCCollapseClause>);
1103+ auto *UnInstCollapseClauseItr =
1104+ llvm::find_if (UnInstClauses, llvm::IsaPred<OpenACCCollapseClause>);
1105+
1106+ if (Clauses.end () == CollapseClauseItr)
1107+ return ;
1108+
1109+ OpenACCCollapseClause *CollapseClause =
1110+ cast<OpenACCCollapseClause>(*CollapseClauseItr);
1111+
1112+ SemaRef.CollapseInfo .ActiveCollapse = CollapseClause;
1113+ Expr *LoopCount = CollapseClause->getLoopCount ();
1114+
1115+ // If the loop count is still instantiation dependent, setting the depth
1116+ // counter isn't necessary, so return here.
1117+ if (!LoopCount || LoopCount->isInstantiationDependent ())
1118+ return ;
1119+
1120+ // Suppress diagnostics if we've done a 'transform' where the previous version
1121+ // wasn't dependent, meaning we already diagnosed it.
1122+ if (UnInstCollapseClauseItr != UnInstClauses.end () &&
1123+ !cast<OpenACCCollapseClause>(*UnInstCollapseClauseItr)
1124+ ->getLoopCount ()
1125+ ->isInstantiationDependent ())
1126+ return ;
1127+
1128+ SemaRef.CollapseInfo .CurCollapseCount =
1129+ cast<ConstantExpr>(LoopCount)->getResultAsAPSInt ();
1130+ }
1131+
10891132SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII () {
10901133 SemaRef.InsideComputeConstruct = WasInsideComputeConstruct;
10911134 if (DirKind == OpenACCDirectiveKind::Parallel ||
@@ -1094,6 +1137,9 @@ SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
10941137 assert (SemaRef.ParentlessLoopConstructs .empty () &&
10951138 " Didn't consume loop construct list?" );
10961139 SemaRef.ParentlessLoopConstructs .swap (ParentlessLoopConstructs);
1140+ } else if (DirKind == OpenACCDirectiveKind::Loop) {
1141+ // Nothing really to do here, the LoopInConstruct should handle restorations
1142+ // correctly.
10971143 }
10981144}
10991145
@@ -1646,10 +1692,78 @@ ExprResult SemaOpenACC::CheckCollapseLoopCount(Expr *LoopCount) {
16461692 ConstantExpr::Create (getASTContext (), LoopCount, APValue{*ICE})};
16471693}
16481694
1695+ void SemaOpenACC::ActOnWhileStmt (SourceLocation WhileLoc) {
1696+ if (!getLangOpts ().OpenACC )
1697+ return ;
1698+
1699+ if (!CollapseInfo.TopLevelLoopSeen )
1700+ return ;
1701+
1702+ if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0 ) {
1703+ Diag (WhileLoc, diag::err_acc_invalid_in_collapse_loop) << /* while loop*/ 1 ;
1704+ assert (CollapseInfo.ActiveCollapse && " Collapse count without object?" );
1705+ Diag (CollapseInfo.ActiveCollapse ->getBeginLoc (),
1706+ diag::note_acc_collapse_clause_here);
1707+
1708+ // Remove the value so that we don't get cascading errors in the body. The
1709+ // caller RAII object will restore this.
1710+ CollapseInfo.CurCollapseCount = std::nullopt ;
1711+ }
1712+ }
1713+
1714+ void SemaOpenACC::ActOnDoStmt (SourceLocation DoLoc) {
1715+ if (!getLangOpts ().OpenACC )
1716+ return ;
1717+
1718+ if (!CollapseInfo.TopLevelLoopSeen )
1719+ return ;
1720+
1721+ if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0 ) {
1722+ Diag (DoLoc, diag::err_acc_invalid_in_collapse_loop) << /* do loop*/ 2 ;
1723+ assert (CollapseInfo.ActiveCollapse && " Collapse count without object?" );
1724+ Diag (CollapseInfo.ActiveCollapse ->getBeginLoc (),
1725+ diag::note_acc_collapse_clause_here);
1726+
1727+ // Remove the value so that we don't get cascading errors in the body. The
1728+ // caller RAII object will restore this.
1729+ CollapseInfo.CurCollapseCount = std::nullopt ;
1730+ }
1731+ }
1732+
1733+ void SemaOpenACC::ActOnForStmtBegin (SourceLocation ForLoc) {
1734+ if (!getLangOpts ().OpenACC )
1735+ return ;
1736+
1737+ // Enable the while/do-while checking.
1738+ CollapseInfo.TopLevelLoopSeen = true ;
1739+
1740+ if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0 )
1741+ --(*CollapseInfo.CurCollapseCount );
1742+ }
1743+
1744+ void SemaOpenACC::ActOnForStmtEnd (SourceLocation ForLoc, StmtResult Body) {
1745+ if (!getLangOpts ().OpenACC )
1746+ return ;
1747+ }
1748+
16491749bool SemaOpenACC::ActOnStartStmtDirective (OpenACCDirectiveKind K,
16501750 SourceLocation StartLoc) {
16511751 SemaRef.DiscardCleanupsInEvaluationContext ();
16521752 SemaRef.PopExpressionEvaluationContext ();
1753+
1754+ // OpenACC 3.3 2.9.1:
1755+ // Intervening code must not contain other OpenACC directives or calls to API
1756+ // routines.
1757+ //
1758+ // ALL constructs are ill-formed if there is an active 'collapse'
1759+ if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0 ) {
1760+ Diag (StartLoc, diag::err_acc_invalid_in_collapse_loop)
1761+ << /* OpenACC Construct*/ 0 << K;
1762+ assert (CollapseInfo.ActiveCollapse && " Collapse count without object?" );
1763+ Diag (CollapseInfo.ActiveCollapse ->getBeginLoc (),
1764+ diag::note_acc_collapse_clause_here);
1765+ }
1766+
16531767 return diagnoseConstructAppertainment (*this , K, StartLoc, /* IsStmt=*/ true );
16541768}
16551769
0 commit comments