Skip to content

Commit 9e068cd

Browse files
authored
[OpenACC} Improve diagnostics for 'tag's on clauses/directives (#77957)
The 'cache' directive and various clauses have a 'tag' name that is optional. This patch cleans up the use of the 'cache' version so that we get a nicer diagnostic, and enables us to do the same with clauses in the same situation.
1 parent 93d3965 commit 9e068cd

File tree

4 files changed

+217
-13
lines changed

4 files changed

+217
-13
lines changed

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,8 @@ def err_acc_invalid_open_paren
13661366
: Error<"expected clause-list or newline in OpenACC directive">;
13671367
def err_acc_invalid_default_clause_kind
13681368
: Error<"invalid value for 'default' clause; expected 'present' or 'none'">;
1369+
def err_acc_invalid_tag_kind
1370+
: Error<"invalid tag %0 on '%1' %select{directive|clause}2">;
13691371

13701372
// OpenMP support.
13711373
def warn_pragma_omp_ignored : Warning<

clang/include/clang/Basic/OpenACCKinds.h

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
#ifndef LLVM_CLANG_BASIC_OPENACCKINDS_H
1515
#define LLVM_CLANG_BASIC_OPENACCKINDS_H
1616

17+
#include "clang/Basic/Diagnostic.h"
18+
#include "llvm/Support/ErrorHandling.h"
19+
1720
namespace clang {
1821
// Represents the Construct/Directive kind of a pragma directive. Note the
1922
// OpenACC standard is inconsistent between calling these Construct vs
@@ -62,6 +65,75 @@ enum class OpenACCDirectiveKind {
6265
Invalid,
6366
};
6467

68+
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
69+
OpenACCDirectiveKind K) {
70+
switch (K) {
71+
case OpenACCDirectiveKind::Parallel:
72+
return Out << "parallel";
73+
74+
case OpenACCDirectiveKind::Serial:
75+
return Out << "serial";
76+
77+
case OpenACCDirectiveKind::Kernels:
78+
return Out << "kernels";
79+
80+
case OpenACCDirectiveKind::Data:
81+
return Out << "data";
82+
83+
case OpenACCDirectiveKind::EnterData:
84+
return Out << "enter data";
85+
86+
case OpenACCDirectiveKind::ExitData:
87+
return Out << "exit data";
88+
89+
case OpenACCDirectiveKind::HostData:
90+
return Out << "host_data";
91+
92+
case OpenACCDirectiveKind::Loop:
93+
return Out << "loop";
94+
95+
case OpenACCDirectiveKind::Cache:
96+
return Out << "cache";
97+
98+
case OpenACCDirectiveKind::ParallelLoop:
99+
return Out << "parallel loop";
100+
101+
case OpenACCDirectiveKind::SerialLoop:
102+
return Out << "serial loop";
103+
104+
case OpenACCDirectiveKind::KernelsLoop:
105+
return Out << "kernels loop";
106+
107+
case OpenACCDirectiveKind::Atomic:
108+
return Out << "atomic";
109+
110+
case OpenACCDirectiveKind::Declare:
111+
return Out << "declare";
112+
113+
case OpenACCDirectiveKind::Init:
114+
return Out << "init";
115+
116+
case OpenACCDirectiveKind::Shutdown:
117+
return Out << "shutdown";
118+
119+
case OpenACCDirectiveKind::Set:
120+
return Out << "set";
121+
122+
case OpenACCDirectiveKind::Update:
123+
return Out << "update";
124+
125+
case OpenACCDirectiveKind::Wait:
126+
return Out << "wait";
127+
128+
case OpenACCDirectiveKind::Routine:
129+
return Out << "routine";
130+
131+
case OpenACCDirectiveKind::Invalid:
132+
return Out << "<invalid>";
133+
}
134+
llvm_unreachable("Uncovered directive kind");
135+
}
136+
65137
enum class OpenACCAtomicKind {
66138
Read,
67139
Write,
@@ -138,6 +210,89 @@ enum class OpenACCClauseKind {
138210
Invalid,
139211
};
140212

213+
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
214+
OpenACCClauseKind K) {
215+
switch (K) {
216+
case OpenACCClauseKind::Finalize:
217+
return Out << "finalize";
218+
219+
case OpenACCClauseKind::IfPresent:
220+
return Out << "if_present";
221+
222+
case OpenACCClauseKind::Seq:
223+
return Out << "seq";
224+
225+
case OpenACCClauseKind::Independent:
226+
return Out << "independent";
227+
228+
case OpenACCClauseKind::Auto:
229+
return Out << "auto";
230+
231+
case OpenACCClauseKind::Worker:
232+
return Out << "worker";
233+
234+
case OpenACCClauseKind::Vector:
235+
return Out << "vector";
236+
237+
case OpenACCClauseKind::NoHost:
238+
return Out << "nohost";
239+
240+
case OpenACCClauseKind::Default:
241+
return Out << "default";
242+
243+
case OpenACCClauseKind::If:
244+
return Out << "if";
245+
246+
case OpenACCClauseKind::Self:
247+
return Out << "self";
248+
249+
case OpenACCClauseKind::Copy:
250+
return Out << "copy";
251+
252+
case OpenACCClauseKind::UseDevice:
253+
return Out << "use_device";
254+
255+
case OpenACCClauseKind::Attach:
256+
return Out << "attach";
257+
258+
case OpenACCClauseKind::Delete:
259+
return Out << "delete";
260+
261+
case OpenACCClauseKind::Detach:
262+
return Out << "detach";
263+
264+
case OpenACCClauseKind::Device:
265+
return Out << "device";
266+
267+
case OpenACCClauseKind::DevicePtr:
268+
return Out << "deviceptr";
269+
270+
case OpenACCClauseKind::DeviceResident:
271+
return Out << "device_resident";
272+
273+
case OpenACCClauseKind::FirstPrivate:
274+
return Out << "firstprivate";
275+
276+
case OpenACCClauseKind::Host:
277+
return Out << "host";
278+
279+
case OpenACCClauseKind::Link:
280+
return Out << "link";
281+
282+
case OpenACCClauseKind::NoCreate:
283+
return Out << "no_create";
284+
285+
case OpenACCClauseKind::Present:
286+
return Out << "present";
287+
288+
case OpenACCClauseKind::Private:
289+
return Out << "private";
290+
291+
case OpenACCClauseKind::Invalid:
292+
return Out << "<invalid>";
293+
}
294+
llvm_unreachable("Uncovered clause kind");
295+
}
141296
enum class OpenACCDefaultClauseKind {
142297
/// 'none' option.
143298
None,

clang/lib/Parse/ParseOpenACC.cpp

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,48 @@ bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {
163163
llvm_unreachable("Unknown 'Kind' Passed");
164164
}
165165

166+
/// Used for cases where we have a token we want to check against an
167+
/// 'identifier-like' token, but don't want to give awkward error messages in
168+
/// cases where it is accidentially a keyword.
169+
bool isTokenIdentifierOrKeyword(Parser &P, Token Tok) {
170+
if (Tok.is(tok::identifier))
171+
return true;
172+
173+
if (!Tok.isAnnotation() && Tok.getIdentifierInfo() &&
174+
Tok.getIdentifierInfo()->isKeyword(P.getLangOpts()))
175+
return true;
176+
177+
return false;
178+
}
179+
180+
/// Parses and consumes an identifer followed immediately by a single colon, and
181+
/// diagnoses if it is not the 'special token' kind that we require. Used when
182+
/// the tag is the only valid value.
183+
/// Return 'true' if the special token was matched, false if no special token,
184+
/// or an invalid special token was found.
185+
template <typename DirOrClauseTy>
186+
bool tryParseAndConsumeSpecialTokenKind(Parser &P, OpenACCSpecialTokenKind Kind,
187+
DirOrClauseTy DirOrClause) {
188+
Token IdentTok = P.getCurToken();
189+
// If this is an identifier-like thing followed by ':', it is one of the
190+
// OpenACC 'special' name tags, so consume it.
191+
if (isTokenIdentifierOrKeyword(P, IdentTok) && P.NextToken().is(tok::colon)) {
192+
P.ConsumeToken();
193+
P.ConsumeToken();
194+
195+
if (!isOpenACCSpecialToken(Kind, IdentTok)) {
196+
P.Diag(IdentTok, diag::err_acc_invalid_tag_kind)
197+
<< IdentTok.getIdentifierInfo() << DirOrClause
198+
<< std::is_same_v<DirOrClauseTy, OpenACCClauseKind>;
199+
return false;
200+
}
201+
202+
return true;
203+
}
204+
205+
return false;
206+
}
207+
166208
bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
167209
if (!Tok.is(tok::identifier))
168210
return false;
@@ -217,11 +259,7 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
217259
bool expectIdentifierOrKeyword(Parser &P) {
218260
Token Tok = P.getCurToken();
219261

220-
if (Tok.is(tok::identifier))
221-
return false;
222-
223-
if (!Tok.isAnnotation() && Tok.getIdentifierInfo() &&
224-
Tok.getIdentifierInfo()->isKeyword(P.getLangOpts()))
262+
if (isTokenIdentifierOrKeyword(P, Tok))
225263
return false;
226264

227265
P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;
@@ -673,14 +711,11 @@ void Parser::ParseOpenACCCacheVarList() {
673711
return;
674712

675713
// The VarList is an optional `readonly:` followed by a list of a variable
676-
// specifications. First, see if we have `readonly:`, else we back-out and
677-
// treat it like the beginning of a reference to a potentially-existing
678-
// `readonly` variable.
679-
if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::ReadOnly, Tok) &&
680-
NextToken().is(tok::colon)) {
681-
// Consume both tokens.
682-
ConsumeToken();
683-
ConsumeToken();
714+
// specifications. Consume something that looks like a 'tag', and diagnose if
715+
// it isn't 'readonly'.
716+
if (tryParseAndConsumeSpecialTokenKind(*this,
717+
OpenACCSpecialTokenKind::ReadOnly,
718+
OpenACCDirectiveKind::Cache)) {
684719
// FIXME: Record that this is a 'readonly' so that we can use that during
685720
// Sema/AST generation.
686721
}

clang/test/ParserOpenACC/parse-cache-construct.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ void func() {
114114
#pragma acc cache(readonly)
115115
}
116116

117+
for (int i = 0; i < 10; ++i) {
118+
// expected-error@+2{{invalid tag 'devnum' on 'cache' directive}}
119+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
120+
#pragma acc cache(devnum:ArrayPtr)
121+
}
122+
123+
for (int i = 0; i < 10; ++i) {
124+
// expected-error@+2{{invalid tag 'invalid' on 'cache' directive}}
125+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
126+
#pragma acc cache(invalid:ArrayPtr)
127+
}
128+
117129
for (int i = 0; i < 10; ++i) {
118130
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
119131
#pragma acc cache(readonly:ArrayPtr)

0 commit comments

Comments
 (0)