1//===--- SemaOpenACC.cpp - Semantic Analysis for OpenACC constructs -------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8/// \file
9/// This file implements semantic analysis for OpenACC constructs, and things
10/// that are not clause specific.
11///
12//===----------------------------------------------------------------------===//
13
14#include "clang/Sema/SemaOpenACC.h"
15#include "clang/AST/ASTConsumer.h"
16#include "clang/AST/DeclOpenACC.h"
17#include "clang/AST/StmtOpenACC.h"
18#include "clang/Basic/DiagnosticSema.h"
19#include "clang/Basic/OpenACCKinds.h"
20#include "clang/Basic/SourceManager.h"
21#include "clang/Sema/Initialization.h"
22#include "clang/Sema/Scope.h"
23#include "clang/Sema/Sema.h"
24#include "llvm/ADT/StringExtras.h"
25#include "llvm/Support/Casting.h"
26
27using namespace clang;
28
29namespace {
30bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K,
31 SourceLocation StartLoc, bool IsStmt) {
32 switch (K) {
33 default:
34 case OpenACCDirectiveKind::Invalid:
35 // Nothing to do here, both invalid and unimplemented don't really need to
36 // do anything.
37 break;
38 case OpenACCDirectiveKind::Parallel:
39 case OpenACCDirectiveKind::ParallelLoop:
40 case OpenACCDirectiveKind::Serial:
41 case OpenACCDirectiveKind::SerialLoop:
42 case OpenACCDirectiveKind::Kernels:
43 case OpenACCDirectiveKind::KernelsLoop:
44 case OpenACCDirectiveKind::Loop:
45 case OpenACCDirectiveKind::Data:
46 case OpenACCDirectiveKind::EnterData:
47 case OpenACCDirectiveKind::ExitData:
48 case OpenACCDirectiveKind::HostData:
49 case OpenACCDirectiveKind::Wait:
50 case OpenACCDirectiveKind::Update:
51 case OpenACCDirectiveKind::Init:
52 case OpenACCDirectiveKind::Shutdown:
53 case OpenACCDirectiveKind::Cache:
54 case OpenACCDirectiveKind::Atomic:
55 if (!IsStmt)
56 return S.Diag(Loc: StartLoc, DiagID: diag::err_acc_construct_appertainment) << K;
57 break;
58 }
59 return false;
60}
61
62void CollectActiveReductionClauses(
63 llvm::SmallVector<OpenACCReductionClause *> &ActiveClauses,
64 ArrayRef<OpenACCClause *> CurClauses) {
65 for (auto *CurClause : CurClauses) {
66 if (auto *RedClause = dyn_cast<OpenACCReductionClause>(Val: CurClause);
67 RedClause && !RedClause->getVarList().empty())
68 ActiveClauses.push_back(Elt: RedClause);
69 }
70}
71
72// Depth needs to be preserved for all associated statements that aren't
73// supposed to modify the compute/combined/loop construct information.
74bool PreserveLoopRAIIDepthInAssociatedStmtRAII(OpenACCDirectiveKind DK) {
75 switch (DK) {
76 case OpenACCDirectiveKind::Parallel:
77 case OpenACCDirectiveKind::ParallelLoop:
78 case OpenACCDirectiveKind::Serial:
79 case OpenACCDirectiveKind::SerialLoop:
80 case OpenACCDirectiveKind::Kernels:
81 case OpenACCDirectiveKind::KernelsLoop:
82 case OpenACCDirectiveKind::Loop:
83 return false;
84 case OpenACCDirectiveKind::Data:
85 case OpenACCDirectiveKind::HostData:
86 case OpenACCDirectiveKind::Atomic:
87 return true;
88 case OpenACCDirectiveKind::Cache:
89 case OpenACCDirectiveKind::Routine:
90 case OpenACCDirectiveKind::Declare:
91 case OpenACCDirectiveKind::EnterData:
92 case OpenACCDirectiveKind::ExitData:
93 case OpenACCDirectiveKind::Wait:
94 case OpenACCDirectiveKind::Init:
95 case OpenACCDirectiveKind::Shutdown:
96 case OpenACCDirectiveKind::Set:
97 case OpenACCDirectiveKind::Update:
98 llvm_unreachable("Doesn't have an associated stmt");
99 case OpenACCDirectiveKind::Invalid:
100 llvm_unreachable("Unhandled directive kind?");
101 }
102 llvm_unreachable("Unhandled directive kind?");
103}
104
105} // namespace
106
107SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {}
108
109SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII(
110 SemaOpenACC &S, OpenACCDirectiveKind DK, SourceLocation DirLoc,
111 ArrayRef<const OpenACCClause *> UnInstClauses,
112 ArrayRef<OpenACCClause *> Clauses)
113 : SemaRef(S), OldActiveComputeConstructInfo(S.ActiveComputeConstructInfo),
114 DirKind(DK), OldLoopGangClauseOnKernel(S.LoopGangClauseOnKernel),
115 OldLoopWorkerClauseLoc(S.LoopWorkerClauseLoc),
116 OldLoopVectorClauseLoc(S.LoopVectorClauseLoc),
117 OldLoopWithoutSeqInfo(S.LoopWithoutSeqInfo),
118 ActiveReductionClauses(S.ActiveReductionClauses),
119 LoopRAII(SemaRef, PreserveLoopRAIIDepthInAssociatedStmtRAII(DK: DirKind)) {
120
121 // Compute constructs end up taking their 'loop'.
122 if (DirKind == OpenACCDirectiveKind::Parallel ||
123 DirKind == OpenACCDirectiveKind::Serial ||
124 DirKind == OpenACCDirectiveKind::Kernels) {
125 CollectActiveReductionClauses(ActiveClauses&: S.ActiveReductionClauses, CurClauses: Clauses);
126 SemaRef.ActiveComputeConstructInfo.Kind = DirKind;
127 SemaRef.ActiveComputeConstructInfo.Clauses = Clauses;
128
129 // OpenACC 3.3 2.9.2: When the parent compute construct is a kernels
130 // construct, the gang clause behaves as follows. ... The region of a loop
131 // with a gang clause may not contain another loop with a gang clause unless
132 // within a nested compute region.
133 //
134 // Implement the 'unless within a nested compute region' part.
135 SemaRef.LoopGangClauseOnKernel = {};
136 SemaRef.LoopWorkerClauseLoc = {};
137 SemaRef.LoopVectorClauseLoc = {};
138 SemaRef.LoopWithoutSeqInfo = {};
139 } else if (DirKind == OpenACCDirectiveKind::ParallelLoop ||
140 DirKind == OpenACCDirectiveKind::SerialLoop ||
141 DirKind == OpenACCDirectiveKind::KernelsLoop) {
142 SemaRef.ActiveComputeConstructInfo.Kind = DirKind;
143 SemaRef.ActiveComputeConstructInfo.Clauses = Clauses;
144
145 CollectActiveReductionClauses(ActiveClauses&: S.ActiveReductionClauses, CurClauses: Clauses);
146 SetCollapseInfoBeforeAssociatedStmt(UnInstClauses, Clauses);
147 SetTileInfoBeforeAssociatedStmt(UnInstClauses, Clauses);
148
149 SemaRef.LoopGangClauseOnKernel = {};
150 SemaRef.LoopWorkerClauseLoc = {};
151 SemaRef.LoopVectorClauseLoc = {};
152
153 // Set the active 'loop' location if there isn't a 'seq' on it, so we can
154 // diagnose the for loops.
155 SemaRef.LoopWithoutSeqInfo = {};
156 if (Clauses.end() ==
157 llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCSeqClause>))
158 SemaRef.LoopWithoutSeqInfo = {.Kind: DirKind, .Loc: DirLoc};
159
160 // OpenACC 3.3 2.9.2: When the parent compute construct is a kernels
161 // construct, the gang clause behaves as follows. ... The region of a loop
162 // with a gang clause may not contain another loop with a gang clause unless
163 // within a nested compute region.
164 //
165 // We don't bother doing this when this is a template instantiation, as
166 // there is no reason to do these checks: the existance of a
167 // gang/kernels/etc cannot be dependent.
168 if (DirKind == OpenACCDirectiveKind::KernelsLoop && UnInstClauses.empty()) {
169 // This handles the 'outer loop' part of this.
170 auto *Itr = llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCGangClause>);
171 if (Itr != Clauses.end())
172 SemaRef.LoopGangClauseOnKernel = {.Loc: (*Itr)->getBeginLoc(), .DirKind: DirKind};
173 }
174
175 if (UnInstClauses.empty()) {
176 auto *Itr = llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCWorkerClause>);
177 if (Itr != Clauses.end())
178 SemaRef.LoopWorkerClauseLoc = (*Itr)->getBeginLoc();
179
180 auto *Itr2 = llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCVectorClause>);
181 if (Itr2 != Clauses.end())
182 SemaRef.LoopVectorClauseLoc = (*Itr2)->getBeginLoc();
183 }
184 } else if (DirKind == OpenACCDirectiveKind::Loop) {
185 CollectActiveReductionClauses(ActiveClauses&: S.ActiveReductionClauses, CurClauses: Clauses);
186 SetCollapseInfoBeforeAssociatedStmt(UnInstClauses, Clauses);
187 SetTileInfoBeforeAssociatedStmt(UnInstClauses, Clauses);
188
189 // Set the active 'loop' location if there isn't a 'seq' on it, so we can
190 // diagnose the for loops.
191 SemaRef.LoopWithoutSeqInfo = {};
192 if (Clauses.end() ==
193 llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCSeqClause>))
194 SemaRef.LoopWithoutSeqInfo = {.Kind: DirKind, .Loc: DirLoc};
195
196 // OpenACC 3.3 2.9.2: When the parent compute construct is a kernels
197 // construct, the gang clause behaves as follows. ... The region of a loop
198 // with a gang clause may not contain another loop with a gang clause unless
199 // within a nested compute region.
200 //
201 // We don't bother doing this when this is a template instantiation, as
202 // there is no reason to do these checks: the existance of a
203 // gang/kernels/etc cannot be dependent.
204 if (SemaRef.getActiveComputeConstructInfo().Kind ==
205 OpenACCDirectiveKind::Kernels &&
206 UnInstClauses.empty()) {
207 // This handles the 'outer loop' part of this.
208 auto *Itr = llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCGangClause>);
209 if (Itr != Clauses.end())
210 SemaRef.LoopGangClauseOnKernel = {.Loc: (*Itr)->getBeginLoc(),
211 .DirKind: OpenACCDirectiveKind::Kernels};
212 }
213
214 if (UnInstClauses.empty()) {
215 auto *Itr = llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCWorkerClause>);
216 if (Itr != Clauses.end())
217 SemaRef.LoopWorkerClauseLoc = (*Itr)->getBeginLoc();
218
219 auto *Itr2 = llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCVectorClause>);
220 if (Itr2 != Clauses.end())
221 SemaRef.LoopVectorClauseLoc = (*Itr2)->getBeginLoc();
222 }
223 }
224}
225
226namespace {
227// Given two collapse clauses, and the uninstanted version of the new one,
228// return the 'best' one for the purposes of setting the collapse checking
229// values.
230const OpenACCCollapseClause *
231getBestCollapseCandidate(const OpenACCCollapseClause *Old,
232 const OpenACCCollapseClause *New,
233 const OpenACCCollapseClause *UnInstNew) {
234 // If the loop count is nullptr, it is because instantiation failed, so this
235 // can't be the best one.
236 if (!New->getLoopCount())
237 return Old;
238
239 // If the loop-count had an error, than 'new' isn't a candidate.
240 if (!New->getLoopCount())
241 return Old;
242
243 // Don't consider uninstantiated ones, since we can't really check these.
244 if (New->getLoopCount()->isInstantiationDependent())
245 return Old;
246
247 // If this is an instantiation, and the old version wasn't instantation
248 // dependent, than nothing has changed and we've already done a diagnostic
249 // based on this one, so don't consider it.
250 if (UnInstNew && !UnInstNew->getLoopCount()->isInstantiationDependent())
251 return Old;
252
253 // New is now a valid candidate, so if there isn't an old one at this point,
254 // New is the only valid one.
255 if (!Old)
256 return New;
257
258 // If the 'New' expression has a larger value than 'Old', then it is the new
259 // best candidate.
260 if (cast<ConstantExpr>(Val: Old->getLoopCount())->getResultAsAPSInt() <
261 cast<ConstantExpr>(Val: New->getLoopCount())->getResultAsAPSInt())
262 return New;
263
264 return Old;
265}
266} // namespace
267
268void SemaOpenACC::AssociatedStmtRAII::SetCollapseInfoBeforeAssociatedStmt(
269 ArrayRef<const OpenACCClause *> UnInstClauses,
270 ArrayRef<OpenACCClause *> Clauses) {
271
272 // Reset this checking for loops that aren't covered in a RAII object.
273 SemaRef.LoopInfo.CurLevelHasLoopAlready = false;
274 SemaRef.CollapseInfo.CollapseDepthSatisfied = true;
275 SemaRef.CollapseInfo.CurCollapseCount = 0;
276 SemaRef.TileInfo.TileDepthSatisfied = true;
277
278 // We make sure to take an optional list of uninstantiated clauses, so that
279 // we can check to make sure we don't 'double diagnose' in the event that
280 // the value of 'N' was not dependent in a template. Since we cannot count on
281 // there only being a single collapse clause, we count on the order to make
282 // sure get the matching ones, and we count on TreeTransform not removing
283 // these, even if loop-count instantiation failed. We can check the
284 // non-dependent ones right away, and realize that subsequent instantiation
285 // can only make it more specific.
286
287 auto *UnInstClauseItr =
288 llvm::find_if(Range&: UnInstClauses, P: llvm::IsaPred<OpenACCCollapseClause>);
289 auto *ClauseItr =
290 llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCCollapseClause>);
291 const OpenACCCollapseClause *FoundClause = nullptr;
292
293 // Loop through the list of Collapse clauses and find the one that:
294 // 1- Has a non-dependent, non-null loop count (null means error, likely
295 // during instantiation).
296 // 2- If UnInstClauses isn't empty, its corresponding
297 // loop count was dependent.
298 // 3- Has the largest 'loop count' of all.
299 while (ClauseItr != Clauses.end()) {
300 const OpenACCCollapseClause *CurClause =
301 cast<OpenACCCollapseClause>(Val: *ClauseItr);
302 const OpenACCCollapseClause *UnInstCurClause =
303 UnInstClauseItr == UnInstClauses.end()
304 ? nullptr
305 : cast<OpenACCCollapseClause>(Val: *UnInstClauseItr);
306
307 FoundClause =
308 getBestCollapseCandidate(Old: FoundClause, New: CurClause, UnInstNew: UnInstCurClause);
309
310 UnInstClauseItr =
311 UnInstClauseItr == UnInstClauses.end()
312 ? UnInstClauseItr
313 : std::find_if(first: std::next(x: UnInstClauseItr), last: UnInstClauses.end(),
314 pred: llvm::IsaPred<OpenACCCollapseClause>);
315 ClauseItr = std::find_if(first: std::next(x: ClauseItr), last: Clauses.end(),
316 pred: llvm::IsaPred<OpenACCCollapseClause>);
317 }
318
319 if (!FoundClause)
320 return;
321
322 SemaRef.CollapseInfo.ActiveCollapse = FoundClause;
323 SemaRef.CollapseInfo.CollapseDepthSatisfied = false;
324 SemaRef.CollapseInfo.CurCollapseCount =
325 cast<ConstantExpr>(Val: FoundClause->getLoopCount())->getResultAsAPSInt();
326 SemaRef.CollapseInfo.DirectiveKind = DirKind;
327}
328
329void SemaOpenACC::AssociatedStmtRAII::SetTileInfoBeforeAssociatedStmt(
330 ArrayRef<const OpenACCClause *> UnInstClauses,
331 ArrayRef<OpenACCClause *> Clauses) {
332 // We don't diagnose if this is during instantiation, since the only thing we
333 // care about is the number of arguments, which we can figure out without
334 // instantiation, so we don't want to double-diagnose.
335 if (UnInstClauses.size() > 0)
336 return;
337 auto *TileClauseItr =
338 llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCTileClause>);
339
340 if (Clauses.end() == TileClauseItr)
341 return;
342
343 OpenACCTileClause *TileClause = cast<OpenACCTileClause>(Val: *TileClauseItr);
344
345 // Multiple tile clauses are allowed, so ensure that we use the one with the
346 // largest 'tile count'.
347 while (Clauses.end() !=
348 (TileClauseItr = std::find_if(first: std::next(x: TileClauseItr), last: Clauses.end(),
349 pred: llvm::IsaPred<OpenACCTileClause>))) {
350 OpenACCTileClause *NewClause = cast<OpenACCTileClause>(Val: *TileClauseItr);
351 if (NewClause->getSizeExprs().size() > TileClause->getSizeExprs().size())
352 TileClause = NewClause;
353 }
354
355 SemaRef.TileInfo.ActiveTile = TileClause;
356 SemaRef.TileInfo.TileDepthSatisfied = false;
357 SemaRef.TileInfo.CurTileCount =
358 static_cast<unsigned>(TileClause->getSizeExprs().size());
359 SemaRef.TileInfo.DirectiveKind = DirKind;
360}
361
362SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
363 if (DirKind == OpenACCDirectiveKind::Parallel ||
364 DirKind == OpenACCDirectiveKind::Serial ||
365 DirKind == OpenACCDirectiveKind::Kernels ||
366 DirKind == OpenACCDirectiveKind::Loop ||
367 DirKind == OpenACCDirectiveKind::ParallelLoop ||
368 DirKind == OpenACCDirectiveKind::SerialLoop ||
369 DirKind == OpenACCDirectiveKind::KernelsLoop) {
370 SemaRef.ActiveComputeConstructInfo = OldActiveComputeConstructInfo;
371 SemaRef.LoopGangClauseOnKernel = OldLoopGangClauseOnKernel;
372 SemaRef.LoopWorkerClauseLoc = OldLoopWorkerClauseLoc;
373 SemaRef.LoopVectorClauseLoc = OldLoopVectorClauseLoc;
374 SemaRef.LoopWithoutSeqInfo = OldLoopWithoutSeqInfo;
375 SemaRef.ActiveReductionClauses.swap(RHS&: ActiveReductionClauses);
376 } else if (DirKind == OpenACCDirectiveKind::Data ||
377 DirKind == OpenACCDirectiveKind::HostData) {
378 // Intentionally doesn't reset the Loop, Compute Construct, or reduction
379 // effects.
380 }
381}
382
383void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K,
384 SourceLocation DirLoc) {
385 // Start an evaluation context to parse the clause arguments on.
386 SemaRef.PushExpressionEvaluationContext(
387 NewContext: Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
388
389 // There is nothing do do here as all we have at this point is the name of the
390 // construct itself.
391}
392
393ExprResult SemaOpenACC::ActOnIntExpr(OpenACCDirectiveKind DK,
394 OpenACCClauseKind CK, SourceLocation Loc,
395 Expr *IntExpr) {
396
397 assert(((DK != OpenACCDirectiveKind::Invalid &&
398 CK == OpenACCClauseKind::Invalid) ||
399 (DK == OpenACCDirectiveKind::Invalid &&
400 CK != OpenACCClauseKind::Invalid) ||
401 (DK == OpenACCDirectiveKind::Invalid &&
402 CK == OpenACCClauseKind::Invalid)) &&
403 "Only one of directive or clause kind should be provided");
404
405 class IntExprConverter : public Sema::ICEConvertDiagnoser {
406 OpenACCDirectiveKind DirectiveKind;
407 OpenACCClauseKind ClauseKind;
408 Expr *IntExpr;
409
410 // gets the index into the diagnostics so we can use this for clauses,
411 // directives, and sub array.s
412 unsigned getDiagKind() const {
413 if (ClauseKind != OpenACCClauseKind::Invalid)
414 return 0;
415 if (DirectiveKind != OpenACCDirectiveKind::Invalid)
416 return 1;
417 return 2;
418 }
419
420 public:
421 IntExprConverter(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
422 Expr *IntExpr)
423 : ICEConvertDiagnoser(/*AllowScopedEnumerations=*/false,
424 /*Suppress=*/false,
425 /*SuppressConversion=*/true),
426 DirectiveKind(DK), ClauseKind(CK), IntExpr(IntExpr) {}
427
428 bool match(QualType T) override {
429 // OpenACC spec just calls this 'integer expression' as having an
430 // 'integer type', so fall back on C99's 'integer type'.
431 return T->isIntegerType();
432 }
433 SemaBase::SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
434 QualType T) override {
435 return S.Diag(Loc, DiagID: diag::err_acc_int_expr_requires_integer)
436 << getDiagKind() << ClauseKind << DirectiveKind << T;
437 }
438
439 SemaBase::SemaDiagnosticBuilder
440 diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) override {
441 return S.Diag(Loc, DiagID: diag::err_acc_int_expr_incomplete_class_type)
442 << T << IntExpr->getSourceRange();
443 }
444
445 SemaBase::SemaDiagnosticBuilder
446 diagnoseExplicitConv(Sema &S, SourceLocation Loc, QualType T,
447 QualType ConvTy) override {
448 return S.Diag(Loc, DiagID: diag::err_acc_int_expr_explicit_conversion)
449 << T << ConvTy;
450 }
451
452 SemaBase::SemaDiagnosticBuilder noteExplicitConv(Sema &S,
453 CXXConversionDecl *Conv,
454 QualType ConvTy) override {
455 return S.Diag(Loc: Conv->getLocation(), DiagID: diag::note_acc_int_expr_conversion)
456 << ConvTy->isEnumeralType() << ConvTy;
457 }
458
459 SemaBase::SemaDiagnosticBuilder
460 diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) override {
461 return S.Diag(Loc, DiagID: diag::err_acc_int_expr_multiple_conversions) << T;
462 }
463
464 SemaBase::SemaDiagnosticBuilder
465 noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override {
466 return S.Diag(Loc: Conv->getLocation(), DiagID: diag::note_acc_int_expr_conversion)
467 << ConvTy->isEnumeralType() << ConvTy;
468 }
469
470 SemaBase::SemaDiagnosticBuilder
471 diagnoseConversion(Sema &S, SourceLocation Loc, QualType T,
472 QualType ConvTy) override {
473 llvm_unreachable("conversion functions are permitted");
474 }
475 } IntExprDiagnoser(DK, CK, IntExpr);
476
477 if (!IntExpr)
478 return ExprError();
479
480 ExprResult IntExprResult = SemaRef.PerformContextualImplicitConversion(
481 Loc, FromE: IntExpr, Converter&: IntExprDiagnoser);
482 if (IntExprResult.isInvalid())
483 return ExprError();
484
485 IntExpr = IntExprResult.get();
486 if (!IntExpr->isTypeDependent() && !IntExpr->getType()->isIntegerType())
487 return ExprError();
488
489 // TODO OpenACC: Do we want to perform usual unary conversions here? When
490 // doing codegen we might find that is necessary, but skip it for now.
491 return IntExpr;
492}
493
494bool SemaOpenACC::CheckVarIsPointerType(OpenACCClauseKind ClauseKind,
495 Expr *VarExpr) {
496 // We already know that VarExpr is a proper reference to a variable, so we
497 // should be able to just take the type of the expression to get the type of
498 // the referenced variable.
499
500 // We've already seen an error, don't diagnose anything else.
501 if (!VarExpr || VarExpr->containsErrors())
502 return false;
503
504 if (isa<ArraySectionExpr>(Val: VarExpr->IgnoreParenImpCasts()) ||
505 VarExpr->hasPlaceholderType(K: BuiltinType::ArraySection)) {
506 Diag(Loc: VarExpr->getExprLoc(), DiagID: diag::err_array_section_use) << /*OpenACC=*/0;
507 Diag(Loc: VarExpr->getExprLoc(), DiagID: diag::note_acc_expected_pointer_var);
508 return true;
509 }
510
511 QualType Ty = VarExpr->getType();
512 Ty = Ty.getNonReferenceType().getUnqualifiedType();
513
514 // Nothing we can do if this is a dependent type.
515 if (Ty->isDependentType())
516 return false;
517
518 if (!Ty->isPointerType())
519 return Diag(Loc: VarExpr->getExprLoc(), DiagID: diag::err_acc_var_not_pointer_type)
520 << ClauseKind << Ty;
521 return false;
522}
523
524void SemaOpenACC::ActOnStartParseVar(OpenACCDirectiveKind DK,
525 OpenACCClauseKind CK) {
526 if (DK == OpenACCDirectiveKind::Cache) {
527 CacheInfo.ParsingCacheVarList = true;
528 CacheInfo.IsInvalidCacheRef = false;
529 }
530}
531
532void SemaOpenACC::ActOnInvalidParseVar() {
533 CacheInfo.ParsingCacheVarList = false;
534 CacheInfo.IsInvalidCacheRef = false;
535 // This makes sure that we properly mark variables 'used' that are referenced.
536 SemaRef.CleanupVarDeclMarking();
537}
538
539ExprResult SemaOpenACC::ActOnCacheVar(Expr *VarExpr) {
540 Expr *CurVarExpr = VarExpr->IgnoreParenImpCasts();
541 // Clear this here, so we can do the returns based on the invalid cache ref
542 // here. Note all return statements in this function must return ExprError if
543 // IsInvalidCacheRef. However, instead of doing an 'early return' in that
544 // case, we can let the rest of the diagnostics happen, as the invalid decl
545 // ref is a warning.
546 bool WasParsingInvalidCacheRef =
547 CacheInfo.ParsingCacheVarList && CacheInfo.IsInvalidCacheRef;
548 CacheInfo.ParsingCacheVarList = false;
549 CacheInfo.IsInvalidCacheRef = false;
550
551 if (!isa<ArraySectionExpr, ArraySubscriptExpr>(Val: CurVarExpr)) {
552 Diag(Loc: VarExpr->getExprLoc(), DiagID: diag::err_acc_not_a_var_ref_cache);
553 return ExprError();
554 }
555
556 // It isn't clear what 'simple array element or simple subarray' means, so we
557 // will just allow arbitrary depth.
558 while (isa<ArraySectionExpr, ArraySubscriptExpr>(Val: CurVarExpr)) {
559 if (auto *SubScrpt = dyn_cast<ArraySubscriptExpr>(Val: CurVarExpr))
560 CurVarExpr = SubScrpt->getBase()->IgnoreParenImpCasts();
561 else
562 CurVarExpr =
563 cast<ArraySectionExpr>(Val: CurVarExpr)->getBase()->IgnoreParenImpCasts();
564 }
565
566 // References to a VarDecl are fine.
567 if (const auto *DRE = dyn_cast<DeclRefExpr>(Val: CurVarExpr)) {
568 if (isa<VarDecl, NonTypeTemplateParmDecl>(
569 Val: DRE->getFoundDecl()->getCanonicalDecl()))
570 return WasParsingInvalidCacheRef ? ExprEmpty() : VarExpr;
571 }
572
573 if (const auto *ME = dyn_cast<MemberExpr>(Val: CurVarExpr)) {
574 if (isa<FieldDecl>(Val: ME->getMemberDecl()->getCanonicalDecl())) {
575 return WasParsingInvalidCacheRef ? ExprEmpty() : VarExpr;
576 }
577 }
578
579 // Nothing really we can do here, as these are dependent. So just return they
580 // are valid.
581 if (isa<DependentScopeDeclRefExpr, CXXDependentScopeMemberExpr>(Val: CurVarExpr))
582 return WasParsingInvalidCacheRef ? ExprEmpty() : VarExpr;
583
584 // There isn't really anything we can do in the case of a recovery expr, so
585 // skip the diagnostic rather than produce a confusing diagnostic.
586 if (isa<RecoveryExpr>(Val: CurVarExpr))
587 return ExprError();
588
589 Diag(Loc: VarExpr->getExprLoc(), DiagID: diag::err_acc_not_a_var_ref_cache);
590 return ExprError();
591}
592
593void SemaOpenACC::CheckDeclReference(SourceLocation Loc, Expr *E, Decl *D) {
594 if (!getLangOpts().OpenACC || !CacheInfo.ParsingCacheVarList || !D ||
595 D->isInvalidDecl())
596 return;
597 // A 'cache' variable reference MUST be declared before the 'acc.loop' we
598 // generate in codegen, so we have to mark it invalid here in some way. We do
599 // so in a bit of a convoluted way as there is no good way to put this into
600 // the AST, so we store it in SemaOpenACC State. We can check the Scope
601 // during parsing to make sure there is a 'loop' before the decl is
602 // declared(and skip during instantiation).
603 // We only diagnose this as a warning, as this isn't required by the standard
604 // (unless you take a VERY awkward reading of some awkward prose).
605
606 Scope *CurScope = SemaRef.getCurScope();
607
608 // if we are at TU level, we are either doing some EXTRA wacky, or are in a
609 // template instantiation, so just give up.
610 if (CurScope->getDepth() == 0)
611 return;
612
613 while (CurScope) {
614 // If we run into a loop construct scope, than this is 'correct' in that the
615 // declaration is outside of the loop.
616 if (CurScope->isOpenACCLoopConstructScope())
617 return;
618
619 if (CurScope->isDeclScope(D)) {
620 Diag(Loc, DiagID: diag::warn_acc_cache_var_not_outside_loop);
621
622 CacheInfo.IsInvalidCacheRef = true;
623 }
624
625 CurScope = CurScope->getParent();
626 }
627 // If we don't find the decl at all, we assume that it must be outside of the
628 // loop (or we aren't in a loop!) so skip the diagnostic.
629}
630
631namespace {
632// Check whether the type of the thing we are referencing is OK for things like
633// private, firstprivate, and reduction, which require certain operators to be
634// available.
635ExprResult CheckVarType(SemaOpenACC &S, OpenACCClauseKind CK, Expr *VarExpr,
636 SourceLocation InnerLoc, QualType InnerTy) {
637 // There is nothing to do here, only these three have these sorts of
638 // restrictions.
639 if (CK != OpenACCClauseKind::Private &&
640 CK != OpenACCClauseKind::FirstPrivate &&
641 CK != OpenACCClauseKind::Reduction)
642 return VarExpr;
643
644 // We can't test this if it isn't here, or if the type isn't clear yet.
645 if (InnerTy.isNull() || InnerTy->isDependentType())
646 return VarExpr;
647
648 InnerTy = InnerTy.getUnqualifiedType();
649 if (auto *RefTy = InnerTy->getAs<ReferenceType>())
650 InnerTy = RefTy->getPointeeType();
651
652 if (auto *ArrTy = InnerTy->getAsArrayTypeUnsafe()) {
653 // Non constant arrays decay to 'pointer', so warn and return that we're
654 // successful.
655 if (!ArrTy->isConstantArrayType()) {
656 S.Diag(Loc: InnerLoc, DiagID: clang::diag::warn_acc_var_referenced_non_const_array)
657 << InnerTy << CK;
658 return VarExpr;
659 }
660
661 return CheckVarType(S, CK, VarExpr, InnerLoc, InnerTy: ArrTy->getElementType());
662 }
663
664 if (S.SemaRef.RequireCompleteType(Loc: InnerLoc, T: InnerTy,
665 Kind: Sema::CompleteTypeKind::Normal,
666 DiagID: diag::err_incomplete_type))
667 return ExprError();
668
669 auto *RD = InnerTy->getAsCXXRecordDecl();
670
671 // if this isn't a C++ record decl, we can create/copy/destroy this thing at
672 // will without problem, so this is a success.
673 if (!RD)
674 return VarExpr;
675
676 if (CK == OpenACCClauseKind::Private) {
677 bool HasNonDeletedDefaultCtor =
678 llvm::find_if(Range: RD->ctors(), P: [](const CXXConstructorDecl *CD) {
679 return CD->isDefaultConstructor() && !CD->isDeleted();
680 }) != RD->ctors().end();
681 if (!HasNonDeletedDefaultCtor && !RD->needsImplicitDefaultConstructor()) {
682 S.Diag(Loc: InnerLoc, DiagID: clang::diag::warn_acc_var_referenced_lacks_op)
683 << InnerTy << CK << clang::diag::AccVarReferencedReason::DefCtor;
684 return ExprError();
685 }
686 } else if (CK == OpenACCClauseKind::FirstPrivate) {
687 if (!RD->hasSimpleCopyConstructor()) {
688 Sema::SpecialMemberOverloadResult SMOR = S.SemaRef.LookupSpecialMember(
689 D: RD, SM: CXXSpecialMemberKind::CopyConstructor, /*ConstArg=*/true,
690 /*VolatileArg=*/false, /*RValueThis=*/false, /*ConstThis=*/false,
691 /*VolatileThis=*/false);
692
693 if (SMOR.getKind() != Sema::SpecialMemberOverloadResult::Success ||
694 SMOR.getMethod()->isDeleted()) {
695 S.Diag(Loc: InnerLoc, DiagID: clang::diag::warn_acc_var_referenced_lacks_op)
696 << InnerTy << CK << clang::diag::AccVarReferencedReason::CopyCtor;
697 return ExprError();
698 }
699 }
700 } else if (CK == OpenACCClauseKind::Reduction) {
701 // TODO: Reduction needs to be an aggregate, which gets checked later, so
702 // construction here isn't a problem. However, we need to make sure that we
703 // can compare it correctly still.
704 }
705
706 // All 3 things need to make sure they have a dtor.
707 bool DestructorDeleted =
708 RD->getDestructor() && RD->getDestructor()->isDeleted();
709 if (DestructorDeleted && !RD->needsImplicitDestructor()) {
710 S.Diag(Loc: InnerLoc, DiagID: clang::diag::warn_acc_var_referenced_lacks_op)
711 << InnerTy << CK << clang::diag::AccVarReferencedReason::Dtor;
712 return ExprError();
713 }
714 return VarExpr;
715}
716
717ExprResult CheckVarType(SemaOpenACC &S, OpenACCClauseKind CK, Expr *VarExpr,
718 Expr *InnerExpr) {
719 if (!InnerExpr)
720 return VarExpr;
721 return CheckVarType(S, CK, VarExpr, InnerLoc: InnerExpr->getBeginLoc(),
722 InnerTy: InnerExpr->getType());
723}
724} // namespace
725
726ExprResult SemaOpenACC::ActOnVar(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
727 Expr *VarExpr) {
728 // This makes sure that we properly mark variables 'used' that are referenced.
729 SemaRef.CleanupVarDeclMarking();
730
731 // This has unique enough restrictions that we should split it to a separate
732 // function.
733 if (DK == OpenACCDirectiveKind::Cache)
734 return ActOnCacheVar(VarExpr);
735
736 Expr *CurVarExpr = VarExpr->IgnoreParenImpCasts();
737
738 // 'use_device' doesn't allow array subscript or array sections.
739 // OpenACC3.3 2.8:
740 // A 'var' in a 'use_device' clause must be the name of a variable or array.
741 // OpenACC3.3 2.13:
742 // A 'var' in a 'declare' directive must be a variable or array name.
743 if ((CK == OpenACCClauseKind::UseDevice ||
744 DK == OpenACCDirectiveKind::Declare)) {
745 if (isa<ArraySubscriptExpr>(Val: CurVarExpr)) {
746 Diag(Loc: VarExpr->getExprLoc(),
747 DiagID: diag::err_acc_not_a_var_ref_use_device_declare)
748 << (DK == OpenACCDirectiveKind::Declare);
749 return ExprError();
750 }
751 // As an extension, we allow 'array sections'/'sub-arrays' here, as that is
752 // effectively defining an array, and are in common use.
753 if (isa<ArraySectionExpr>(Val: CurVarExpr))
754 Diag(Loc: VarExpr->getExprLoc(),
755 DiagID: diag::ext_acc_array_section_use_device_declare)
756 << (DK == OpenACCDirectiveKind::Declare);
757 }
758
759 // Sub-arrays/subscript-exprs are fine as long as the base is a
760 // VarExpr/MemberExpr. So strip all of those off.
761 while (isa<ArraySectionExpr, ArraySubscriptExpr>(Val: CurVarExpr)) {
762 if (auto *SubScrpt = dyn_cast<ArraySubscriptExpr>(Val: CurVarExpr))
763 CurVarExpr = SubScrpt->getBase()->IgnoreParenImpCasts();
764 else
765 CurVarExpr =
766 cast<ArraySectionExpr>(Val: CurVarExpr)->getBase()->IgnoreParenImpCasts();
767 }
768
769 // References to a VarDecl are fine.
770 if (const auto *DRE = dyn_cast<DeclRefExpr>(Val: CurVarExpr)) {
771 if (isa<VarDecl, NonTypeTemplateParmDecl>(
772 Val: DRE->getFoundDecl()->getCanonicalDecl()))
773 return CheckVarType(S&: *this, CK, VarExpr, InnerExpr: CurVarExpr);
774 }
775
776 // If CK is a Reduction, this special cases for OpenACC3.3 2.5.15: "A var in a
777 // reduction clause must be a scalar variable name, an aggregate variable
778 // name, an array element, or a subarray.
779 // If CK is a 'use_device', this also isn't valid, as it isn't the name of a
780 // variable or array, if not done as a member expr.
781 // A MemberExpr that references a Field is valid for other clauses.
782 if (const auto *ME = dyn_cast<MemberExpr>(Val: CurVarExpr)) {
783 if (isa<FieldDecl>(Val: ME->getMemberDecl()->getCanonicalDecl())) {
784 if (DK == OpenACCDirectiveKind::Declare ||
785 CK == OpenACCClauseKind::Reduction ||
786 CK == OpenACCClauseKind::UseDevice) {
787
788 // We can allow 'member expr' if the 'this' is implicit in the case of
789 // declare, reduction, and use_device.
790 const auto *This = dyn_cast<CXXThisExpr>(Val: ME->getBase());
791 if (This && This->isImplicit())
792 return CheckVarType(S&: *this, CK, VarExpr, InnerExpr: CurVarExpr);
793 } else {
794 return CheckVarType(S&: *this, CK, VarExpr, InnerExpr: CurVarExpr);
795 }
796 }
797 }
798
799 // Referring to 'this' is ok for the most part, but for 'use_device'/'declare'
800 // doesn't fall into 'variable or array name'
801 if (CK != OpenACCClauseKind::UseDevice &&
802 DK != OpenACCDirectiveKind::Declare && isa<CXXThisExpr>(Val: CurVarExpr))
803 return CheckVarType(S&: *this, CK, VarExpr, InnerExpr: CurVarExpr);
804
805 // Nothing really we can do here, as these are dependent. So just return they
806 // are valid.
807 if (isa<DependentScopeDeclRefExpr>(Val: CurVarExpr) ||
808 (CK != OpenACCClauseKind::Reduction &&
809 isa<CXXDependentScopeMemberExpr>(Val: CurVarExpr)))
810 return CheckVarType(S&: *this, CK, VarExpr, InnerExpr: CurVarExpr);
811
812 // There isn't really anything we can do in the case of a recovery expr, so
813 // skip the diagnostic rather than produce a confusing diagnostic.
814 if (isa<RecoveryExpr>(Val: CurVarExpr))
815 return ExprError();
816
817 if (DK == OpenACCDirectiveKind::Declare)
818 Diag(Loc: VarExpr->getExprLoc(), DiagID: diag::err_acc_not_a_var_ref_use_device_declare)
819 << /*declare*/ 1;
820 else if (CK == OpenACCClauseKind::UseDevice)
821 Diag(Loc: VarExpr->getExprLoc(), DiagID: diag::err_acc_not_a_var_ref_use_device_declare)
822 << /*use_device*/ 0;
823 else
824 Diag(Loc: VarExpr->getExprLoc(), DiagID: diag::err_acc_not_a_var_ref)
825 << (CK != OpenACCClauseKind::Reduction);
826 return ExprError();
827}
828
829ExprResult SemaOpenACC::ActOnArraySectionExpr(Expr *Base, SourceLocation LBLoc,
830 Expr *LowerBound,
831 SourceLocation ColonLoc,
832 Expr *Length,
833 SourceLocation RBLoc) {
834 ASTContext &Context = getASTContext();
835
836 // Handle placeholders.
837 if (Base->hasPlaceholderType() &&
838 !Base->hasPlaceholderType(K: BuiltinType::ArraySection)) {
839 ExprResult Result = SemaRef.CheckPlaceholderExpr(E: Base);
840 if (Result.isInvalid())
841 return ExprError();
842 Base = Result.get();
843 }
844 if (LowerBound && LowerBound->getType()->isNonOverloadPlaceholderType()) {
845 ExprResult Result = SemaRef.CheckPlaceholderExpr(E: LowerBound);
846 if (Result.isInvalid())
847 return ExprError();
848 Result = SemaRef.DefaultLvalueConversion(E: Result.get());
849 if (Result.isInvalid())
850 return ExprError();
851 LowerBound = Result.get();
852 }
853 if (Length && Length->getType()->isNonOverloadPlaceholderType()) {
854 ExprResult Result = SemaRef.CheckPlaceholderExpr(E: Length);
855 if (Result.isInvalid())
856 return ExprError();
857 Result = SemaRef.DefaultLvalueConversion(E: Result.get());
858 if (Result.isInvalid())
859 return ExprError();
860 Length = Result.get();
861 }
862
863 // Check the 'base' value, it must be an array or pointer type, and not to/of
864 // a function type.
865 QualType OriginalBaseTy = ArraySectionExpr::getBaseOriginalType(Base);
866 QualType ResultTy;
867 if (!Base->isTypeDependent()) {
868 if (OriginalBaseTy->isAnyPointerType()) {
869 ResultTy = OriginalBaseTy->getPointeeType();
870 } else if (OriginalBaseTy->isArrayType()) {
871 ResultTy = OriginalBaseTy->getAsArrayTypeUnsafe()->getElementType();
872 } else {
873 return ExprError(
874 Diag(Loc: Base->getExprLoc(), DiagID: diag::err_acc_typecheck_subarray_value)
875 << Base->getSourceRange());
876 }
877
878 if (ResultTy->isFunctionType()) {
879 Diag(Loc: Base->getExprLoc(), DiagID: diag::err_acc_subarray_function_type)
880 << ResultTy << Base->getSourceRange();
881 return ExprError();
882 }
883
884 if (SemaRef.RequireCompleteType(Loc: Base->getExprLoc(), T: ResultTy,
885 DiagID: diag::err_acc_subarray_incomplete_type,
886 Args: Base))
887 return ExprError();
888
889 if (!Base->hasPlaceholderType(K: BuiltinType::ArraySection)) {
890 ExprResult Result = SemaRef.DefaultFunctionArrayLvalueConversion(E: Base);
891 if (Result.isInvalid())
892 return ExprError();
893 Base = Result.get();
894 }
895 }
896
897 auto GetRecovery = [&](Expr *E, QualType Ty) {
898 ExprResult Recovery =
899 SemaRef.CreateRecoveryExpr(Begin: E->getBeginLoc(), End: E->getEndLoc(), SubExprs: E, T: Ty);
900 return Recovery.isUsable() ? Recovery.get() : nullptr;
901 };
902
903 // Ensure both of the expressions are int-exprs.
904 if (LowerBound && !LowerBound->isTypeDependent()) {
905 ExprResult LBRes =
906 ActOnIntExpr(DK: OpenACCDirectiveKind::Invalid, CK: OpenACCClauseKind::Invalid,
907 Loc: LowerBound->getExprLoc(), IntExpr: LowerBound);
908
909 if (LBRes.isUsable())
910 LBRes = SemaRef.DefaultLvalueConversion(E: LBRes.get());
911 LowerBound =
912 LBRes.isUsable() ? LBRes.get() : GetRecovery(LowerBound, Context.IntTy);
913 }
914
915 if (Length && !Length->isTypeDependent()) {
916 ExprResult LenRes =
917 ActOnIntExpr(DK: OpenACCDirectiveKind::Invalid, CK: OpenACCClauseKind::Invalid,
918 Loc: Length->getExprLoc(), IntExpr: Length);
919
920 if (LenRes.isUsable())
921 LenRes = SemaRef.DefaultLvalueConversion(E: LenRes.get());
922 Length =
923 LenRes.isUsable() ? LenRes.get() : GetRecovery(Length, Context.IntTy);
924 }
925
926 // Length is required if the base type is not an array of known bounds.
927 if (!Length && (OriginalBaseTy.isNull() ||
928 (!OriginalBaseTy->isDependentType() &&
929 !OriginalBaseTy->isConstantArrayType() &&
930 !OriginalBaseTy->isDependentSizedArrayType()))) {
931 bool IsArray = !OriginalBaseTy.isNull() && OriginalBaseTy->isArrayType();
932 SourceLocation DiagLoc = ColonLoc.isInvalid() ? LBLoc : ColonLoc;
933 Diag(Loc: DiagLoc, DiagID: diag::err_acc_subarray_no_length) << IsArray;
934 // Fill in a dummy 'length' so that when we instantiate this we don't
935 // double-diagnose here.
936 ExprResult Recovery = SemaRef.CreateRecoveryExpr(
937 Begin: DiagLoc, End: SourceLocation(), SubExprs: ArrayRef<Expr *>(), T: Context.IntTy);
938 Length = Recovery.isUsable() ? Recovery.get() : nullptr;
939 }
940
941 // Check the values of each of the arguments, they cannot be negative(we
942 // assume), and if the array bound is known, must be within range. As we do
943 // so, do our best to continue with evaluation, we can set the
944 // value/expression to nullptr/nullopt if they are invalid, and treat them as
945 // not present for the rest of evaluation.
946
947 // We don't have to check for dependence, because the dependent size is
948 // represented as a different AST node.
949 std::optional<llvm::APSInt> BaseSize;
950 if (!OriginalBaseTy.isNull() && OriginalBaseTy->isConstantArrayType()) {
951 const auto *ArrayTy = Context.getAsConstantArrayType(T: OriginalBaseTy);
952 BaseSize = ArrayTy->getSize();
953 }
954
955 auto GetBoundValue = [&](Expr *E) -> std::optional<llvm::APSInt> {
956 if (!E || E->isInstantiationDependent())
957 return std::nullopt;
958
959 Expr::EvalResult Res;
960 if (!E->EvaluateAsInt(Result&: Res, Ctx: Context))
961 return std::nullopt;
962 return Res.Val.getInt();
963 };
964
965 std::optional<llvm::APSInt> LowerBoundValue = GetBoundValue(LowerBound);
966 std::optional<llvm::APSInt> LengthValue = GetBoundValue(Length);
967
968 // Check lower bound for negative or out of range.
969 if (LowerBoundValue.has_value()) {
970 if (LowerBoundValue->isNegative()) {
971 Diag(Loc: LowerBound->getExprLoc(), DiagID: diag::err_acc_subarray_negative)
972 << /*LowerBound=*/0 << toString(I: *LowerBoundValue, /*Radix=*/10);
973 LowerBoundValue.reset();
974 LowerBound = GetRecovery(LowerBound, LowerBound->getType());
975 } else if (BaseSize.has_value() &&
976 llvm::APSInt::compareValues(I1: *LowerBoundValue, I2: *BaseSize) >= 0) {
977 // Lower bound (start index) must be less than the size of the array.
978 Diag(Loc: LowerBound->getExprLoc(), DiagID: diag::err_acc_subarray_out_of_range)
979 << /*LowerBound=*/0 << toString(I: *LowerBoundValue, /*Radix=*/10)
980 << toString(I: *BaseSize, /*Radix=*/10);
981 LowerBoundValue.reset();
982 LowerBound = GetRecovery(LowerBound, LowerBound->getType());
983 }
984 }
985
986 // Check length for negative or out of range.
987 if (LengthValue.has_value()) {
988 if (LengthValue->isNegative()) {
989 Diag(Loc: Length->getExprLoc(), DiagID: diag::err_acc_subarray_negative)
990 << /*Length=*/1 << toString(I: *LengthValue, /*Radix=*/10);
991 LengthValue.reset();
992 Length = GetRecovery(Length, Length->getType());
993 } else if (BaseSize.has_value() &&
994 llvm::APSInt::compareValues(I1: *LengthValue, I2: *BaseSize) > 0) {
995 // Length must be lessthan or EQUAL to the size of the array.
996 Diag(Loc: Length->getExprLoc(), DiagID: diag::err_acc_subarray_out_of_range)
997 << /*Length=*/1 << toString(I: *LengthValue, /*Radix=*/10)
998 << toString(I: *BaseSize, /*Radix=*/10);
999 LengthValue.reset();
1000 Length = GetRecovery(Length, Length->getType());
1001 }
1002 }
1003
1004 // Adding two APSInts requires matching sign and width, so extract those here.
1005 auto AddAPSInt = [](llvm::APSInt LHS, llvm::APSInt RHS) -> llvm::APSInt {
1006 if (LHS.isSigned() == RHS.isSigned() &&
1007 LHS.getBitWidth() == RHS.getBitWidth())
1008 return LHS + RHS;
1009
1010 // Width is + 1 so that unsigned->signed conversion just works.
1011 unsigned Width = std::max(a: LHS.getBitWidth(), b: RHS.getBitWidth()) + 1;
1012 return llvm::APSInt(LHS.sext(width: Width) + RHS.sext(width: Width), /*Signed=*/true);
1013 };
1014
1015 // If we know all 3 values, we can diagnose that the total value would be out
1016 // of range.
1017 if (BaseSize.has_value() && LowerBoundValue.has_value() &&
1018 LengthValue.has_value() &&
1019 llvm::APSInt::compareValues(I1: AddAPSInt(*LowerBoundValue, *LengthValue),
1020 I2: *BaseSize) > 0) {
1021 Diag(Loc: Base->getExprLoc(),
1022 DiagID: diag::err_acc_subarray_base_plus_length_out_of_range)
1023 << toString(I: *LowerBoundValue, /*Radix=*/10)
1024 << toString(I: *LengthValue, /*Radix=*/10)
1025 << toString(I: *BaseSize, /*Radix=*/10);
1026
1027 LowerBoundValue.reset();
1028 LowerBound = GetRecovery(LowerBound, LowerBound->getType());
1029 LengthValue.reset();
1030 Length = GetRecovery(Length, Length->getType());
1031 }
1032
1033 // If any part of the expression is dependent, return a dependent sub-array.
1034 QualType ArrayExprTy = Context.ArraySectionTy;
1035 if (Base->isTypeDependent() ||
1036 (LowerBound && LowerBound->isTypeDependent()) ||
1037 (Length && Length->isTypeDependent()))
1038 ArrayExprTy = Context.DependentTy;
1039
1040 return new (Context)
1041 ArraySectionExpr(Base, LowerBound, Length, ArrayExprTy, VK_LValue,
1042 OK_Ordinary, ColonLoc, RBLoc);
1043}
1044
1045void SemaOpenACC::ActOnWhileStmt(SourceLocation WhileLoc) {
1046 if (!getLangOpts().OpenACC)
1047 return;
1048
1049 if (!LoopInfo.TopLevelLoopSeen)
1050 return;
1051
1052 if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
1053 Diag(Loc: WhileLoc, DiagID: diag::err_acc_invalid_in_loop)
1054 << /*while loop*/ 1 << CollapseInfo.DirectiveKind
1055 << OpenACCClauseKind::Collapse;
1056 assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
1057 Diag(Loc: CollapseInfo.ActiveCollapse->getBeginLoc(),
1058 DiagID: diag::note_acc_active_clause_here)
1059 << OpenACCClauseKind::Collapse;
1060
1061 // Remove the value so that we don't get cascading errors in the body. The
1062 // caller RAII object will restore this.
1063 CollapseInfo.CurCollapseCount = std::nullopt;
1064 }
1065
1066 if (TileInfo.CurTileCount && *TileInfo.CurTileCount > 0) {
1067 Diag(Loc: WhileLoc, DiagID: diag::err_acc_invalid_in_loop)
1068 << /*while loop*/ 1 << TileInfo.DirectiveKind
1069 << OpenACCClauseKind::Tile;
1070 assert(TileInfo.ActiveTile && "tile count without object?");
1071 Diag(Loc: TileInfo.ActiveTile->getBeginLoc(), DiagID: diag::note_acc_active_clause_here)
1072 << OpenACCClauseKind::Tile;
1073
1074 // Remove the value so that we don't get cascading errors in the body. The
1075 // caller RAII object will restore this.
1076 TileInfo.CurTileCount = std::nullopt;
1077 }
1078}
1079
1080void SemaOpenACC::ActOnDoStmt(SourceLocation DoLoc) {
1081 if (!getLangOpts().OpenACC)
1082 return;
1083
1084 if (!LoopInfo.TopLevelLoopSeen)
1085 return;
1086
1087 if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
1088 Diag(Loc: DoLoc, DiagID: diag::err_acc_invalid_in_loop)
1089 << /*do loop*/ 2 << CollapseInfo.DirectiveKind
1090 << OpenACCClauseKind::Collapse;
1091 assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
1092 Diag(Loc: CollapseInfo.ActiveCollapse->getBeginLoc(),
1093 DiagID: diag::note_acc_active_clause_here)
1094 << OpenACCClauseKind::Collapse;
1095
1096 // Remove the value so that we don't get cascading errors in the body. The
1097 // caller RAII object will restore this.
1098 CollapseInfo.CurCollapseCount = std::nullopt;
1099 }
1100
1101 if (TileInfo.CurTileCount && *TileInfo.CurTileCount > 0) {
1102 Diag(Loc: DoLoc, DiagID: diag::err_acc_invalid_in_loop)
1103 << /*do loop*/ 2 << TileInfo.DirectiveKind << OpenACCClauseKind::Tile;
1104 assert(TileInfo.ActiveTile && "tile count without object?");
1105 Diag(Loc: TileInfo.ActiveTile->getBeginLoc(), DiagID: diag::note_acc_active_clause_here)
1106 << OpenACCClauseKind::Tile;
1107
1108 // Remove the value so that we don't get cascading errors in the body. The
1109 // caller RAII object will restore this.
1110 TileInfo.CurTileCount = std::nullopt;
1111 }
1112}
1113
1114void SemaOpenACC::ForStmtBeginHelper(SourceLocation ForLoc,
1115 ForStmtBeginChecker &C) {
1116 assert(getLangOpts().OpenACC && "Check enabled when not OpenACC?");
1117
1118 // Enable the while/do-while checking.
1119 LoopInfo.TopLevelLoopSeen = true;
1120
1121 if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
1122 // Check the format of this loop if it is affected by the collapse.
1123 C.check();
1124
1125 // OpenACC 3.3 2.9.1:
1126 // Each associated loop, except the innermost, must contain exactly one loop
1127 // or loop nest.
1128 // This checks for more than 1 loop at the current level, the
1129 // 'depth'-satisifed checking manages the 'not zero' case.
1130 if (LoopInfo.CurLevelHasLoopAlready) {
1131 Diag(Loc: ForLoc, DiagID: diag::err_acc_clause_multiple_loops)
1132 << CollapseInfo.DirectiveKind << OpenACCClauseKind::Collapse;
1133 assert(CollapseInfo.ActiveCollapse && "No collapse object?");
1134 Diag(Loc: CollapseInfo.ActiveCollapse->getBeginLoc(),
1135 DiagID: diag::note_acc_active_clause_here)
1136 << OpenACCClauseKind::Collapse;
1137 } else {
1138 --(*CollapseInfo.CurCollapseCount);
1139
1140 // Once we've hit zero here, we know we have deep enough 'for' loops to
1141 // get to the bottom.
1142 if (*CollapseInfo.CurCollapseCount == 0)
1143 CollapseInfo.CollapseDepthSatisfied = true;
1144 }
1145 }
1146
1147 if (TileInfo.CurTileCount && *TileInfo.CurTileCount > 0) {
1148 // Check the format of this loop if it is affected by the tile.
1149 C.check();
1150
1151 if (LoopInfo.CurLevelHasLoopAlready) {
1152 Diag(Loc: ForLoc, DiagID: diag::err_acc_clause_multiple_loops)
1153 << TileInfo.DirectiveKind << OpenACCClauseKind::Tile;
1154 assert(TileInfo.ActiveTile && "No tile object?");
1155 Diag(Loc: TileInfo.ActiveTile->getBeginLoc(),
1156 DiagID: diag::note_acc_active_clause_here)
1157 << OpenACCClauseKind::Tile;
1158 } else {
1159 TileInfo.CurTileCount = *TileInfo.CurTileCount - 1;
1160 // Once we've hit zero here, we know we have deep enough 'for' loops to
1161 // get to the bottom.
1162 if (*TileInfo.CurTileCount == 0)
1163 TileInfo.TileDepthSatisfied = true;
1164 }
1165 }
1166
1167 // Set this to 'false' for the body of this loop, so that the next level
1168 // checks independently.
1169 LoopInfo.CurLevelHasLoopAlready = false;
1170}
1171
1172namespace {
1173bool isValidLoopVariableType(QualType LoopVarTy) {
1174 // Just skip if it is dependent, it could be any of the below.
1175 if (LoopVarTy->isDependentType())
1176 return true;
1177
1178 // The loop variable must be of integer,
1179 if (LoopVarTy->isIntegerType())
1180 return true;
1181
1182 // C/C++ pointer,
1183 if (LoopVarTy->isPointerType())
1184 return true;
1185
1186 // or C++ random-access iterator type.
1187 if (const auto *RD = LoopVarTy->getAsCXXRecordDecl()) {
1188 // Note: Only do CXXRecordDecl because RecordDecl can't be a random access
1189 // iterator type!
1190
1191 // We could either do a lot of work to see if this matches
1192 // random-access-iterator, but it seems that just checking that the
1193 // 'iterator_category' typedef is more than sufficient. If programmers are
1194 // willing to lie about this, we can let them.
1195
1196 for (const auto *TD :
1197 llvm::make_filter_range(Range: RD->decls(), Pred: llvm::IsaPred<TypedefNameDecl>)) {
1198 const auto *TDND = cast<TypedefNameDecl>(Val: TD)->getCanonicalDecl();
1199
1200 if (TDND->getName() != "iterator_category")
1201 continue;
1202
1203 // If there is no type for this decl, return false.
1204 if (TDND->getUnderlyingType().isNull())
1205 return false;
1206
1207 const CXXRecordDecl *ItrCategoryDecl =
1208 TDND->getUnderlyingType()->getAsCXXRecordDecl();
1209
1210 // If the category isn't a record decl, it isn't the tag type.
1211 if (!ItrCategoryDecl)
1212 return false;
1213
1214 auto IsRandomAccessIteratorTag = [](const CXXRecordDecl *RD) {
1215 if (RD->getName() != "random_access_iterator_tag")
1216 return false;
1217 // Checks just for std::random_access_iterator_tag.
1218 return RD->getEnclosingNamespaceContext()->isStdNamespace();
1219 };
1220
1221 if (IsRandomAccessIteratorTag(ItrCategoryDecl))
1222 return true;
1223
1224 // We can also support tag-types inherited from the
1225 // random_access_iterator_tag.
1226 for (CXXBaseSpecifier BS : ItrCategoryDecl->bases())
1227 if (IsRandomAccessIteratorTag(BS.getType()->getAsCXXRecordDecl()))
1228 return true;
1229
1230 return false;
1231 }
1232 }
1233
1234 return false;
1235}
1236const ValueDecl *getDeclFromExpr(const Expr *E) {
1237 E = E->IgnoreParenImpCasts();
1238 if (const auto *FE = dyn_cast<FullExpr>(Val: E))
1239 E = FE->getSubExpr();
1240
1241 E = E->IgnoreParenImpCasts();
1242
1243 if (!E)
1244 return nullptr;
1245 if (const auto *DRE = dyn_cast<DeclRefExpr>(Val: E))
1246 return DRE->getDecl();
1247
1248 if (const auto *ME = dyn_cast<MemberExpr>(Val: E))
1249 if (isa<CXXThisExpr>(Val: ME->getBase()->IgnoreParenImpCasts()))
1250 return ME->getMemberDecl();
1251
1252 return nullptr;
1253}
1254} // namespace
1255
1256void SemaOpenACC::ForStmtBeginChecker::checkRangeFor() {
1257 const RangeForInfo &RFI = std::get<RangeForInfo>(v&: Info);
1258 // If this hasn't changed since last instantiated we're done.
1259 if (RFI.Uninstantiated == RFI.CurrentVersion)
1260 return;
1261
1262 const DeclStmt *UninstRangeStmt =
1263 IsInstantiation ? RFI.Uninstantiated->getBeginStmt() : nullptr;
1264 const DeclStmt *RangeStmt = RFI.CurrentVersion->getBeginStmt();
1265
1266 // If this isn't the first time we've checked this loop, suppress any cases
1267 // where we previously diagnosed.
1268 if (UninstRangeStmt) {
1269 const ValueDecl *InitVar =
1270 cast<ValueDecl>(Val: UninstRangeStmt->getSingleDecl());
1271 QualType VarType = InitVar->getType().getNonReferenceType();
1272
1273 if (!isValidLoopVariableType(LoopVarTy: VarType))
1274 return;
1275 }
1276
1277 // In some dependent contexts, the autogenerated range statement doesn't get
1278 // included until instantiation, so skip for now.
1279 if (RangeStmt) {
1280 const ValueDecl *InitVar = cast<ValueDecl>(Val: RangeStmt->getSingleDecl());
1281 QualType VarType = InitVar->getType().getNonReferenceType();
1282
1283 if (!isValidLoopVariableType(LoopVarTy: VarType)) {
1284 SemaRef.Diag(Loc: InitVar->getBeginLoc(), DiagID: diag::err_acc_loop_variable_type)
1285 << SemaRef.LoopWithoutSeqInfo.Kind << VarType;
1286 SemaRef.Diag(Loc: SemaRef.LoopWithoutSeqInfo.Loc,
1287 DiagID: diag::note_acc_construct_here)
1288 << SemaRef.LoopWithoutSeqInfo.Kind;
1289 return;
1290 }
1291 }
1292}
1293bool SemaOpenACC::ForStmtBeginChecker::checkForInit(const Stmt *InitStmt,
1294 const ValueDecl *&InitVar,
1295 bool Diag) {
1296 // Init statement is required.
1297 if (!InitStmt) {
1298 if (Diag) {
1299 SemaRef.Diag(Loc: ForLoc, DiagID: diag::err_acc_loop_variable)
1300 << SemaRef.LoopWithoutSeqInfo.Kind;
1301 SemaRef.Diag(Loc: SemaRef.LoopWithoutSeqInfo.Loc,
1302 DiagID: diag::note_acc_construct_here)
1303 << SemaRef.LoopWithoutSeqInfo.Kind;
1304 }
1305 return true;
1306 }
1307 auto DiagLoopVar = [this, Diag, InitStmt]() {
1308 if (Diag) {
1309 SemaRef.Diag(Loc: InitStmt->getBeginLoc(), DiagID: diag::err_acc_loop_variable)
1310 << SemaRef.LoopWithoutSeqInfo.Kind;
1311 SemaRef.Diag(Loc: SemaRef.LoopWithoutSeqInfo.Loc,
1312 DiagID: diag::note_acc_construct_here)
1313 << SemaRef.LoopWithoutSeqInfo.Kind;
1314 }
1315 return true;
1316 };
1317
1318 if (const auto *ExprTemp = dyn_cast<ExprWithCleanups>(Val: InitStmt))
1319 InitStmt = ExprTemp->getSubExpr();
1320 if (const auto *E = dyn_cast<Expr>(Val: InitStmt))
1321 InitStmt = E->IgnoreParenImpCasts();
1322
1323 InitVar = nullptr;
1324 if (const auto *BO = dyn_cast<BinaryOperator>(Val: InitStmt)) {
1325 // Allow assignment operator here.
1326
1327 if (!BO->isAssignmentOp())
1328 return DiagLoopVar();
1329
1330 const Expr *LHS = BO->getLHS()->IgnoreParenImpCasts();
1331 if (const auto *DRE = dyn_cast<DeclRefExpr>(Val: LHS))
1332 InitVar = DRE->getDecl();
1333 } else if (const auto *DS = dyn_cast<DeclStmt>(Val: InitStmt)) {
1334 // Allow T t = <whatever>
1335 if (!DS->isSingleDecl())
1336 return DiagLoopVar();
1337 InitVar = dyn_cast<ValueDecl>(Val: DS->getSingleDecl());
1338
1339 // Ensure we have an initializer, unless this is a record/dependent type.
1340 if (InitVar) {
1341 if (!isa<VarDecl>(Val: InitVar))
1342 return DiagLoopVar();
1343
1344 if (!InitVar->getType()->isRecordType() &&
1345 !InitVar->getType()->isDependentType() &&
1346 !cast<VarDecl>(Val: InitVar)->hasInit())
1347 return DiagLoopVar();
1348 }
1349 } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(Val: InitStmt)) {
1350 // Allow assignment operator call.
1351 if (CE->getOperator() != OO_Equal)
1352 return DiagLoopVar();
1353 if (CE->getNumArgs() < 1)
1354 return DiagLoopVar();
1355
1356 const Expr *LHS = CE->getArg(Arg: 0)->IgnoreParenImpCasts();
1357 if (auto *DRE = dyn_cast<DeclRefExpr>(Val: LHS)) {
1358 InitVar = DRE->getDecl();
1359 } else if (auto *ME = dyn_cast<MemberExpr>(Val: LHS)) {
1360 if (isa<CXXThisExpr>(Val: ME->getBase()->IgnoreParenImpCasts()))
1361 InitVar = ME->getMemberDecl();
1362 }
1363 }
1364
1365 // If after all of that, we haven't found a variable, give up.
1366 if (!InitVar)
1367 return DiagLoopVar();
1368
1369 InitVar = cast<ValueDecl>(Val: InitVar->getCanonicalDecl());
1370 QualType VarType = InitVar->getType().getNonReferenceType();
1371
1372 // Since we have one, all we need to do is ensure it is the right type.
1373 if (!isValidLoopVariableType(LoopVarTy: VarType)) {
1374 if (Diag) {
1375 SemaRef.Diag(Loc: InitVar->getBeginLoc(), DiagID: diag::err_acc_loop_variable_type)
1376 << SemaRef.LoopWithoutSeqInfo.Kind << VarType;
1377 SemaRef.Diag(Loc: SemaRef.LoopWithoutSeqInfo.Loc,
1378 DiagID: diag::note_acc_construct_here)
1379 << SemaRef.LoopWithoutSeqInfo.Kind;
1380 }
1381 return true;
1382 }
1383
1384 return false;
1385}
1386
1387bool SemaOpenACC::ForStmtBeginChecker::checkForCond(const Stmt *CondStmt,
1388 const ValueDecl *InitVar,
1389 bool Diag) {
1390 // A condition statement is required.
1391 if (!CondStmt) {
1392 if (Diag) {
1393 SemaRef.Diag(Loc: ForLoc, DiagID: diag::err_acc_loop_terminating_condition)
1394 << SemaRef.LoopWithoutSeqInfo.Kind;
1395 SemaRef.Diag(Loc: SemaRef.LoopWithoutSeqInfo.Loc,
1396 DiagID: diag::note_acc_construct_here)
1397 << SemaRef.LoopWithoutSeqInfo.Kind;
1398 }
1399
1400 return true;
1401 }
1402 auto DiagCondVar = [this, Diag, CondStmt] {
1403 if (Diag) {
1404 SemaRef.Diag(Loc: CondStmt->getBeginLoc(),
1405 DiagID: diag::err_acc_loop_terminating_condition)
1406 << SemaRef.LoopWithoutSeqInfo.Kind;
1407 SemaRef.Diag(Loc: SemaRef.LoopWithoutSeqInfo.Loc,
1408 DiagID: diag::note_acc_construct_here)
1409 << SemaRef.LoopWithoutSeqInfo.Kind;
1410 }
1411 return true;
1412 };
1413
1414 if (const auto *ExprTemp = dyn_cast<ExprWithCleanups>(Val: CondStmt))
1415 CondStmt = ExprTemp->getSubExpr();
1416 if (const auto *E = dyn_cast<Expr>(Val: CondStmt))
1417 CondStmt = E->IgnoreParenImpCasts();
1418
1419 const ValueDecl *CondVar = nullptr;
1420 if (const auto *BO = dyn_cast<BinaryOperator>(Val: CondStmt)) {
1421 switch (BO->getOpcode()) {
1422 default:
1423 return DiagCondVar();
1424 case BO_EQ:
1425 case BO_LT:
1426 case BO_GT:
1427 case BO_NE:
1428 case BO_LE:
1429 case BO_GE:
1430 break;
1431 }
1432
1433 // Assign the condition-var to the LHS. If it either comes back null, or
1434 // the LHS doesn't match the InitVar, assign it to the RHS so that 5 < N is
1435 // allowed.
1436 CondVar = getDeclFromExpr(E: BO->getLHS());
1437 if (!CondVar ||
1438 (InitVar && CondVar->getCanonicalDecl() != InitVar->getCanonicalDecl()))
1439 CondVar = getDeclFromExpr(E: BO->getRHS());
1440
1441 } else if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(Val: CondStmt)) {
1442 // Any of the comparison ops should be ok here, but we don't know how to
1443 // handle spaceship, so disallow for now.
1444 if (!CE->isComparisonOp() || CE->getOperator() == OO_Spaceship)
1445 return DiagCondVar();
1446
1447 if (CE->getNumArgs() < 1)
1448 DiagCondVar();
1449
1450 // Same logic here: Assign it to the LHS, unless the LHS comes back null or
1451 // not equal to the init var.
1452 CondVar = getDeclFromExpr(E: CE->getArg(Arg: 0));
1453 if (!CondVar ||
1454 (InitVar &&
1455 CondVar->getCanonicalDecl() != InitVar->getCanonicalDecl() &&
1456 CE->getNumArgs() > 1))
1457 CondVar = getDeclFromExpr(E: CE->getArg(Arg: 1));
1458 } else {
1459 return DiagCondVar();
1460 }
1461
1462 if (!CondVar)
1463 return DiagCondVar();
1464
1465 // Don't consider this an error unless the init variable was properly set,
1466 // else check to make sure they are the same variable.
1467 if (InitVar && CondVar->getCanonicalDecl() != InitVar->getCanonicalDecl())
1468 return DiagCondVar();
1469
1470 return false;
1471}
1472
1473namespace {
1474// Helper to check the RHS of an assignment during for's step. We can allow
1475// InitVar = InitVar + N, InitVar = N + InitVar, and Initvar = Initvar - N,
1476// where N is an integer.
1477bool isValidForIncRHSAssign(const ValueDecl *InitVar, const Expr *RHS) {
1478
1479 auto isValid = [](const ValueDecl *InitVar, const Expr *InnerLHS,
1480 const Expr *InnerRHS, bool IsAddition) {
1481 // ONE of the sides has to be an integer type.
1482 if (!InnerLHS->getType()->isIntegerType() &&
1483 !InnerRHS->getType()->isIntegerType())
1484 return false;
1485
1486 // If the init var is already an error, don't bother trying to check for
1487 // it.
1488 if (!InitVar)
1489 return true;
1490
1491 const ValueDecl *LHSDecl = getDeclFromExpr(E: InnerLHS);
1492 const ValueDecl *RHSDecl = getDeclFromExpr(E: InnerRHS);
1493 // If we can't get a declaration, this is probably an error, so give up.
1494 if (!LHSDecl || !RHSDecl)
1495 return true;
1496
1497 // If the LHS is the InitVar, the other must be int, so this is valid.
1498 if (LHSDecl->getCanonicalDecl() ==
1499 InitVar->getCanonicalDecl())
1500 return true;
1501
1502 // Subtraction doesn't allow the RHS to be init var, so this is invalid.
1503 if (!IsAddition)
1504 return false;
1505
1506 return RHSDecl->getCanonicalDecl() ==
1507 InitVar->getCanonicalDecl();
1508 };
1509
1510 if (const auto *BO = dyn_cast<BinaryOperator>(Val: RHS)) {
1511 BinaryOperatorKind OpC = BO->getOpcode();
1512 if (OpC != BO_Add && OpC != BO_Sub)
1513 return false;
1514 return isValid(InitVar, BO->getLHS(), BO->getRHS(), OpC == BO_Add);
1515 } else if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(Val: RHS)) {
1516 OverloadedOperatorKind Op = CE->getOperator();
1517 if (Op != OO_Plus && Op != OO_Minus)
1518 return false;
1519 // Despite Plus/Minus otherwise only being possible with 2 arguments, error
1520 // recovery will sometimes leave us with only 1 here, so fail out if we
1521 // don't have the correct number of args.
1522 if (CE->getNumArgs() != 2)
1523 return false;
1524 return isValid(InitVar, CE->getArg(Arg: 0), CE->getArg(Arg: 1), Op == OO_Plus);
1525 }
1526
1527 return false;
1528}
1529} // namespace
1530
1531bool SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
1532 const ValueDecl *InitVar,
1533 bool Diag) {
1534 if (!IncStmt) {
1535 if (Diag) {
1536 SemaRef.Diag(Loc: ForLoc, DiagID: diag::err_acc_loop_not_monotonic)
1537 << SemaRef.LoopWithoutSeqInfo.Kind;
1538 SemaRef.Diag(Loc: SemaRef.LoopWithoutSeqInfo.Loc,
1539 DiagID: diag::note_acc_construct_here)
1540 << SemaRef.LoopWithoutSeqInfo.Kind;
1541 }
1542 return true;
1543 }
1544 auto DiagIncVar = [this, Diag, IncStmt] {
1545 if (Diag) {
1546 SemaRef.Diag(Loc: IncStmt->getBeginLoc(), DiagID: diag::err_acc_loop_not_monotonic)
1547 << SemaRef.LoopWithoutSeqInfo.Kind;
1548 SemaRef.Diag(Loc: SemaRef.LoopWithoutSeqInfo.Loc,
1549 DiagID: diag::note_acc_construct_here)
1550 << SemaRef.LoopWithoutSeqInfo.Kind;
1551 }
1552 return true;
1553 };
1554
1555 if (const auto *ExprTemp = dyn_cast<ExprWithCleanups>(Val: IncStmt))
1556 IncStmt = ExprTemp->getSubExpr();
1557 if (const auto *E = dyn_cast<Expr>(Val: IncStmt))
1558 IncStmt = E->IgnoreParenImpCasts();
1559
1560 const ValueDecl *IncVar = nullptr;
1561 // Here we enforce the monotonically increase/decrease:
1562 if (const auto *UO = dyn_cast<UnaryOperator>(Val: IncStmt)) {
1563 // Allow increment/decrement ops.
1564 if (!UO->isIncrementDecrementOp())
1565 return DiagIncVar();
1566 IncVar = getDeclFromExpr(E: UO->getSubExpr());
1567 } else if (const auto *BO = dyn_cast<BinaryOperator>(Val: IncStmt)) {
1568 switch (BO->getOpcode()) {
1569 default:
1570 return DiagIncVar();
1571 case BO_AddAssign:
1572 case BO_SubAssign:
1573 break;
1574 case BO_Assign:
1575 // For assignment we also allow InitVar = InitVar + N, InitVar = N +
1576 // InitVar, and InitVar = InitVar - N; BUT only if 'N' is integral.
1577 if (!isValidForIncRHSAssign(InitVar, RHS: BO->getRHS()))
1578 return DiagIncVar();
1579 break;
1580 }
1581 IncVar = getDeclFromExpr(E: BO->getLHS());
1582 } else if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(Val: IncStmt)) {
1583 if (CE->getNumArgs() < 1)
1584 return DiagIncVar();
1585
1586 switch (CE->getOperator()) {
1587 default:
1588 return DiagIncVar();
1589 case OO_PlusPlus:
1590 case OO_MinusMinus:
1591 case OO_PlusEqual:
1592 case OO_MinusEqual:
1593 break;
1594 case OO_Equal:
1595 // For assignment we also allow InitVar = InitVar + N, InitVar = N +
1596 // InitVar, and InitVar = InitVar - N; BUT only if 'N' is integral.
1597 if (CE->getNumArgs() != 2 ||
1598 !isValidForIncRHSAssign(InitVar, RHS: CE->getArg(Arg: 1)))
1599 return DiagIncVar();
1600 break;
1601 }
1602
1603 IncVar = getDeclFromExpr(E: CE->getArg(Arg: 0));
1604 } else {
1605 return DiagIncVar();
1606 }
1607
1608 if (!IncVar)
1609 return DiagIncVar();
1610
1611 // InitVar shouldn't be null unless there was an error, so don't diagnose if
1612 // that is the case. Else we should ensure that it refers to the loop
1613 // value.
1614 if (InitVar && IncVar->getCanonicalDecl() != InitVar->getCanonicalDecl())
1615 return DiagIncVar();
1616
1617 return false;
1618}
1619
1620void SemaOpenACC::ForStmtBeginChecker::checkFor() {
1621 const CheckForInfo &CFI = std::get<CheckForInfo>(v&: Info);
1622
1623 if (!IsInstantiation) {
1624 // If this isn't an instantiation, we can just check all of these and
1625 // diagnose.
1626 const ValueDecl *CurInitVar = nullptr;
1627 checkForInit(InitStmt: CFI.Current.Init, InitVar&: CurInitVar, /*Diag=*/true);
1628 checkForCond(CondStmt: CFI.Current.Condition, InitVar: CurInitVar, /*Diag=*/true);
1629 checkForInc(IncStmt: CFI.Current.Increment, InitVar: CurInitVar, /*DIag=*/Diag: true);
1630 } else {
1631 const ValueDecl *UninstInitVar = nullptr;
1632 // Checking the 'init' section first. We have to always run both versions,
1633 // at minimum with the 'diag' off, so that we can ensure we get the correct
1634 // instantiation var for checking by later ones.
1635 bool UninstInitFailed =
1636 checkForInit(InitStmt: CFI.Uninst.Init, InitVar&: UninstInitVar, /*Diag=*/false);
1637
1638 // VarDecls are always rebuild because they are dependent, so we can do a
1639 // little work to suppress some of the double checking based on whether the
1640 // type is instantiation dependent. This is imperfect, but will get us most
1641 // cases suppressed. Currently this only handles the 'T t =' case.
1642 auto InitChanged = [=]() {
1643 if (CFI.Uninst.Init == CFI.Current.Init)
1644 return false;
1645
1646 QualType OldVDTy;
1647 QualType NewVDTy;
1648
1649 if (const auto *DS = dyn_cast<DeclStmt>(Val: CFI.Uninst.Init))
1650 if (const VarDecl *VD = dyn_cast_if_present<VarDecl>(
1651 Val: DS->isSingleDecl() ? DS->getSingleDecl() : nullptr))
1652 OldVDTy = VD->getType();
1653 if (const auto *DS = dyn_cast<DeclStmt>(Val: CFI.Current.Init))
1654 if (const VarDecl *VD = dyn_cast_if_present<VarDecl>(
1655 Val: DS->isSingleDecl() ? DS->getSingleDecl() : nullptr))
1656 NewVDTy = VD->getType();
1657
1658 if (OldVDTy.isNull() || NewVDTy.isNull())
1659 return true;
1660
1661 return OldVDTy->isInstantiationDependentType() !=
1662 NewVDTy->isInstantiationDependentType();
1663 };
1664
1665 // Only diagnose the new 'init' if the previous version didn't fail, AND the
1666 // current init changed meaningfully.
1667 bool ShouldDiagNewInit = !UninstInitFailed && InitChanged();
1668 const ValueDecl *CurInitVar = nullptr;
1669 checkForInit(InitStmt: CFI.Current.Init, InitVar&: CurInitVar, /*Diag=*/ShouldDiagNewInit);
1670
1671 // Check the condition and increment only if the previous version passed,
1672 // and this changed.
1673 if (CFI.Uninst.Condition != CFI.Current.Condition &&
1674 !checkForCond(CondStmt: CFI.Uninst.Condition, InitVar: UninstInitVar, /*Diag=*/false))
1675 checkForCond(CondStmt: CFI.Current.Condition, InitVar: CurInitVar, /*Diag=*/true);
1676 if (CFI.Uninst.Increment != CFI.Current.Increment &&
1677 !checkForInc(IncStmt: CFI.Uninst.Increment, InitVar: UninstInitVar, /*Diag=*/false))
1678 checkForInc(IncStmt: CFI.Current.Increment, InitVar: CurInitVar, /*Diag=*/true);
1679 }
1680}
1681
1682void SemaOpenACC::ForStmtBeginChecker::check() {
1683 // If this isn't an active loop without a seq, immediately return, nothing to
1684 // check.
1685 if (SemaRef.LoopWithoutSeqInfo.Kind == OpenACCDirectiveKind::Invalid)
1686 return;
1687
1688 // If we've already checked, because this is a 'top level' one (and asking
1689 // again because 'tile' and 'collapse' might apply), just return, nothing to
1690 // do here.
1691 if (AlreadyChecked)
1692 return;
1693 AlreadyChecked = true;
1694
1695 // OpenACC3.3 2.1:
1696 // A loop associated with a loop construct that does not have a seq clause
1697 // must be written to meet all the following conditions:
1698 // - The loop variable must be of integer, C/C++ pointer, or C++ random-access
1699 // iterator type.
1700 // - The loop variable must monotonically increase or decrease in the
1701 // direction of its termination condition.
1702 // - The loop trip count must be computable in constant time when entering the
1703 // loop construct.
1704 //
1705 // For a C++ range-based for loop, the loop variable
1706 // identified by the above conditions is the internal iterator, such as a
1707 // pointer, that the compiler generates to iterate the range. it is not the
1708 // variable declared by the for loop.
1709
1710 if (std::holds_alternative<RangeForInfo>(v: Info))
1711 return checkRangeFor();
1712
1713 return checkFor();
1714}
1715
1716void SemaOpenACC::ActOnForStmtBegin(SourceLocation ForLoc, const Stmt *OldFirst,
1717 const Stmt *First, const Stmt *OldSecond,
1718 const Stmt *Second, const Stmt *OldThird,
1719 const Stmt *Third) {
1720 if (!getLangOpts().OpenACC)
1721 return;
1722
1723 ForStmtBeginChecker FSBC{*this, ForLoc, OldFirst, OldSecond,
1724 OldThird, First, Second, Third};
1725 // Check if this is the top-level 'for' for a 'loop'. Else it will be checked
1726 // as a part of the helper if a tile/collapse applies.
1727 if (!LoopInfo.TopLevelLoopSeen) {
1728 FSBC.check();
1729 }
1730
1731 ForStmtBeginHelper(ForLoc, C&: FSBC);
1732}
1733
1734void SemaOpenACC::ActOnForStmtBegin(SourceLocation ForLoc, const Stmt *First,
1735 const Stmt *Second, const Stmt *Third) {
1736 if (!getLangOpts().OpenACC)
1737 return;
1738
1739 ForStmtBeginChecker FSBC{*this, ForLoc, First, Second, Third};
1740
1741 // Check if this is the top-level 'for' for a 'loop'. Else it will be checked
1742 // as a part of the helper if a tile/collapse applies.
1743 if (!LoopInfo.TopLevelLoopSeen)
1744 FSBC.check();
1745
1746 ForStmtBeginHelper(ForLoc, C&: FSBC);
1747}
1748
1749void SemaOpenACC::ActOnRangeForStmtBegin(SourceLocation ForLoc,
1750 const Stmt *OldRangeFor,
1751 const Stmt *RangeFor) {
1752 if (!getLangOpts().OpenACC || OldRangeFor == nullptr || RangeFor == nullptr)
1753 return;
1754
1755 ForStmtBeginChecker FSBC{*this, ForLoc,
1756 cast_if_present<CXXForRangeStmt>(Val: OldRangeFor),
1757 cast_if_present<CXXForRangeStmt>(Val: RangeFor)};
1758 // Check if this is the top-level 'for' for a 'loop'. Else it will be checked
1759 // as a part of the helper if a tile/collapse applies.
1760 if (!LoopInfo.TopLevelLoopSeen) {
1761 FSBC.check();
1762 }
1763 ForStmtBeginHelper(ForLoc, C&: FSBC);
1764}
1765
1766void SemaOpenACC::ActOnRangeForStmtBegin(SourceLocation ForLoc,
1767 const Stmt *RangeFor) {
1768 if (!getLangOpts().OpenACC || RangeFor == nullptr)
1769 return;
1770
1771 ForStmtBeginChecker FSBC = {*this, ForLoc,
1772 cast_if_present<CXXForRangeStmt>(Val: RangeFor)};
1773
1774 // Check if this is the top-level 'for' for a 'loop'. Else it will be checked
1775 // as a part of the helper if a tile/collapse applies.
1776 if (!LoopInfo.TopLevelLoopSeen)
1777 FSBC.check();
1778
1779 ForStmtBeginHelper(ForLoc, C&: FSBC);
1780}
1781
1782namespace {
1783SourceLocation FindInterveningCodeInLoop(const Stmt *CurStmt) {
1784 // We should diagnose on anything except `CompoundStmt`, `NullStmt`,
1785 // `ForStmt`, `CXXForRangeStmt`, since those are legal, and `WhileStmt` and
1786 // `DoStmt`, as those are caught as a violation elsewhere.
1787 // For `CompoundStmt` we need to search inside of it.
1788 if (!CurStmt ||
1789 isa<ForStmt, NullStmt, ForStmt, CXXForRangeStmt, WhileStmt, DoStmt>(
1790 Val: CurStmt))
1791 return SourceLocation{};
1792
1793 // Any other construct is an error anyway, so it has already been diagnosed.
1794 if (isa<OpenACCConstructStmt>(Val: CurStmt))
1795 return SourceLocation{};
1796
1797 // Search inside the compound statement, this allows for arbitrary nesting
1798 // of compound statements, as long as there isn't any code inside.
1799 if (const auto *CS = dyn_cast<CompoundStmt>(Val: CurStmt)) {
1800 for (const auto *ChildStmt : CS->children()) {
1801 SourceLocation ChildStmtLoc = FindInterveningCodeInLoop(CurStmt: ChildStmt);
1802 if (ChildStmtLoc.isValid())
1803 return ChildStmtLoc;
1804 }
1805 // Empty/not invalid compound statements are legal.
1806 return SourceLocation{};
1807 }
1808 return CurStmt->getBeginLoc();
1809}
1810} // namespace
1811
1812void SemaOpenACC::ActOnForStmtEnd(SourceLocation ForLoc, StmtResult Body) {
1813 if (!getLangOpts().OpenACC)
1814 return;
1815
1816 // Set this to 'true' so if we find another one at this level we can diagnose.
1817 LoopInfo.CurLevelHasLoopAlready = true;
1818
1819 if (!Body.isUsable())
1820 return;
1821
1822 bool IsActiveCollapse = CollapseInfo.CurCollapseCount &&
1823 *CollapseInfo.CurCollapseCount > 0 &&
1824 !CollapseInfo.ActiveCollapse->hasForce();
1825 bool IsActiveTile = TileInfo.CurTileCount && *TileInfo.CurTileCount > 0;
1826
1827 if (IsActiveCollapse || IsActiveTile) {
1828 SourceLocation OtherStmtLoc = FindInterveningCodeInLoop(CurStmt: Body.get());
1829
1830 if (OtherStmtLoc.isValid() && IsActiveCollapse) {
1831 Diag(Loc: OtherStmtLoc, DiagID: diag::err_acc_intervening_code)
1832 << OpenACCClauseKind::Collapse << CollapseInfo.DirectiveKind;
1833 Diag(Loc: CollapseInfo.ActiveCollapse->getBeginLoc(),
1834 DiagID: diag::note_acc_active_clause_here)
1835 << OpenACCClauseKind::Collapse;
1836 }
1837
1838 if (OtherStmtLoc.isValid() && IsActiveTile) {
1839 Diag(Loc: OtherStmtLoc, DiagID: diag::err_acc_intervening_code)
1840 << OpenACCClauseKind::Tile << TileInfo.DirectiveKind;
1841 Diag(Loc: TileInfo.ActiveTile->getBeginLoc(),
1842 DiagID: diag::note_acc_active_clause_here)
1843 << OpenACCClauseKind::Tile;
1844 }
1845 }
1846}
1847
1848namespace {
1849// Helper that should mirror ActOnRoutineName to get the FunctionDecl out for
1850// magic-static checking.
1851FunctionDecl *getFunctionFromRoutineName(Expr *RoutineName) {
1852 if (!RoutineName)
1853 return nullptr;
1854 RoutineName = RoutineName->IgnoreParenImpCasts();
1855 if (isa<RecoveryExpr>(Val: RoutineName)) {
1856 // There is nothing we can do here, this isn't a function we can count on.
1857 return nullptr;
1858 } else if (isa<DependentScopeDeclRefExpr, CXXDependentScopeMemberExpr>(
1859 Val: RoutineName)) {
1860 // The lookup is dependent, so we'll have to figure this out later.
1861 return nullptr;
1862 } else if (auto *DRE = dyn_cast<DeclRefExpr>(Val: RoutineName)) {
1863 ValueDecl *VD = DRE->getDecl();
1864
1865 if (auto *FD = dyn_cast<FunctionDecl>(Val: VD))
1866 return FD;
1867
1868 // Allow lambdas.
1869 if (auto *VarD = dyn_cast<VarDecl>(Val: VD)) {
1870 QualType VarDTy = VarD->getType();
1871 if (!VarDTy.isNull()) {
1872 if (auto *RD = VarDTy->getAsCXXRecordDecl()) {
1873 if (RD->isGenericLambda())
1874 return nullptr;
1875 if (RD->isLambda())
1876 return RD->getLambdaCallOperator();
1877 } else if (VarDTy->isDependentType()) {
1878 // We don't really know what this is going to be.
1879 return nullptr;
1880 }
1881 }
1882 return nullptr;
1883 } else if (isa<OverloadExpr>(Val: RoutineName)) {
1884 return nullptr;
1885 }
1886 }
1887 return nullptr;
1888}
1889} // namespace
1890
1891ExprResult SemaOpenACC::ActOnRoutineName(Expr *RoutineName) {
1892 assert(RoutineName && "Routine name cannot be null here");
1893 RoutineName = RoutineName->IgnoreParenImpCasts();
1894
1895 if (isa<RecoveryExpr>(Val: RoutineName)) {
1896 // This has already been diagnosed, so we can skip it.
1897 return ExprError();
1898 } else if (isa<DependentScopeDeclRefExpr, CXXDependentScopeMemberExpr>(
1899 Val: RoutineName)) {
1900 // These are dependent and we can't really check them, so delay until
1901 // instantiation.
1902 return RoutineName;
1903 } else if (const auto *DRE = dyn_cast<DeclRefExpr>(Val: RoutineName)) {
1904 const ValueDecl *VD = DRE->getDecl();
1905
1906 if (isa<FunctionDecl>(Val: VD))
1907 return RoutineName;
1908
1909 // Allow lambdas.
1910 if (const auto *VarD = dyn_cast<VarDecl>(Val: VD)) {
1911 QualType VarDTy = VarD->getType();
1912 if (!VarDTy.isNull()) {
1913 if (const auto *RD = VarDTy->getAsCXXRecordDecl()) {
1914 if (RD->isGenericLambda()) {
1915 Diag(Loc: RoutineName->getBeginLoc(), DiagID: diag::err_acc_routine_overload_set)
1916 << RoutineName;
1917 return ExprError();
1918 }
1919 if (RD->isLambda())
1920 return RoutineName;
1921 } else if (VarDTy->isDependentType()) {
1922 // If this is a dependent variable, it might be a lambda. So we just
1923 // accept this and catch it next time.
1924 return RoutineName;
1925 }
1926 }
1927 }
1928
1929 Diag(Loc: RoutineName->getBeginLoc(), DiagID: diag::err_acc_routine_not_func)
1930 << RoutineName;
1931 return ExprError();
1932 } else if (isa<OverloadExpr>(Val: RoutineName)) {
1933 // This happens in function templates, even when the template arguments are
1934 // fully specified. We could possibly do some sort of matching to make sure
1935 // that this is looked up/deduced, but GCC does not do this, so there
1936 // doesn't seem to be a good reason for us to do it either.
1937 Diag(Loc: RoutineName->getBeginLoc(), DiagID: diag::err_acc_routine_overload_set)
1938 << RoutineName;
1939 return ExprError();
1940 }
1941
1942 Diag(Loc: RoutineName->getBeginLoc(), DiagID: diag::err_acc_routine_not_func)
1943 << RoutineName;
1944 return ExprError();
1945}
1946void SemaOpenACC::ActOnVariableDeclarator(VarDecl *VD) {
1947 if (!getLangOpts().OpenACC || VD->isInvalidDecl() || !VD->isStaticLocal())
1948 return;
1949
1950 // This cast should be safe, since a static-local can only happen in a
1951 // function declaration. However, in error cases (or perhaps ObjC/C++?), this
1952 // could possibly be something like a 'block' decl, so if this is NOT a
1953 // function decl, just give up.
1954 auto *ContextDecl = dyn_cast<FunctionDecl>(Val: getCurContext());
1955
1956 if (!ContextDecl)
1957 return;
1958
1959 // OpenACC 3.3 2.15:
1960 // In C and C++, function static variables are not supported in functions to
1961 // which a routine directive applies.
1962 for (const auto *A : ContextDecl->attrs()) {
1963 if (isa<OpenACCRoutineDeclAttr, OpenACCRoutineAnnotAttr>(Val: A)) {
1964 Diag(Loc: VD->getBeginLoc(), DiagID: diag::err_acc_magic_static_in_routine);
1965 Diag(Loc: A->getLocation(), DiagID: diag::note_acc_construct_here)
1966 << OpenACCDirectiveKind::Routine;
1967 return;
1968 }
1969 }
1970
1971 MagicStaticLocs.insert(KV: {ContextDecl->getCanonicalDecl(), VD->getBeginLoc()});
1972}
1973void SemaOpenACC::CheckLastRoutineDeclNameConflict(const NamedDecl *ND) {
1974 // OpenACC 3.3 A.3.4
1975 // When a procedure with that name is in scope and it is not the same
1976 // procedure as the immediately following procedure declaration or
1977 // definition, the resolution of the name can be confusing. Implementations
1978 // should then issue a compile-time warning diagnostic even though the
1979 // application is conforming.
1980
1981 // If we haven't created one, also can't diagnose.
1982 if (!LastRoutineDecl)
1983 return;
1984
1985 // If the currently created function doesn't have a name, we can't diagnose on
1986 // a match.
1987 if (!ND->getDeclName().isIdentifier())
1988 return;
1989
1990 // If the two are in different decl contexts, it doesn't make sense to
1991 // diagnose.
1992 if (LastRoutineDecl->getDeclContext() != ND->getLexicalDeclContext())
1993 return;
1994
1995 // If we don't have a referenced thing yet, we can't diagnose.
1996 FunctionDecl *RoutineTarget =
1997 getFunctionFromRoutineName(RoutineName: LastRoutineDecl->getFunctionReference());
1998 if (!RoutineTarget)
1999 return;
2000
2001 // If the Routine target doesn't have a name, we can't diagnose.
2002 if (!RoutineTarget->getDeclName().isIdentifier())
2003 return;
2004
2005 // Of course don't diagnose if the names don't match.
2006 if (ND->getName() != RoutineTarget->getName())
2007 return;
2008
2009 long NDLine = SemaRef.SourceMgr.getSpellingLineNumber(Loc: ND->getBeginLoc());
2010 long LastLine =
2011 SemaRef.SourceMgr.getSpellingLineNumber(Loc: LastRoutineDecl->getBeginLoc());
2012
2013 // Do some line-number math to make sure they are within a line of eachother.
2014 // Comments or newlines can be inserted to clarify intent.
2015 if (NDLine - LastLine > 1)
2016 return;
2017
2018 // Don't warn if it actually DOES apply to this function via redecls.
2019 if (ND->getCanonicalDecl() == RoutineTarget->getCanonicalDecl())
2020 return;
2021
2022 Diag(Loc: LastRoutineDecl->getFunctionReference()->getBeginLoc(),
2023 DiagID: diag::warn_acc_confusing_routine_name);
2024 Diag(Loc: RoutineTarget->getBeginLoc(), DiagID: diag::note_previous_decl) << ND;
2025}
2026
2027void SemaOpenACC::ActOnVariableInit(VarDecl *VD, QualType InitType) {
2028 if (!VD || !getLangOpts().OpenACC || InitType.isNull())
2029 return;
2030
2031 // To avoid double-diagnostic, just diagnose this during instantiation. We'll
2032 // get 1 warning per instantiation, but this permits us to be more sensible
2033 // for cases where the lookup is confusing.
2034 if (VD->getLexicalDeclContext()->isDependentContext())
2035 return;
2036
2037 const auto *RD = InitType->getAsCXXRecordDecl();
2038 // If this isn't a lambda, no sense in diagnosing.
2039 if (!RD || !RD->isLambda())
2040 return;
2041
2042 CheckLastRoutineDeclNameConflict(ND: VD);
2043}
2044
2045void SemaOpenACC::ActOnFunctionDeclarator(FunctionDecl *FD) {
2046 if (!FD || !getLangOpts().OpenACC)
2047 return;
2048 CheckLastRoutineDeclNameConflict(ND: FD);
2049}
2050
2051bool SemaOpenACC::ActOnStartStmtDirective(
2052 OpenACCDirectiveKind K, SourceLocation StartLoc,
2053 ArrayRef<const OpenACCClause *> Clauses) {
2054
2055 // Declaration directives an appear in a statement location, so call into that
2056 // function here.
2057 if (K == OpenACCDirectiveKind::Declare || K == OpenACCDirectiveKind::Routine)
2058 return ActOnStartDeclDirective(K, StartLoc, Clauses);
2059
2060 SemaRef.DiscardCleanupsInEvaluationContext();
2061 SemaRef.PopExpressionEvaluationContext();
2062
2063 // OpenACC 3.3 2.9.1:
2064 // Intervening code must not contain other OpenACC directives or calls to API
2065 // routines.
2066 //
2067 // ALL constructs are ill-formed if there is an active 'collapse'
2068 if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
2069 Diag(Loc: StartLoc, DiagID: diag::err_acc_invalid_in_loop)
2070 << /*OpenACC Construct*/ 0 << CollapseInfo.DirectiveKind
2071 << OpenACCClauseKind::Collapse << K;
2072 assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
2073 Diag(Loc: CollapseInfo.ActiveCollapse->getBeginLoc(),
2074 DiagID: diag::note_acc_active_clause_here)
2075 << OpenACCClauseKind::Collapse;
2076 }
2077 if (TileInfo.CurTileCount && *TileInfo.CurTileCount > 0) {
2078 Diag(Loc: StartLoc, DiagID: diag::err_acc_invalid_in_loop)
2079 << /*OpenACC Construct*/ 0 << TileInfo.DirectiveKind
2080 << OpenACCClauseKind::Tile << K;
2081 assert(TileInfo.ActiveTile && "Tile count without object?");
2082 Diag(Loc: TileInfo.ActiveTile->getBeginLoc(), DiagID: diag::note_acc_active_clause_here)
2083 << OpenACCClauseKind::Tile;
2084 }
2085
2086 if (DiagnoseRequiredClauses(DK: K, DirLoc: StartLoc, Clauses))
2087 return true;
2088 return diagnoseConstructAppertainment(S&: *this, K, StartLoc, /*IsStmt=*/true);
2089}
2090
2091StmtResult SemaOpenACC::ActOnEndStmtDirective(
2092 OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation DirLoc,
2093 SourceLocation LParenLoc, SourceLocation MiscLoc, ArrayRef<Expr *> Exprs,
2094 OpenACCAtomicKind AtomicKind, SourceLocation RParenLoc,
2095 SourceLocation EndLoc, ArrayRef<OpenACCClause *> Clauses,
2096 StmtResult AssocStmt) {
2097 switch (K) {
2098 case OpenACCDirectiveKind::Invalid:
2099 return StmtError();
2100 case OpenACCDirectiveKind::Parallel:
2101 case OpenACCDirectiveKind::Serial:
2102 case OpenACCDirectiveKind::Kernels: {
2103 return OpenACCComputeConstruct::Create(
2104 C: getASTContext(), K, BeginLoc: StartLoc, DirectiveLoc: DirLoc, EndLoc, Clauses,
2105 StructuredBlock: AssocStmt.isUsable() ? AssocStmt.get() : nullptr);
2106 }
2107 case OpenACCDirectiveKind::ParallelLoop:
2108 case OpenACCDirectiveKind::SerialLoop:
2109 case OpenACCDirectiveKind::KernelsLoop: {
2110 return OpenACCCombinedConstruct::Create(
2111 C: getASTContext(), K, Start: StartLoc, DirectiveLoc: DirLoc, End: EndLoc, Clauses,
2112 StructuredBlock: AssocStmt.isUsable() ? AssocStmt.get() : nullptr);
2113 }
2114 case OpenACCDirectiveKind::Loop: {
2115 return OpenACCLoopConstruct::Create(
2116 C: getASTContext(), ParentKind: ActiveComputeConstructInfo.Kind, BeginLoc: StartLoc, DirLoc,
2117 EndLoc, Clauses, Loop: AssocStmt.isUsable() ? AssocStmt.get() : nullptr);
2118 }
2119 case OpenACCDirectiveKind::Data: {
2120 return OpenACCDataConstruct::Create(
2121 C: getASTContext(), Start: StartLoc, DirectiveLoc: DirLoc, End: EndLoc, Clauses,
2122 StructuredBlock: AssocStmt.isUsable() ? AssocStmt.get() : nullptr);
2123 }
2124 case OpenACCDirectiveKind::EnterData: {
2125 return OpenACCEnterDataConstruct::Create(C: getASTContext(), Start: StartLoc, DirectiveLoc: DirLoc,
2126 End: EndLoc, Clauses);
2127 }
2128 case OpenACCDirectiveKind::ExitData: {
2129 return OpenACCExitDataConstruct::Create(C: getASTContext(), Start: StartLoc, DirectiveLoc: DirLoc,
2130 End: EndLoc, Clauses);
2131 }
2132 case OpenACCDirectiveKind::HostData: {
2133 return OpenACCHostDataConstruct::Create(
2134 C: getASTContext(), Start: StartLoc, DirectiveLoc: DirLoc, End: EndLoc, Clauses,
2135 StructuredBlock: AssocStmt.isUsable() ? AssocStmt.get() : nullptr);
2136 }
2137 case OpenACCDirectiveKind::Wait: {
2138 return OpenACCWaitConstruct::Create(
2139 C: getASTContext(), Start: StartLoc, DirectiveLoc: DirLoc, LParenLoc, DevNumExpr: Exprs.front(), QueuesLoc: MiscLoc,
2140 QueueIdExprs: Exprs.drop_front(), RParenLoc, End: EndLoc, Clauses);
2141 }
2142 case OpenACCDirectiveKind::Init: {
2143 return OpenACCInitConstruct::Create(C: getASTContext(), Start: StartLoc, DirectiveLoc: DirLoc,
2144 End: EndLoc, Clauses);
2145 }
2146 case OpenACCDirectiveKind::Shutdown: {
2147 return OpenACCShutdownConstruct::Create(C: getASTContext(), Start: StartLoc, DirectiveLoc: DirLoc,
2148 End: EndLoc, Clauses);
2149 }
2150 case OpenACCDirectiveKind::Set: {
2151 return OpenACCSetConstruct::Create(C: getASTContext(), Start: StartLoc, DirectiveLoc: DirLoc,
2152 End: EndLoc, Clauses);
2153 }
2154 case OpenACCDirectiveKind::Update: {
2155 return OpenACCUpdateConstruct::Create(C: getASTContext(), Start: StartLoc, DirectiveLoc: DirLoc,
2156 End: EndLoc, Clauses);
2157 }
2158 case OpenACCDirectiveKind::Atomic: {
2159 return OpenACCAtomicConstruct::Create(
2160 C: getASTContext(), Start: StartLoc, DirectiveLoc: DirLoc, AtKind: AtomicKind, End: EndLoc, Clauses,
2161 AssociatedStmt: AssocStmt.isUsable() ? AssocStmt.get() : nullptr);
2162 }
2163 case OpenACCDirectiveKind::Cache: {
2164 assert(Clauses.empty() && "Cache doesn't allow clauses");
2165 return OpenACCCacheConstruct::Create(C: getASTContext(), Start: StartLoc, DirectiveLoc: DirLoc,
2166 LParenLoc, ReadOnlyLoc: MiscLoc, VarList: Exprs, RParenLoc,
2167 End: EndLoc);
2168 }
2169 case OpenACCDirectiveKind::Routine:
2170 llvm_unreachable("routine shouldn't handled here");
2171 case OpenACCDirectiveKind::Declare: {
2172 // Declare and routine arei declaration directives, but can be used here as
2173 // long as we wrap it in a DeclStmt. So make sure we do that here.
2174 DeclGroupRef DR = ActOnEndDeclDirective(K, StartLoc, DirLoc, LParenLoc,
2175 RParenLoc, EndLoc, Clauses);
2176
2177 return SemaRef.ActOnDeclStmt(Decl: DeclGroupPtrTy::make(P: DR), StartLoc, EndLoc);
2178 }
2179 }
2180 llvm_unreachable("Unhandled case in directive handling?");
2181}
2182
2183StmtResult SemaOpenACC::ActOnAssociatedStmt(
2184 SourceLocation DirectiveLoc, OpenACCDirectiveKind K,
2185 OpenACCAtomicKind AtKind, ArrayRef<const OpenACCClause *> Clauses,
2186 StmtResult AssocStmt) {
2187 switch (K) {
2188 default:
2189 llvm_unreachable("Unimplemented associated statement application");
2190 case OpenACCDirectiveKind::EnterData:
2191 case OpenACCDirectiveKind::ExitData:
2192 case OpenACCDirectiveKind::Wait:
2193 case OpenACCDirectiveKind::Init:
2194 case OpenACCDirectiveKind::Shutdown:
2195 case OpenACCDirectiveKind::Set:
2196 case OpenACCDirectiveKind::Cache:
2197 llvm_unreachable(
2198 "these don't have associated statements, so shouldn't get here");
2199 case OpenACCDirectiveKind::Atomic:
2200 return CheckAtomicAssociatedStmt(AtomicDirLoc: DirectiveLoc, AtKind, AssocStmt);
2201 case OpenACCDirectiveKind::Parallel:
2202 case OpenACCDirectiveKind::Serial:
2203 case OpenACCDirectiveKind::Kernels:
2204 case OpenACCDirectiveKind::Data:
2205 case OpenACCDirectiveKind::HostData:
2206 // There really isn't any checking here that could happen. As long as we
2207 // have a statement to associate, this should be fine.
2208 // OpenACC 3.3 Section 6:
2209 // Structured Block: in C or C++, an executable statement, possibly
2210 // compound, with a single entry at the top and a single exit at the
2211 // bottom.
2212 // FIXME: Should we reject DeclStmt's here? The standard isn't clear, and
2213 // an interpretation of it is to allow this and treat the initializer as
2214 // the 'structured block'.
2215 return AssocStmt;
2216 case OpenACCDirectiveKind::Loop:
2217 case OpenACCDirectiveKind::ParallelLoop:
2218 case OpenACCDirectiveKind::SerialLoop:
2219 case OpenACCDirectiveKind::KernelsLoop:
2220 if (!AssocStmt.isUsable())
2221 return StmtError();
2222
2223 if (!isa<CXXForRangeStmt, ForStmt>(Val: AssocStmt.get())) {
2224 Diag(Loc: AssocStmt.get()->getBeginLoc(), DiagID: diag::err_acc_loop_not_for_loop)
2225 << K;
2226 Diag(Loc: DirectiveLoc, DiagID: diag::note_acc_construct_here) << K;
2227 return StmtError();
2228 }
2229
2230 if (!CollapseInfo.CollapseDepthSatisfied || !TileInfo.TileDepthSatisfied) {
2231 if (!CollapseInfo.CollapseDepthSatisfied) {
2232 Diag(Loc: DirectiveLoc, DiagID: diag::err_acc_insufficient_loops)
2233 << OpenACCClauseKind::Collapse;
2234 assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
2235 Diag(Loc: CollapseInfo.ActiveCollapse->getBeginLoc(),
2236 DiagID: diag::note_acc_active_clause_here)
2237 << OpenACCClauseKind::Collapse;
2238 }
2239
2240 if (!TileInfo.TileDepthSatisfied) {
2241 Diag(Loc: DirectiveLoc, DiagID: diag::err_acc_insufficient_loops)
2242 << OpenACCClauseKind::Tile;
2243 assert(TileInfo.ActiveTile && "Collapse count without object?");
2244 Diag(Loc: TileInfo.ActiveTile->getBeginLoc(),
2245 DiagID: diag::note_acc_active_clause_here)
2246 << OpenACCClauseKind::Tile;
2247 }
2248 return StmtError();
2249 }
2250
2251 return AssocStmt.get();
2252 }
2253 llvm_unreachable("Invalid associated statement application");
2254}
2255
2256namespace {
2257
2258// Routine has some pretty complicated set of rules for how device_type
2259// interacts with 'gang', 'worker', 'vector', and 'seq'. Enforce part of it
2260// here.
2261bool CheckValidRoutineGangWorkerVectorSeqClauses(
2262 SemaOpenACC &SemaRef, SourceLocation DirectiveLoc,
2263 ArrayRef<const OpenACCClause *> Clauses) {
2264 auto RequiredPred = llvm::IsaPred<OpenACCGangClause, OpenACCWorkerClause,
2265 OpenACCVectorClause, OpenACCSeqClause>;
2266 // The clause handling has assured us that there is no duplicates. That is,
2267 // if there is 1 before a device_type, there are none after a device_type.
2268 // If not, there is at most 1 applying to each device_type.
2269
2270 // What is left to legalize is that either:
2271 // 1- there is 1 before the first device_type.
2272 // 2- there is 1 AFTER each device_type.
2273 auto *FirstDeviceType =
2274 llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCDeviceTypeClause>);
2275
2276 // If there is 1 before the first device_type (or at all if no device_type),
2277 // we are legal.
2278 auto *ClauseItr =
2279 std::find_if(first: Clauses.begin(), last: FirstDeviceType, pred: RequiredPred);
2280
2281 if (ClauseItr != FirstDeviceType)
2282 return false;
2283
2284 // If there IS no device_type, and no clause, diagnose.
2285 if (FirstDeviceType == Clauses.end())
2286 return SemaRef.Diag(Loc: DirectiveLoc, DiagID: diag::err_acc_construct_one_clause_of)
2287 << OpenACCDirectiveKind::Routine
2288 << "'gang', 'seq', 'vector', or 'worker'";
2289
2290 // Else, we have to check EACH device_type group. PrevDeviceType is the
2291 // device-type before the current group.
2292 auto *PrevDeviceType = FirstDeviceType;
2293
2294 while (PrevDeviceType != Clauses.end()) {
2295 auto *NextDeviceType =
2296 std::find_if(first: std::next(x: PrevDeviceType), last: Clauses.end(),
2297 pred: llvm::IsaPred<OpenACCDeviceTypeClause>);
2298
2299 ClauseItr = std::find_if(first: PrevDeviceType, last: NextDeviceType, pred: RequiredPred);
2300
2301 if (ClauseItr == NextDeviceType)
2302 return SemaRef.Diag(Loc: (*PrevDeviceType)->getBeginLoc(),
2303 DiagID: diag::err_acc_clause_routine_one_of_in_region);
2304
2305 PrevDeviceType = NextDeviceType;
2306 }
2307
2308 return false;
2309}
2310} // namespace
2311
2312bool SemaOpenACC::ActOnStartDeclDirective(
2313 OpenACCDirectiveKind K, SourceLocation StartLoc,
2314 ArrayRef<const OpenACCClause *> Clauses) {
2315 // OpenCC3.3 2.1 (line 889)
2316 // A program must not depend on the order of evaluation of expressions in
2317 // clause arguments or on any side effects of the evaluations.
2318 SemaRef.DiscardCleanupsInEvaluationContext();
2319 SemaRef.PopExpressionEvaluationContext();
2320
2321 if (DiagnoseRequiredClauses(DK: K, DirLoc: StartLoc, Clauses))
2322 return true;
2323 if (K == OpenACCDirectiveKind::Routine &&
2324 CheckValidRoutineGangWorkerVectorSeqClauses(SemaRef&: *this, DirectiveLoc: StartLoc, Clauses))
2325 return true;
2326
2327 return diagnoseConstructAppertainment(S&: *this, K, StartLoc, /*IsStmt=*/false);
2328}
2329
2330DeclGroupRef SemaOpenACC::ActOnEndDeclDirective(
2331 OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation DirLoc,
2332 SourceLocation LParenLoc, SourceLocation RParenLoc, SourceLocation EndLoc,
2333 ArrayRef<OpenACCClause *> Clauses) {
2334 switch (K) {
2335 default:
2336 case OpenACCDirectiveKind::Invalid:
2337 return DeclGroupRef{};
2338 case OpenACCDirectiveKind::Declare: {
2339 // OpenACC3.3 2.13: At least one clause must appear on a declare directive.
2340 if (Clauses.empty()) {
2341 Diag(Loc: EndLoc, DiagID: diag::err_acc_declare_required_clauses);
2342 // No reason to add this to the AST, as we would just end up trying to
2343 // instantiate this, which would double-diagnose here, which we wouldn't
2344 // want to do.
2345 return DeclGroupRef{};
2346 }
2347
2348 auto *DeclareDecl = OpenACCDeclareDecl::Create(
2349 Ctx&: getASTContext(), DC: getCurContext(), StartLoc, DirLoc, EndLoc, Clauses);
2350 DeclareDecl->setAccess(AS_public);
2351 getCurContext()->addDecl(D: DeclareDecl);
2352 return DeclGroupRef{DeclareDecl};
2353 }
2354 case OpenACCDirectiveKind::Routine:
2355 llvm_unreachable("routine shouldn't be handled here");
2356 }
2357 llvm_unreachable("unhandled case in directive handling?");
2358}
2359
2360namespace {
2361// Given the decl on the next line, figure out if it is one that is acceptable
2362// to `routine`, or looks like the sort of decl we should be diagnosing against.
2363FunctionDecl *LegalizeNextParsedDecl(Decl *D) {
2364 if (!D)
2365 return nullptr;
2366
2367 // Functions are per-fact acceptable as-is.
2368 if (auto *FD = dyn_cast<FunctionDecl>(Val: D))
2369 return FD;
2370
2371 // Function templates are functions, so attach to the templated decl.
2372 if (auto *FTD = dyn_cast<FunctionTemplateDecl>(Val: D))
2373 return FTD->getTemplatedDecl();
2374
2375 if (auto *FD = dyn_cast<FieldDecl>(Val: D)) {
2376 auto *RD =
2377 FD->getType().isNull() ? nullptr : FD->getType()->getAsCXXRecordDecl();
2378
2379 if (RD && RD->isGenericLambda())
2380 return RD->getDependentLambdaCallOperator()->getTemplatedDecl();
2381 if (RD && RD->isLambda())
2382 return RD->getLambdaCallOperator();
2383 }
2384 // VarDecl we can look at the init instead of the type of the variable, this
2385 // makes us more tolerant of the 'auto' deduced type.
2386 if (auto *VD = dyn_cast<VarDecl>(Val: D)) {
2387 Expr *Init = VD->getInit();
2388 if (!Init || Init->getType().isNull())
2389 return nullptr;
2390
2391 const auto *RD = Init->getType()->getAsCXXRecordDecl();
2392 if (RD && RD->isGenericLambda())
2393 return RD->getDependentLambdaCallOperator()->getTemplatedDecl();
2394 if (RD && RD->isLambda())
2395 return RD->getLambdaCallOperator();
2396
2397 // FIXME: We could try harder in the case where this is a dependent thing
2398 // that ends up being a lambda (that is, the init is an unresolved lookup
2399 // expr), but we can't attach to the call/lookup expr. If we instead try to
2400 // attach to the VarDecl, when we go to instantiate it, attributes are
2401 // instantiated before the init, so we can't actually see the type at any
2402 // point where it would be relevant/able to be checked. We could perhaps do
2403 // some sort of 'after-init' instantiation/checking here, but that doesn't
2404 // seem valuable for a situation that other compilers don't handle.
2405 }
2406 return nullptr;
2407}
2408
2409void CreateRoutineDeclAttr(SemaOpenACC &SemaRef, SourceLocation DirLoc,
2410 ArrayRef<const OpenACCClause *> Clauses,
2411 ValueDecl *AddTo) {
2412 OpenACCRoutineDeclAttr *A =
2413 OpenACCRoutineDeclAttr::Create(Ctx&: SemaRef.getASTContext(), Range: DirLoc);
2414 A->Clauses.assign(in_start: Clauses.begin(), in_end: Clauses.end());
2415 AddTo->addAttr(A);
2416}
2417} // namespace
2418
2419// Variant that adds attributes, because this is the unnamed case.
2420void SemaOpenACC::CheckRoutineDecl(SourceLocation DirLoc,
2421 ArrayRef<const OpenACCClause *> Clauses,
2422 Decl *NextParsedDecl) {
2423
2424 FunctionDecl *NextParsedFDecl = LegalizeNextParsedDecl(D: NextParsedDecl);
2425
2426 if (!NextParsedFDecl) {
2427 // If we don't have a valid 'next thing', just diagnose.
2428 SemaRef.Diag(Loc: DirLoc, DiagID: diag::err_acc_decl_for_routine);
2429 return;
2430 }
2431
2432 // OpenACC 3.3 2.15:
2433 // In C and C++, function static variables are not supported in functions to
2434 // which a routine directive applies.
2435 if (auto Itr = MagicStaticLocs.find(Val: NextParsedFDecl->getCanonicalDecl());
2436 Itr != MagicStaticLocs.end()) {
2437 Diag(Loc: Itr->second, DiagID: diag::err_acc_magic_static_in_routine);
2438 Diag(Loc: DirLoc, DiagID: diag::note_acc_construct_here)
2439 << OpenACCDirectiveKind::Routine;
2440
2441 return;
2442 }
2443
2444 auto BindItr = llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCBindClause>);
2445 if (BindItr != Clauses.end()) {
2446 for (auto *A : NextParsedFDecl->attrs()) {
2447 // OpenACC 3.3 2.15:
2448 // If a procedure has a bind clause on both the declaration and definition
2449 // than they both must bind to the same name.
2450 if (auto *RA = dyn_cast<OpenACCRoutineDeclAttr>(Val: A)) {
2451 auto OtherBindItr =
2452 llvm::find_if(Range&: RA->Clauses, P: llvm::IsaPred<OpenACCBindClause>);
2453 if (OtherBindItr != RA->Clauses.end() &&
2454 (*cast<OpenACCBindClause>(Val: *BindItr)) !=
2455 (*cast<OpenACCBindClause>(Val: *OtherBindItr))) {
2456 Diag(Loc: (*BindItr)->getBeginLoc(), DiagID: diag::err_acc_duplicate_unnamed_bind);
2457 Diag(Loc: (*OtherBindItr)->getEndLoc(),
2458 DiagID: diag::note_acc_previous_clause_here)
2459 << (*BindItr)->getClauseKind();
2460 return;
2461 }
2462 }
2463
2464 // OpenACC 3.3 2.15:
2465 // A bind clause may not bind to a routine name that has a visible bind
2466 // clause.
2467 // We take the combo of these two 2.15 restrictions to mean that the
2468 // 'declaration'/'definition' quote is an exception to this. So we're
2469 // going to disallow mixing of the two types entirely.
2470 if (auto *RA = dyn_cast<OpenACCRoutineAnnotAttr>(Val: A);
2471 RA && RA->getRange().getEnd().isValid()) {
2472 Diag(Loc: (*BindItr)->getBeginLoc(), DiagID: diag::err_acc_duplicate_bind);
2473 Diag(Loc: RA->getRange().getEnd(), DiagID: diag::note_acc_previous_clause_here)
2474 << "bind";
2475 return;
2476 }
2477 }
2478 }
2479
2480 CreateRoutineDeclAttr(SemaRef&: *this, DirLoc, Clauses, AddTo: NextParsedFDecl);
2481}
2482
2483// Variant that adds a decl, because this is the named case.
2484OpenACCRoutineDecl *SemaOpenACC::CheckRoutineDecl(
2485 SourceLocation StartLoc, SourceLocation DirLoc, SourceLocation LParenLoc,
2486 Expr *FuncRef, SourceLocation RParenLoc,
2487 ArrayRef<const OpenACCClause *> Clauses, SourceLocation EndLoc) {
2488 assert(LParenLoc.isValid());
2489
2490 FunctionDecl *FD = nullptr;
2491 if ((FD = getFunctionFromRoutineName(RoutineName: FuncRef))) {
2492 // OpenACC 3.3 2.15:
2493 // In C and C++, function static variables are not supported in functions to
2494 // which a routine directive applies.
2495 if (auto Itr = MagicStaticLocs.find(Val: FD->getCanonicalDecl());
2496 Itr != MagicStaticLocs.end()) {
2497 Diag(Loc: Itr->second, DiagID: diag::err_acc_magic_static_in_routine);
2498 Diag(Loc: DirLoc, DiagID: diag::note_acc_construct_here)
2499 << OpenACCDirectiveKind::Routine;
2500
2501 return nullptr;
2502 }
2503
2504 // OpenACC 3.3 2.15:
2505 // A bind clause may not bind to a routine name that has a visible bind
2506 // clause.
2507 auto BindItr = llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OpenACCBindClause>);
2508 SourceLocation BindLoc;
2509 if (BindItr != Clauses.end()) {
2510 BindLoc = (*BindItr)->getBeginLoc();
2511 // Since this is adding a 'named' routine, we aren't allowed to combine
2512 // with ANY other visible bind clause. Error if we see either.
2513
2514 for (auto *A : FD->attrs()) {
2515 if (auto *RA = dyn_cast<OpenACCRoutineDeclAttr>(Val: A)) {
2516 auto OtherBindItr =
2517 llvm::find_if(Range&: RA->Clauses, P: llvm::IsaPred<OpenACCBindClause>);
2518 if (OtherBindItr != RA->Clauses.end()) {
2519 Diag(Loc: (*BindItr)->getBeginLoc(), DiagID: diag::err_acc_duplicate_bind);
2520 Diag(Loc: (*OtherBindItr)->getEndLoc(),
2521 DiagID: diag::note_acc_previous_clause_here)
2522 << (*BindItr)->getClauseKind();
2523 return nullptr;
2524 }
2525 }
2526
2527 if (auto *RA = dyn_cast<OpenACCRoutineAnnotAttr>(Val: A);
2528 RA && RA->getRange().getEnd().isValid()) {
2529 Diag(Loc: (*BindItr)->getBeginLoc(), DiagID: diag::err_acc_duplicate_bind);
2530 Diag(Loc: RA->getRange().getEnd(), DiagID: diag::note_acc_previous_clause_here)
2531 << (*BindItr)->getClauseKind();
2532 return nullptr;
2533 }
2534 }
2535 }
2536
2537 // Set the end-range to the 'bind' clause here, so we can look it up
2538 // later.
2539 auto *RAA = OpenACCRoutineAnnotAttr::CreateImplicit(Ctx&: getASTContext(),
2540 Range: {DirLoc, BindLoc});
2541 FD->addAttr(A: RAA);
2542 // In case we are referencing not the 'latest' version, make sure we add
2543 // the attribute to all declarations after the 'found' one.
2544 for (auto *CurFD : FD->redecls())
2545 CurFD->addAttr(A: RAA->clone(C&: getASTContext()));
2546 }
2547
2548 LastRoutineDecl = OpenACCRoutineDecl::Create(
2549 Ctx&: getASTContext(), DC: getCurContext(), StartLoc, DirLoc, LParenLoc, FuncRef,
2550 RParenLoc, EndLoc, Clauses);
2551 LastRoutineDecl->setAccess(AS_public);
2552 getCurContext()->addDecl(D: LastRoutineDecl);
2553
2554 if (FD) {
2555 // Add this attribute to the list of annotations so that codegen can visit
2556 // it later. FD doesn't necessarily exist, but that case should be
2557 // diagnosed.
2558 RoutineRefList.emplace_back(Args&: FD, Args&: LastRoutineDecl);
2559 }
2560 return LastRoutineDecl;
2561}
2562
2563void SemaOpenACC::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) {
2564 for (auto [FD, RoutineDecl] : RoutineRefList)
2565 SemaRef.Consumer.HandleOpenACCRoutineReference(FD, RD: RoutineDecl);
2566}
2567
2568DeclGroupRef SemaOpenACC::ActOnEndRoutineDeclDirective(
2569 SourceLocation StartLoc, SourceLocation DirLoc, SourceLocation LParenLoc,
2570 Expr *ReferencedFunc, SourceLocation RParenLoc,
2571 ArrayRef<const OpenACCClause *> Clauses, SourceLocation EndLoc,
2572 DeclGroupPtrTy NextDecl) {
2573 assert((!ReferencedFunc || !NextDecl) &&
2574 "Only one of these should be filled");
2575
2576 if (LParenLoc.isInvalid()) {
2577 Decl *NextLineDecl = nullptr;
2578 if (NextDecl && NextDecl.get().isSingleDecl())
2579 NextLineDecl = NextDecl.get().getSingleDecl();
2580
2581 CheckRoutineDecl(DirLoc, Clauses, NextParsedDecl: NextLineDecl);
2582
2583 return NextDecl.get();
2584 }
2585
2586 return DeclGroupRef{CheckRoutineDecl(
2587 StartLoc, DirLoc, LParenLoc, FuncRef: ReferencedFunc, RParenLoc, Clauses, EndLoc)};
2588}
2589
2590StmtResult SemaOpenACC::ActOnEndRoutineStmtDirective(
2591 SourceLocation StartLoc, SourceLocation DirLoc, SourceLocation LParenLoc,
2592 Expr *ReferencedFunc, SourceLocation RParenLoc,
2593 ArrayRef<const OpenACCClause *> Clauses, SourceLocation EndLoc,
2594 Stmt *NextStmt) {
2595 assert((!ReferencedFunc || !NextStmt) &&
2596 "Only one of these should be filled");
2597
2598 if (LParenLoc.isInvalid()) {
2599 Decl *NextLineDecl = nullptr;
2600 if (NextStmt)
2601 if (DeclStmt *DS = dyn_cast<DeclStmt>(Val: NextStmt); DS && DS->isSingleDecl())
2602 NextLineDecl = DS->getSingleDecl();
2603
2604 CheckRoutineDecl(DirLoc, Clauses, NextParsedDecl: NextLineDecl);
2605 return NextStmt;
2606 }
2607
2608 DeclGroupRef DR{CheckRoutineDecl(StartLoc, DirLoc, LParenLoc, FuncRef: ReferencedFunc,
2609 RParenLoc, Clauses, EndLoc)};
2610 return SemaRef.ActOnDeclStmt(Decl: DeclGroupPtrTy::make(P: DR), StartLoc, EndLoc);
2611}
2612
2613OpenACCRoutineDeclAttr *
2614SemaOpenACC::mergeRoutineDeclAttr(const OpenACCRoutineDeclAttr &Old) {
2615 OpenACCRoutineDeclAttr *New =
2616 OpenACCRoutineDeclAttr::Create(Ctx&: getASTContext(), Range: Old.getLocation());
2617 // We should jsut be able to copy these, there isn't really any
2618 // merging/inheriting we have to do, so no worry about doing a deep copy.
2619 New->Clauses = Old.Clauses;
2620 return New;
2621}
2622ExprResult
2623SemaOpenACC::BuildOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) {
2624 return OpenACCAsteriskSizeExpr::Create(C: getASTContext(), Loc: AsteriskLoc);
2625}
2626
2627ExprResult
2628SemaOpenACC::ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) {
2629 return BuildOpenACCAsteriskSizeExpr(AsteriskLoc);
2630}
2631
2632namespace {
2633enum class InitKind { Invalid, Zero, One, AllOnes, Least, Largest };
2634llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) {
2635 switch (IK) {
2636 case InitKind::Invalid:
2637 llvm_unreachable("invalid init kind");
2638 case InitKind::Zero:
2639 return llvm::APFloat::getZero(Sem: Context.getFloatTypeSemantics(T: Ty));
2640 case InitKind::One:
2641 return llvm::APFloat::getOne(Sem: Context.getFloatTypeSemantics(T: Ty));
2642 case InitKind::AllOnes:
2643 return llvm::APFloat::getAllOnesValue(Semantics: Context.getFloatTypeSemantics(T: Ty));
2644 case InitKind::Least:
2645 return llvm::APFloat::getLargest(Sem: Context.getFloatTypeSemantics(T: Ty),
2646 /*Negative=*/true);
2647 case InitKind::Largest:
2648 return llvm::APFloat::getLargest(Sem: Context.getFloatTypeSemantics(T: Ty));
2649 }
2650 llvm_unreachable("unknown init kind");
2651}
2652
2653llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
2654 switch (IK) {
2655 case InitKind::Invalid:
2656 llvm_unreachable("invalid init kind");
2657 case InitKind::Zero:
2658 return llvm::APInt(Context.getIntWidth(T: Ty), 0);
2659 case InitKind::One:
2660 return llvm::APInt(Context.getIntWidth(T: Ty), 1);
2661 case InitKind::AllOnes:
2662 return llvm::APInt::getAllOnes(numBits: Context.getIntWidth(T: Ty));
2663 case InitKind::Least:
2664 if (Ty->isSignedIntegerOrEnumerationType())
2665 return llvm::APInt::getSignedMinValue(numBits: Context.getIntWidth(T: Ty));
2666 return llvm::APInt::getMinValue(numBits: Context.getIntWidth(T: Ty));
2667 case InitKind::Largest:
2668 if (Ty->isSignedIntegerOrEnumerationType())
2669 return llvm::APInt::getSignedMaxValue(numBits: Context.getIntWidth(T: Ty));
2670 return llvm::APInt::getMaxValue(numBits: Context.getIntWidth(T: Ty));
2671 }
2672 llvm_unreachable("unknown init kind");
2673}
2674
2675/// Loops through a type and generates an appropriate InitListExpr to
2676/// generate type initialization.
2677Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
2678 SourceRange ExprRange, QualType Ty,
2679 InitKind IK) {
2680 if (IK == InitKind::Invalid)
2681 return nullptr;
2682
2683 if (IK == InitKind::Zero) {
2684 Expr *InitExpr =
2685 new (Context) InitListExpr(Context, ExprRange.getBegin(), {},
2686 ExprRange.getEnd(), /*isExplicit=*/false);
2687 InitExpr->setType(Context.VoidTy);
2688 return InitExpr;
2689 }
2690
2691 Ty = Ty.getCanonicalType();
2692 llvm::SmallVector<Expr *> Exprs;
2693
2694 if (const RecordDecl *RD = Ty->getAsRecordDecl()) {
2695 for (auto *F : RD->fields()) {
2696 if (Expr *NewExpr = GenerateReductionInitRecipeExpr(Context, ExprRange,
2697 Ty: F->getType(), IK))
2698 Exprs.push_back(Elt: NewExpr);
2699 else
2700 return nullptr;
2701 }
2702 } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T: Ty)) {
2703 for (uint64_t Idx = 0; Idx < AT->getZExtSize(); ++Idx) {
2704 if (Expr *NewExpr = GenerateReductionInitRecipeExpr(
2705 Context, ExprRange, Ty: AT->getElementType(), IK))
2706 Exprs.push_back(Elt: NewExpr);
2707 else
2708 return nullptr;
2709 }
2710
2711 } else if (Ty->isPointerType()) {
2712 // For now, we are going to punt/not initialize pointer types, as
2713 // discussions/designs are ongoing on how to express this behavior,
2714 // particularly since they probably need the 'bounds' passed to them
2715 // correctly. A future patch/patch set will go through all of the pointer
2716 // values for all of the recipes to make sure we have a sane behavior.
2717
2718 // For now, this will result in a NYI during code generation for
2719 // no-initializer.
2720 return nullptr;
2721 } else {
2722 assert(Ty->isScalarType());
2723
2724 if (const auto *Cplx = Ty->getAs<ComplexType>()) {
2725 // we can get here in error cases, so make sure we generate something that
2726 // will work if we find ourselves wanting to enable this, so emit '0,0'
2727 // for both ints and floats.
2728
2729 QualType EltTy = Cplx->getElementType();
2730 if (EltTy->isFloatingType()) {
2731 Exprs.push_back(Elt: FloatingLiteral::Create(
2732 C: Context, V: getInitFloatValue(Context, IK: InitKind::Zero, Ty: EltTy),
2733 /*isExact=*/isexact: true, Type: EltTy, L: ExprRange.getBegin()));
2734 Exprs.push_back(Elt: FloatingLiteral::Create(
2735 C: Context, V: getInitFloatValue(Context, IK: InitKind::Zero, Ty: EltTy),
2736 /*isExact=*/isexact: true, Type: EltTy, L: ExprRange.getBegin()));
2737 } else {
2738 Exprs.push_back(Elt: IntegerLiteral::Create(
2739 C: Context, V: getInitIntValue(Context, IK: InitKind::Zero, Ty: EltTy), type: EltTy,
2740 l: ExprRange.getBegin()));
2741 Exprs.push_back(Elt: IntegerLiteral::Create(
2742 C: Context, V: getInitIntValue(Context, IK: InitKind::Zero, Ty: EltTy), type: EltTy,
2743 l: ExprRange.getBegin()));
2744 }
2745
2746 } else if (Ty->isFloatingType()) {
2747 Exprs.push_back(
2748 Elt: FloatingLiteral::Create(C: Context, V: getInitFloatValue(Context, IK, Ty),
2749 /*isExact=*/isexact: true, Type: Ty, L: ExprRange.getBegin()));
2750 } else if (Ty->isBooleanType()) {
2751 Exprs.push_back(Elt: CXXBoolLiteralExpr::Create(C: Context,
2752 Val: (IK == InitKind::One ||
2753 IK == InitKind::AllOnes ||
2754 IK == InitKind::Largest),
2755 Ty, Loc: ExprRange.getBegin()));
2756 } else if (Ty->isNullPtrType()) {
2757 Exprs.push_back(Elt: new (Context)
2758 CXXNullPtrLiteralExpr(Ty, ExprRange.getBegin()));
2759 } else {
2760 Exprs.push_back(Elt: IntegerLiteral::Create(
2761 C: Context, V: getInitIntValue(Context, IK, Ty), type: Ty, l: ExprRange.getBegin()));
2762 }
2763 }
2764
2765 Expr *InitExpr =
2766 new (Context) InitListExpr(Context, ExprRange.getBegin(), Exprs,
2767 ExprRange.getEnd(), /*isExplicit=*/false);
2768 InitExpr->setType(Ty);
2769 return InitExpr;
2770}
2771
2772VarDecl *CreateAllocaDecl(ASTContext &Ctx, DeclContext *DC,
2773 SourceLocation BeginLoc, IdentifierInfo *VarName,
2774 QualType VarTy) {
2775 auto *VD = VarDecl::Create(C&: Ctx, DC, StartLoc: BeginLoc, IdLoc: BeginLoc, Id: VarName, T: VarTy,
2776 TInfo: Ctx.getTrivialTypeSourceInfo(T: VarTy), S: SC_Auto);
2777 VD->markUsed(C&: Ctx);
2778 return VD;
2779}
2780
2781ExprResult FinishValueInit(Sema &S, InitializedEntity &Entity,
2782 SourceLocation Loc, QualType VarTy, Expr *InitExpr) {
2783 if (!InitExpr)
2784 return ExprEmpty();
2785
2786 InitializationKind Kind =
2787 InitializationKind::CreateForInit(Loc, /*DirectInit=*/true, Init: InitExpr);
2788 InitializationSequence InitSeq(S, Entity, Kind, InitExpr,
2789 /*TopLevelOfInitList=*/false,
2790 /*TreatUnavailableAsInvalid=*/false);
2791
2792 return InitSeq.Perform(S, Entity, Kind, Args: InitExpr, ResultType: &VarTy);
2793}
2794
2795} // namespace
2796
2797OpenACCPrivateRecipe SemaOpenACC::CreatePrivateInitRecipe(const Expr *VarExpr) {
2798 // We don't strip bounds here, so that we are doing our recipe init at the
2799 // 'lowest' possible level. Codegen is going to have to do its own 'looping'.
2800 if (!VarExpr || VarExpr->getType()->isDependentType())
2801 return OpenACCPrivateRecipe::Empty();
2802
2803 QualType VarTy =
2804 VarExpr->getType().getNonReferenceType().getUnqualifiedType();
2805
2806 // Array sections are special, and we have to treat them that way.
2807 if (const auto *ASE =
2808 dyn_cast<ArraySectionExpr>(Val: VarExpr->IgnoreParenImpCasts()))
2809 VarTy = ASE->getElementType();
2810
2811 VarDecl *AllocaDecl = CreateAllocaDecl(
2812 Ctx&: getASTContext(), DC: SemaRef.getCurContext(), BeginLoc: VarExpr->getBeginLoc(),
2813 VarName: &getASTContext().Idents.get(Name: "openacc.private.init"), VarTy);
2814
2815 Sema::TentativeAnalysisScope Trap{SemaRef};
2816 InitializedEntity Entity = InitializedEntity::InitializeVariable(Var: AllocaDecl);
2817 InitializationKind Kind =
2818 InitializationKind::CreateDefault(InitLoc: AllocaDecl->getLocation());
2819 InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {});
2820 ExprResult Init = InitSeq.Perform(S&: SemaRef.SemaRef, Entity, Kind, Args: {});
2821
2822 // For 'no bounds' version, we can use this as a shortcut, so set the init
2823 // anyway.
2824 if (Init.isUsable()) {
2825 AllocaDecl->setInit(Init.get());
2826 AllocaDecl->setInitStyle(VarDecl::CallInit);
2827 }
2828
2829 return OpenACCPrivateRecipe(AllocaDecl);
2830}
2831
2832OpenACCFirstPrivateRecipe
2833SemaOpenACC::CreateFirstPrivateInitRecipe(const Expr *VarExpr) {
2834 // We don't strip bounds here, so that we are doing our recipe init at the
2835 // 'lowest' possible level. Codegen is going to have to do its own 'looping'.
2836 if (!VarExpr || VarExpr->getType()->isDependentType())
2837 return OpenACCFirstPrivateRecipe::Empty();
2838
2839 QualType VarTy =
2840 VarExpr->getType().getNonReferenceType().getUnqualifiedType();
2841
2842 // Array sections are special, and we have to treat them that way.
2843 if (const auto *ASE =
2844 dyn_cast<ArraySectionExpr>(Val: VarExpr->IgnoreParenImpCasts()))
2845 VarTy = ASE->getElementType();
2846
2847 VarDecl *AllocaDecl = CreateAllocaDecl(
2848 Ctx&: getASTContext(), DC: SemaRef.getCurContext(), BeginLoc: VarExpr->getBeginLoc(),
2849 VarName: &getASTContext().Idents.get(Name: "openacc.firstprivate.init"), VarTy);
2850
2851 VarDecl *Temporary = CreateAllocaDecl(
2852 Ctx&: getASTContext(), DC: SemaRef.getCurContext(), BeginLoc: VarExpr->getBeginLoc(),
2853 VarName: &getASTContext().Idents.get(Name: "openacc.temp"), VarTy);
2854
2855 auto *TemporaryDRE = DeclRefExpr::Create(
2856 Context: getASTContext(), QualifierLoc: NestedNameSpecifierLoc{}, TemplateKWLoc: SourceLocation{}, D: Temporary,
2857 /*ReferstoEnclosingVariableOrCapture=*/RefersToEnclosingVariableOrCapture: false,
2858 NameInfo: DeclarationNameInfo{DeclarationName{Temporary->getDeclName()},
2859 VarExpr->getBeginLoc()},
2860 T: VarTy, VK: clang::VK_LValue, FoundD: Temporary, TemplateArgs: nullptr, NOUR: NOUR_None);
2861
2862 Sema::TentativeAnalysisScope Trap{SemaRef};
2863 InitializedEntity Entity = InitializedEntity::InitializeVariable(Var: AllocaDecl);
2864
2865 const auto *ArrTy = getASTContext().getAsConstantArrayType(T: VarTy);
2866 if (!ArrTy) {
2867 ExprResult Init = FinishValueInit(
2868 S&: SemaRef.SemaRef, Entity, Loc: VarExpr->getBeginLoc(), VarTy, InitExpr: TemporaryDRE);
2869
2870 // For 'no bounds' version, we can use this as a shortcut, so set the init
2871 // anyway.
2872 if (Init.isUsable()) {
2873 AllocaDecl->setInit(Init.get());
2874 AllocaDecl->setInitStyle(VarDecl::CallInit);
2875 }
2876 return OpenACCFirstPrivateRecipe(AllocaDecl, Temporary);
2877 }
2878
2879 // Arrays need to have each individual element initialized as there
2880 // isn't a normal 'equals' feature in C/C++. This section sets these up
2881 // as an init list after 'initializing' each individual element.
2882 llvm::SmallVector<Expr *> Args;
2883 // Decay to pointer for the array subscript expression.
2884 auto *CastToPtr = ImplicitCastExpr::Create(
2885 Context: getASTContext(), T: getASTContext().getPointerType(T: ArrTy->getElementType()),
2886 Kind: CK_ArrayToPointerDecay, Operand: TemporaryDRE, /*BasePath=*/nullptr,
2887 Cat: clang::VK_LValue, FPO: FPOptionsOverride{});
2888
2889 for (std::size_t I = 0; I < ArrTy->getLimitedSize(); ++I) {
2890 // Each element needs to be some sort of copy initialization from an
2891 // array-index of the original temporary (referenced via a
2892 // DeclRefExpr).
2893 auto *Idx = IntegerLiteral::Create(
2894 C: getASTContext(),
2895 V: llvm::APInt(getASTContext().getTypeSize(T: getASTContext().getSizeType()),
2896 I),
2897 type: getASTContext().getSizeType(), l: VarExpr->getBeginLoc());
2898
2899 Expr *Subscript = new (getASTContext()) ArraySubscriptExpr(
2900 CastToPtr, Idx, ArrTy->getElementType(), clang::VK_LValue, OK_Ordinary,
2901 VarExpr->getBeginLoc());
2902 // Generate a simple copy from the result of the subscript. This will
2903 // do a bitwise copy or a copy-constructor, as necessary.
2904 InitializedEntity CopyEntity =
2905 InitializedEntity::InitializeElement(Context&: getASTContext(), Index: I, Parent: Entity);
2906 InitializationKind CopyKind =
2907 InitializationKind::CreateCopy(InitLoc: VarExpr->getBeginLoc(), EqualLoc: {});
2908 InitializationSequence CopySeq(SemaRef.SemaRef, CopyEntity, CopyKind,
2909 Subscript,
2910 /*TopLevelOfInitList=*/true);
2911 ExprResult ElemRes =
2912 CopySeq.Perform(S&: SemaRef.SemaRef, Entity: CopyEntity, Kind: CopyKind, Args: Subscript);
2913 Args.push_back(Elt: ElemRes.get());
2914 }
2915
2916 Expr *InitExpr = new (getASTContext())
2917 InitListExpr(getASTContext(), VarExpr->getBeginLoc(), Args,
2918 VarExpr->getEndLoc(), /*isExplicit=*/false);
2919 InitExpr->setType(VarTy);
2920
2921 ExprResult Init = FinishValueInit(S&: SemaRef.SemaRef, Entity,
2922 Loc: VarExpr->getBeginLoc(), VarTy, InitExpr);
2923
2924 // For 'no bounds' version, we can use this as a shortcut, so set the init
2925 // anyway.
2926 if (Init.isUsable()) {
2927 AllocaDecl->setInit(Init.get());
2928 AllocaDecl->setInitStyle(VarDecl::CallInit);
2929 }
2930
2931 return OpenACCFirstPrivateRecipe(AllocaDecl, Temporary);
2932}
2933
2934OpenACCReductionRecipeWithStorage SemaOpenACC::CreateReductionInitRecipe(
2935 OpenACCReductionOperator ReductionOperator, const Expr *VarExpr) {
2936 // We don't strip bounds here, so that we are doing our recipe init at the
2937 // 'lowest' possible level. Codegen is going to have to do its own 'looping'.
2938 if (!VarExpr || VarExpr->getType()->isDependentType())
2939 return OpenACCReductionRecipeWithStorage::Empty();
2940
2941 QualType VarTy =
2942 VarExpr->getType().getNonReferenceType().getUnqualifiedType();
2943
2944 // Array sections are special, and we have to treat them that way.
2945 if (const auto *ASE =
2946 dyn_cast<ArraySectionExpr>(Val: VarExpr->IgnoreParenImpCasts()))
2947 VarTy = ASE->getElementType();
2948
2949 llvm::SmallVector<OpenACCReductionRecipe::CombinerRecipe, 1> CombinerRecipes;
2950
2951 // We use the 'set-ness' of the alloca-decl to determine whether the combiner
2952 // is 'set' or not, so we can skip any attempts at it if we're going to fail
2953 // at any of the combiners.
2954 if (CreateReductionCombinerRecipe(loc: VarExpr->getBeginLoc(), ReductionOperator,
2955 VarTy, CombinerRecipes))
2956 return OpenACCReductionRecipeWithStorage::Empty();
2957
2958 VarDecl *AllocaDecl = CreateAllocaDecl(
2959 Ctx&: getASTContext(), DC: SemaRef.getCurContext(), BeginLoc: VarExpr->getBeginLoc(),
2960 VarName: &getASTContext().Idents.get(Name: "openacc.reduction.init"), VarTy);
2961
2962 Sema::TentativeAnalysisScope Trap{SemaRef};
2963 InitializedEntity Entity = InitializedEntity::InitializeVariable(Var: AllocaDecl);
2964
2965 InitKind IK = InitKind::Invalid;
2966 switch (ReductionOperator) {
2967 case OpenACCReductionOperator::Invalid:
2968 // This can only happen when there is an error, and since these inits
2969 // are used for code generation, we can just ignore/not bother doing any
2970 // initialization here.
2971 IK = InitKind::Invalid;
2972 break;
2973 case OpenACCReductionOperator::Max:
2974 IK = InitKind::Least;
2975 break;
2976 case OpenACCReductionOperator::Min:
2977 IK = InitKind::Largest;
2978 break;
2979 case OpenACCReductionOperator::BitwiseAnd:
2980 IK = InitKind::AllOnes;
2981 break;
2982 case OpenACCReductionOperator::Multiplication:
2983 case OpenACCReductionOperator::And:
2984 IK = InitKind::One;
2985 break;
2986 case OpenACCReductionOperator::Addition:
2987 case OpenACCReductionOperator::BitwiseOr:
2988 case OpenACCReductionOperator::BitwiseXOr:
2989 case OpenACCReductionOperator::Or:
2990 IK = InitKind::Zero;
2991 break;
2992 }
2993
2994 Expr *InitExpr = GenerateReductionInitRecipeExpr(
2995 Context&: getASTContext(), ExprRange: VarExpr->getSourceRange(), Ty: VarTy, IK);
2996
2997 ExprResult Init = FinishValueInit(S&: SemaRef.SemaRef, Entity,
2998 Loc: VarExpr->getBeginLoc(), VarTy, InitExpr);
2999
3000 // For 'no bounds' version, we can use this as a shortcut, so set the init
3001 // anyway.
3002 if (Init.isUsable()) {
3003 AllocaDecl->setInit(Init.get());
3004 AllocaDecl->setInitStyle(VarDecl::CallInit);
3005 }
3006
3007 return OpenACCReductionRecipeWithStorage(AllocaDecl, CombinerRecipes);
3008}
3009
3010bool SemaOpenACC::CreateReductionCombinerRecipe(
3011 SourceLocation Loc, OpenACCReductionOperator ReductionOperator,
3012 QualType VarTy,
3013 llvm::SmallVectorImpl<OpenACCReductionRecipe::CombinerRecipe>
3014 &CombinerRecipes) {
3015 // Now we can try to generate the 'combiner' recipe. This is a little
3016 // complicated in that if the 'VarTy' is an array type, we want to take its
3017 // element type so we can generate that. Additionally, if this is a struct,
3018 // we have two options: If there is overloaded operators, we want to take
3019 // THOSE, else we want to do the individual elements.
3020
3021 BinaryOperatorKind BinOp;
3022 switch (ReductionOperator) {
3023 case OpenACCReductionOperator::Invalid:
3024 // This can only happen when there is an error, and since these inits
3025 // are used for code generation, we can just ignore/not bother doing any
3026 // initialization here.
3027 CombinerRecipes.push_back(Elt: {.LHS: nullptr, .RHS: nullptr, .Op: nullptr});
3028 return false;
3029 case OpenACCReductionOperator::Addition:
3030 BinOp = BinaryOperatorKind::BO_AddAssign;
3031 break;
3032 case OpenACCReductionOperator::Multiplication:
3033 BinOp = BinaryOperatorKind::BO_MulAssign;
3034 break;
3035 case OpenACCReductionOperator::BitwiseAnd:
3036 BinOp = BinaryOperatorKind::BO_AndAssign;
3037 break;
3038 case OpenACCReductionOperator::BitwiseOr:
3039 BinOp = BinaryOperatorKind::BO_OrAssign;
3040 break;
3041 case OpenACCReductionOperator::BitwiseXOr:
3042 BinOp = BinaryOperatorKind::BO_XorAssign;
3043 break;
3044
3045 case OpenACCReductionOperator::Max:
3046 case OpenACCReductionOperator::Min:
3047 BinOp = BinaryOperatorKind::BO_LT;
3048 break;
3049 case OpenACCReductionOperator::And:
3050 BinOp = BinaryOperatorKind::BO_LAnd;
3051 break;
3052 case OpenACCReductionOperator::Or:
3053 BinOp = BinaryOperatorKind::BO_LOr;
3054 break;
3055 }
3056
3057 // If VarTy is an array type, at the top level only, we want to do our
3058 // compares/decomp/etc at the element level.
3059 if (auto *AT = getASTContext().getAsArrayType(T: VarTy))
3060 VarTy = AT->getElementType();
3061
3062 assert(!VarTy->isArrayType() && "Only 1 level of array allowed");
3063
3064 enum class CombinerFailureKind {
3065 None = 0,
3066 BinOp = 1,
3067 Conditional = 2,
3068 Assignment = 3,
3069 };
3070
3071 auto genCombiner = [&, this](DeclRefExpr *LHSDRE, DeclRefExpr *RHSDRE)
3072 -> std::pair<ExprResult, CombinerFailureKind> {
3073 ExprResult BinOpRes =
3074 SemaRef.BuildBinOp(S: SemaRef.getCurScope(), OpLoc: Loc, Opc: BinOp, LHSExpr: LHSDRE, RHSExpr: RHSDRE,
3075 /*ForFoldExpr=*/ForFoldExpression: false);
3076 switch (ReductionOperator) {
3077 case OpenACCReductionOperator::Addition:
3078 case OpenACCReductionOperator::Multiplication:
3079 case OpenACCReductionOperator::BitwiseAnd:
3080 case OpenACCReductionOperator::BitwiseOr:
3081 case OpenACCReductionOperator::BitwiseXOr:
3082 // These 5 are simple and are being done as compound operators, so we can
3083 // immediately quit here.
3084 return {BinOpRes, BinOpRes.isUsable() ? CombinerFailureKind::None
3085 : CombinerFailureKind::BinOp};
3086 case OpenACCReductionOperator::Max:
3087 case OpenACCReductionOperator::Min: {
3088 // These are done as:
3089 // LHS = (LHS < RHS) ? LHS : RHS; and LHS = (LHS < RHS) ? RHS : LHS;
3090 //
3091 // The BinOpRes should have been created with the less-than, so we just
3092 // have to build the conditional and assignment.
3093 if (!BinOpRes.isUsable())
3094 return {BinOpRes, CombinerFailureKind::BinOp};
3095
3096 // Create the correct conditional operator, swapping the results
3097 // (true/false value) depending on min/max.
3098 ExprResult CondRes;
3099 if (ReductionOperator == OpenACCReductionOperator::Min)
3100 CondRes = SemaRef.ActOnConditionalOp(QuestionLoc: Loc, ColonLoc: Loc, CondExpr: BinOpRes.get(), LHSExpr: LHSDRE,
3101 RHSExpr: RHSDRE);
3102 else
3103 CondRes = SemaRef.ActOnConditionalOp(QuestionLoc: Loc, ColonLoc: Loc, CondExpr: BinOpRes.get(), LHSExpr: RHSDRE,
3104 RHSExpr: LHSDRE);
3105
3106 if (!CondRes.isUsable())
3107 return {CondRes, CombinerFailureKind::Conditional};
3108
3109 // Build assignment.
3110 ExprResult Assignment = SemaRef.BuildBinOp(S: SemaRef.getCurScope(), OpLoc: Loc,
3111 Opc: BinaryOperatorKind::BO_Assign,
3112 LHSExpr: LHSDRE, RHSExpr: CondRes.get(),
3113 /*ForFoldExpr=*/ForFoldExpression: false);
3114 return {Assignment, Assignment.isUsable()
3115 ? CombinerFailureKind::None
3116 : CombinerFailureKind::Assignment};
3117 }
3118 case OpenACCReductionOperator::And:
3119 case OpenACCReductionOperator::Or: {
3120 // These are done as LHS = LHS && RHS (or LHS = LHS || RHS). So after the
3121 // binop, all we have to do is the assignment.
3122 if (!BinOpRes.isUsable())
3123 return {BinOpRes, CombinerFailureKind::BinOp};
3124
3125 // Build assignment.
3126 ExprResult Assignment = SemaRef.BuildBinOp(S: SemaRef.getCurScope(), OpLoc: Loc,
3127 Opc: BinaryOperatorKind::BO_Assign,
3128 LHSExpr: LHSDRE, RHSExpr: BinOpRes.get(),
3129 /*ForFoldExpr=*/ForFoldExpression: false);
3130 return {Assignment, Assignment.isUsable()
3131 ? CombinerFailureKind::None
3132 : CombinerFailureKind::Assignment};
3133 }
3134 case OpenACCReductionOperator::Invalid:
3135 llvm_unreachable("Invalid should have been caught above");
3136 }
3137 llvm_unreachable("Unhandled case");
3138 };
3139
3140 auto tryCombiner = [&, this](DeclRefExpr *LHSDRE, DeclRefExpr *RHSDRE,
3141 bool IncludeTrap) {
3142 if (IncludeTrap) {
3143 // Trap all of the errors here, we'll emit our own at the end.
3144 Sema::TentativeAnalysisScope Trap{SemaRef};
3145 return genCombiner(LHSDRE, RHSDRE);
3146 }
3147 return genCombiner(LHSDRE, RHSDRE);
3148 };
3149
3150 struct CombinerAttemptTy {
3151 CombinerFailureKind FailKind;
3152 VarDecl *LHS;
3153 DeclRefExpr *LHSDRE;
3154 VarDecl *RHS;
3155 DeclRefExpr *RHSDRE;
3156 Expr *Op;
3157 };
3158
3159 auto formCombiner = [&, this](QualType Ty) -> CombinerAttemptTy {
3160 VarDecl *LHSDecl = CreateAllocaDecl(
3161 Ctx&: getASTContext(), DC: SemaRef.getCurContext(), BeginLoc: Loc,
3162 VarName: &getASTContext().Idents.get(Name: "openacc.reduction.combiner.lhs"), VarTy: Ty);
3163 auto *LHSDRE = DeclRefExpr::Create(
3164 Context: getASTContext(), QualifierLoc: NestedNameSpecifierLoc{}, TemplateKWLoc: SourceLocation{}, D: LHSDecl,
3165 /*ReferstoEnclosingVariableOrCapture=*/RefersToEnclosingVariableOrCapture: false,
3166 NameInfo: DeclarationNameInfo{DeclarationName{LHSDecl->getDeclName()},
3167 LHSDecl->getBeginLoc()},
3168 T: Ty, VK: clang::VK_LValue, FoundD: LHSDecl, TemplateArgs: nullptr, NOUR: NOUR_None);
3169 VarDecl *RHSDecl = CreateAllocaDecl(
3170 Ctx&: getASTContext(), DC: SemaRef.getCurContext(), BeginLoc: Loc,
3171 VarName: &getASTContext().Idents.get(Name: "openacc.reduction.combiner.lhs"), VarTy: Ty);
3172 auto *RHSDRE = DeclRefExpr::Create(
3173 Context: getASTContext(), QualifierLoc: NestedNameSpecifierLoc{}, TemplateKWLoc: SourceLocation{}, D: RHSDecl,
3174 /*ReferstoEnclosingVariableOrCapture=*/RefersToEnclosingVariableOrCapture: false,
3175 NameInfo: DeclarationNameInfo{DeclarationName{RHSDecl->getDeclName()},
3176 RHSDecl->getBeginLoc()},
3177 T: Ty, VK: clang::VK_LValue, FoundD: RHSDecl, TemplateArgs: nullptr, NOUR: NOUR_None);
3178
3179 std::pair<ExprResult, CombinerFailureKind> BinOpResult =
3180 tryCombiner(LHSDRE, RHSDRE, /*IncludeTrap=*/true);
3181
3182 return {.FailKind: BinOpResult.second, .LHS: LHSDecl, .LHSDRE: LHSDRE, .RHS: RHSDecl, .RHSDRE: RHSDRE,
3183 .Op: BinOpResult.first.get()};
3184 };
3185
3186 CombinerAttemptTy TopLevelCombinerInfo = formCombiner(VarTy);
3187
3188 if (TopLevelCombinerInfo.Op) {
3189 if (!TopLevelCombinerInfo.Op->containsErrors() &&
3190 TopLevelCombinerInfo.Op->isInstantiationDependent()) {
3191 // If this is instantiation dependent, we're just going to 'give up' here
3192 // and count on us to get it right during instantaition.
3193 CombinerRecipes.push_back(Elt: {.LHS: nullptr, .RHS: nullptr, .Op: nullptr});
3194 return false;
3195 } else if (!TopLevelCombinerInfo.Op->containsErrors()) {
3196 // Else, we succeeded, we can just return this combiner.
3197 CombinerRecipes.push_back(Elt: {.LHS: TopLevelCombinerInfo.LHS,
3198 .RHS: TopLevelCombinerInfo.RHS,
3199 .Op: TopLevelCombinerInfo.Op});
3200 return false;
3201 }
3202 }
3203
3204 auto EmitFailureNote = [&](CombinerFailureKind CFK) {
3205 if (CFK == CombinerFailureKind::BinOp)
3206 return Diag(Loc, DiagID: diag::note_acc_reduction_combiner_forming)
3207 << CFK << BinaryOperator::getOpcodeStr(Op: BinOp);
3208 return Diag(Loc, DiagID: diag::note_acc_reduction_combiner_forming) << CFK;
3209 };
3210
3211 // Since the 'root' level didn't fail, the only thing that could be successful
3212 // is a struct that we decompose on its individual fields.
3213
3214 RecordDecl *RD = VarTy->getAsRecordDecl();
3215 if (!RD) {
3216 Diag(Loc, DiagID: diag::err_acc_reduction_recipe_no_op) << VarTy;
3217 EmitFailureNote(TopLevelCombinerInfo.FailKind);
3218 tryCombiner(TopLevelCombinerInfo.LHSDRE, TopLevelCombinerInfo.RHSDRE,
3219 /*IncludeTrap=*/false);
3220 return true;
3221 }
3222
3223 for (const FieldDecl *FD : RD->fields()) {
3224 CombinerAttemptTy FieldCombinerInfo = formCombiner(FD->getType());
3225
3226 if (!FieldCombinerInfo.Op || FieldCombinerInfo.Op->containsErrors()) {
3227 Diag(Loc, DiagID: diag::err_acc_reduction_recipe_no_op) << FD->getType();
3228 Diag(Loc: FD->getBeginLoc(), DiagID: diag::note_acc_reduction_recipe_noop_field) << RD;
3229 EmitFailureNote(FieldCombinerInfo.FailKind);
3230 tryCombiner(FieldCombinerInfo.LHSDRE, FieldCombinerInfo.RHSDRE,
3231 /*IncludeTrap=*/false);
3232 return true;
3233 }
3234
3235 if (FieldCombinerInfo.Op->isInstantiationDependent()) {
3236 // If this is instantiation dependent, we're just going to 'give up' here
3237 // and count on us to get it right during instantaition.
3238 CombinerRecipes.push_back(Elt: {.LHS: nullptr, .RHS: nullptr, .Op: nullptr});
3239 } else {
3240 CombinerRecipes.push_back(
3241 Elt: {.LHS: FieldCombinerInfo.LHS, .RHS: FieldCombinerInfo.RHS, .Op: FieldCombinerInfo.Op});
3242 }
3243 }
3244
3245 return false;
3246}
3247