@@ -1073,19 +1073,62 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCollapseClause(
1073
1073
1074
1074
SemaOpenACC::SemaOpenACC (Sema &S) : SemaBase(S) {}
1075
1075
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)
1078
1080
: SemaRef(S), WasInsideComputeConstruct(S.InsideComputeConstruct),
1079
- DirKind(DK) {
1081
+ DirKind(DK), LoopRAII(SemaRef) {
1080
1082
// Compute constructs end up taking their 'loop'.
1081
1083
if (DirKind == OpenACCDirectiveKind::Parallel ||
1082
1084
DirKind == OpenACCDirectiveKind::Serial ||
1083
1085
DirKind == OpenACCDirectiveKind::Kernels) {
1084
1086
SemaRef.InsideComputeConstruct = true ;
1085
1087
SemaRef.ParentlessLoopConstructs .swap (ParentlessLoopConstructs);
1088
+ } else if (DirKind == OpenACCDirectiveKind::Loop) {
1089
+ SetCollapseInfoBeforeAssociatedStmt (UnInstClauses, Clauses);
1086
1090
}
1087
1091
}
1088
1092
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
+
1089
1132
SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII () {
1090
1133
SemaRef.InsideComputeConstruct = WasInsideComputeConstruct;
1091
1134
if (DirKind == OpenACCDirectiveKind::Parallel ||
@@ -1094,6 +1137,9 @@ SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
1094
1137
assert (SemaRef.ParentlessLoopConstructs .empty () &&
1095
1138
" Didn't consume loop construct list?" );
1096
1139
SemaRef.ParentlessLoopConstructs .swap (ParentlessLoopConstructs);
1140
+ } else if (DirKind == OpenACCDirectiveKind::Loop) {
1141
+ // Nothing really to do here, the LoopInConstruct should handle restorations
1142
+ // correctly.
1097
1143
}
1098
1144
}
1099
1145
@@ -1646,10 +1692,78 @@ ExprResult SemaOpenACC::CheckCollapseLoopCount(Expr *LoopCount) {
1646
1692
ConstantExpr::Create (getASTContext (), LoopCount, APValue{*ICE})};
1647
1693
}
1648
1694
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
+
1649
1749
bool SemaOpenACC::ActOnStartStmtDirective (OpenACCDirectiveKind K,
1650
1750
SourceLocation StartLoc) {
1651
1751
SemaRef.DiscardCleanupsInEvaluationContext ();
1652
1752
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
+
1653
1767
return diagnoseConstructAppertainment (*this , K, StartLoc, /* IsStmt=*/ true );
1654
1768
}
1655
1769
0 commit comments