1//===----- SemaOpenACC.h - 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 declares semantic analysis for OpenACC constructs and
10/// clauses.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_SEMA_SEMAOPENACC_H
15#define LLVM_CLANG_SEMA_SEMAOPENACC_H
16
17#include "clang/AST/DeclGroup.h"
18#include "clang/Basic/OpenACCKinds.h"
19#include "clang/Basic/SourceLocation.h"
20#include "clang/Sema/Ownership.h"
21#include "clang/Sema/SemaBase.h"
22#include <variant>
23
24namespace clang {
25class OpenACCClause;
26
27class SemaOpenACC : public SemaBase {
28public:
29 /// A type to represent all the data for an OpenACC Clause that has been
30 /// parsed, but not yet created/semantically analyzed. This is effectively a
31 /// discriminated union on the 'Clause Kind', with all of the individual
32 /// clause details stored in a std::variant.
33 class OpenACCParsedClause {
34 OpenACCDirectiveKind DirKind;
35 OpenACCClauseKind ClauseKind;
36 SourceRange ClauseRange;
37 SourceLocation LParenLoc;
38
39 struct DefaultDetails {
40 OpenACCDefaultClauseKind DefaultClauseKind;
41 };
42
43 struct ConditionDetails {
44 Expr *ConditionExpr;
45 };
46
47 struct IntExprDetails {
48 SmallVector<Expr *> IntExprs;
49 };
50
51 std::variant<std::monostate, DefaultDetails, ConditionDetails,
52 IntExprDetails>
53 Details = std::monostate{};
54
55 public:
56 OpenACCParsedClause(OpenACCDirectiveKind DirKind,
57 OpenACCClauseKind ClauseKind, SourceLocation BeginLoc)
58 : DirKind(DirKind), ClauseKind(ClauseKind), ClauseRange(BeginLoc, {}) {}
59
60 OpenACCDirectiveKind getDirectiveKind() const { return DirKind; }
61
62 OpenACCClauseKind getClauseKind() const { return ClauseKind; }
63
64 SourceLocation getBeginLoc() const { return ClauseRange.getBegin(); }
65
66 SourceLocation getLParenLoc() const { return LParenLoc; }
67
68 SourceLocation getEndLoc() const { return ClauseRange.getEnd(); }
69
70 OpenACCDefaultClauseKind getDefaultClauseKind() const {
71 assert(ClauseKind == OpenACCClauseKind::Default &&
72 "Parsed clause is not a default clause");
73 return std::get<DefaultDetails>(v: Details).DefaultClauseKind;
74 }
75
76 const Expr *getConditionExpr() const {
77 return const_cast<OpenACCParsedClause *>(this)->getConditionExpr();
78 }
79
80 Expr *getConditionExpr() {
81 assert((ClauseKind == OpenACCClauseKind::If ||
82 (ClauseKind == OpenACCClauseKind::Self &&
83 DirKind != OpenACCDirectiveKind::Update)) &&
84 "Parsed clause kind does not have a condition expr");
85
86 // 'self' has an optional ConditionExpr, so be tolerant of that. This will
87 // assert in variant otherwise.
88 if (ClauseKind == OpenACCClauseKind::Self &&
89 std::holds_alternative<std::monostate>(v: Details))
90 return nullptr;
91
92 return std::get<ConditionDetails>(v&: Details).ConditionExpr;
93 }
94
95 unsigned getNumIntExprs() const {
96 assert((ClauseKind == OpenACCClauseKind::NumGangs ||
97 ClauseKind == OpenACCClauseKind::NumWorkers ||
98 ClauseKind == OpenACCClauseKind::VectorLength) &&
99 "Parsed clause kind does not have a int exprs");
100 return std::get<IntExprDetails>(v: Details).IntExprs.size();
101 }
102
103 ArrayRef<Expr *> getIntExprs() {
104 assert((ClauseKind == OpenACCClauseKind::NumGangs ||
105 ClauseKind == OpenACCClauseKind::NumWorkers ||
106 ClauseKind == OpenACCClauseKind::VectorLength) &&
107 "Parsed clause kind does not have a int exprs");
108 return std::get<IntExprDetails>(v&: Details).IntExprs;
109 }
110
111 ArrayRef<Expr *> getIntExprs() const {
112 return const_cast<OpenACCParsedClause *>(this)->getIntExprs();
113 }
114
115 void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; }
116 void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); }
117
118 void setDefaultDetails(OpenACCDefaultClauseKind DefKind) {
119 assert(ClauseKind == OpenACCClauseKind::Default &&
120 "Parsed clause is not a default clause");
121 Details = DefaultDetails{.DefaultClauseKind: DefKind};
122 }
123
124 void setConditionDetails(Expr *ConditionExpr) {
125 assert((ClauseKind == OpenACCClauseKind::If ||
126 (ClauseKind == OpenACCClauseKind::Self &&
127 DirKind != OpenACCDirectiveKind::Update)) &&
128 "Parsed clause kind does not have a condition expr");
129 // In C++ we can count on this being a 'bool', but in C this gets left as
130 // some sort of scalar that codegen will have to take care of converting.
131 assert((!ConditionExpr || ConditionExpr->isInstantiationDependent() ||
132 ConditionExpr->getType()->isScalarType()) &&
133 "Condition expression type not scalar/dependent");
134
135 Details = ConditionDetails{.ConditionExpr: ConditionExpr};
136 }
137
138 void setIntExprDetails(ArrayRef<Expr *> IntExprs) {
139 assert((ClauseKind == OpenACCClauseKind::NumGangs ||
140 ClauseKind == OpenACCClauseKind::NumWorkers ||
141 ClauseKind == OpenACCClauseKind::VectorLength) &&
142 "Parsed clause kind does not have a int exprs");
143 Details = IntExprDetails{.IntExprs: {IntExprs.begin(), IntExprs.end()}};
144 }
145 void setIntExprDetails(llvm::SmallVector<Expr *> &&IntExprs) {
146 assert((ClauseKind == OpenACCClauseKind::NumGangs ||
147 ClauseKind == OpenACCClauseKind::NumWorkers ||
148 ClauseKind == OpenACCClauseKind::VectorLength) &&
149 "Parsed clause kind does not have a int exprs");
150 Details = IntExprDetails{.IntExprs: IntExprs};
151 }
152 };
153
154 SemaOpenACC(Sema &S);
155
156 /// Called after parsing an OpenACC Clause so that it can be checked.
157 OpenACCClause *ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
158 OpenACCParsedClause &Clause);
159
160 /// Called after the construct has been parsed, but clauses haven't been
161 /// parsed. This allows us to diagnose not-implemented, as well as set up any
162 /// state required for parsing the clauses.
163 void ActOnConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc);
164
165 /// Called after the directive, including its clauses, have been parsed and
166 /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES
167 /// happen before any associated declarations or statements have been parsed.
168 /// This function is only called when we are parsing a 'statement' context.
169 bool ActOnStartStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc);
170
171 /// Called after the directive, including its clauses, have been parsed and
172 /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES
173 /// happen before any associated declarations or statements have been parsed.
174 /// This function is only called when we are parsing a 'Decl' context.
175 bool ActOnStartDeclDirective(OpenACCDirectiveKind K, SourceLocation StartLoc);
176 /// Called when we encounter an associated statement for our construct, this
177 /// should check legality of the statement as it appertains to this Construct.
178 StmtResult ActOnAssociatedStmt(OpenACCDirectiveKind K, StmtResult AssocStmt);
179
180 /// Called after the directive has been completely parsed, including the
181 /// declaration group or associated statement.
182 StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K,
183 SourceLocation StartLoc,
184 SourceLocation EndLoc,
185 ArrayRef<OpenACCClause *> Clauses,
186 StmtResult AssocStmt);
187
188 /// Called after the directive has been completely parsed, including the
189 /// declaration group or associated statement.
190 DeclGroupRef ActOnEndDeclDirective();
191
192 /// Called when encountering an 'int-expr' for OpenACC, and manages
193 /// conversions and diagnostics to 'int'.
194 ExprResult ActOnIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
195 SourceLocation Loc, Expr *IntExpr);
196};
197
198} // namespace clang
199
200#endif // LLVM_CLANG_SEMA_SEMAOPENACC_H
201

source code of clang/include/clang/Sema/SemaOpenACC.h