Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/Parse/ParseOpenACC.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- ParseOpenACC.cpp - OpenACC-specific parsing support --------------===//
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
//
9
// This file implements the parsing logic for OpenACC language features.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/Basic/OpenACCKinds.h"
14
#include "clang/Parse/ParseDiagnostic.h"
15
#include "clang/Parse/Parser.h"
16
#include "clang/Parse/RAIIObjectsForParser.h"
17
#include "llvm/ADT/StringRef.h"
18
#include "llvm/ADT/StringSwitch.h"
19
20
using namespace clang;
21
using namespace llvm;
22
23
namespace {
24
// An enum that contains the extended 'partial' parsed variants. This type
25
// should never escape the initial parse functionality, but is useful for
26
// simplifying the implementation.
27
enum class OpenACCDirectiveKindEx {
28
  Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid),
29
  // 'enter data' and 'exit data'
30
  Enter,
31
  Exit,
32
};
33
34
// Translate single-token string representations to the OpenACC Directive Kind.
35
// This doesn't completely comprehend 'Compound Constructs' (as it just
36
// identifies the first token), and doesn't fully handle 'enter data', 'exit
37
// data', nor any of the 'atomic' variants, just the first token of each.  So
38
// this should only be used by `ParseOpenACCDirectiveKind`.
39
0
OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {
40
0
  if (!Tok.is(tok::identifier))
41
0
    return OpenACCDirectiveKindEx::Invalid;
42
0
  OpenACCDirectiveKind DirKind =
43
0
      llvm::StringSwitch<OpenACCDirectiveKind>(
44
0
          Tok.getIdentifierInfo()->getName())
45
0
          .Case("parallel", OpenACCDirectiveKind::Parallel)
46
0
          .Case("serial", OpenACCDirectiveKind::Serial)
47
0
          .Case("kernels", OpenACCDirectiveKind::Kernels)
48
0
          .Case("data", OpenACCDirectiveKind::Data)
49
0
          .Case("host_data", OpenACCDirectiveKind::HostData)
50
0
          .Case("loop", OpenACCDirectiveKind::Loop)
51
0
          .Case("cache", OpenACCDirectiveKind::Cache)
52
0
          .Case("atomic", OpenACCDirectiveKind::Atomic)
53
0
          .Case("routine", OpenACCDirectiveKind::Routine)
54
0
          .Case("declare", OpenACCDirectiveKind::Declare)
55
0
          .Case("init", OpenACCDirectiveKind::Init)
56
0
          .Case("shutdown", OpenACCDirectiveKind::Shutdown)
57
0
          .Case("set", OpenACCDirectiveKind::Shutdown)
58
0
          .Case("update", OpenACCDirectiveKind::Update)
59
0
          .Case("wait", OpenACCDirectiveKind::Wait)
60
0
          .Default(OpenACCDirectiveKind::Invalid);
61
62
0
  if (DirKind != OpenACCDirectiveKind::Invalid)
63
0
    return static_cast<OpenACCDirectiveKindEx>(DirKind);
64
65
0
  return llvm::StringSwitch<OpenACCDirectiveKindEx>(
66
0
             Tok.getIdentifierInfo()->getName())
67
0
      .Case("enter", OpenACCDirectiveKindEx::Enter)
68
0
      .Case("exit", OpenACCDirectiveKindEx::Exit)
69
0
      .Default(OpenACCDirectiveKindEx::Invalid);
70
0
}
71
72
// Translate single-token string representations to the OpenCC Clause Kind.
73
0
OpenACCClauseKind getOpenACCClauseKind(Token Tok) {
74
  // auto is a keyword in some language modes, so make sure we parse it
75
  // correctly.
76
0
  if (Tok.is(tok::kw_auto))
77
0
    return OpenACCClauseKind::Auto;
78
79
  // default is a keyword, so make sure we parse it correctly.
80
0
  if (Tok.is(tok::kw_default))
81
0
    return OpenACCClauseKind::Default;
82
83
  // if is also a keyword, make sure we parse it correctly.
84
0
  if (Tok.is(tok::kw_if))
85
0
    return OpenACCClauseKind::If;
86
87
0
  if (!Tok.is(tok::identifier))
88
0
    return OpenACCClauseKind::Invalid;
89
90
0
  return llvm::StringSwitch<OpenACCClauseKind>(
91
0
             Tok.getIdentifierInfo()->getName())
92
0
      .Case("attach", OpenACCClauseKind::Attach)
93
0
      .Case("auto", OpenACCClauseKind::Auto)
94
0
      .Case("create", OpenACCClauseKind::Create)
95
0
      .Case("copy", OpenACCClauseKind::Copy)
96
0
      .Case("copyin", OpenACCClauseKind::CopyIn)
97
0
      .Case("copyout", OpenACCClauseKind::CopyOut)
98
0
      .Case("default", OpenACCClauseKind::Default)
99
0
      .Case("delete", OpenACCClauseKind::Delete)
100
0
      .Case("detach", OpenACCClauseKind::Detach)
101
0
      .Case("device", OpenACCClauseKind::Device)
102
0
      .Case("device_resident", OpenACCClauseKind::DeviceResident)
103
0
      .Case("deviceptr", OpenACCClauseKind::DevicePtr)
104
0
      .Case("finalize", OpenACCClauseKind::Finalize)
105
0
      .Case("firstprivate", OpenACCClauseKind::FirstPrivate)
106
0
      .Case("host", OpenACCClauseKind::Host)
107
0
      .Case("if", OpenACCClauseKind::If)
108
0
      .Case("if_present", OpenACCClauseKind::IfPresent)
109
0
      .Case("independent", OpenACCClauseKind::Independent)
110
0
      .Case("link", OpenACCClauseKind::Link)
111
0
      .Case("no_create", OpenACCClauseKind::NoCreate)
112
0
      .Case("nohost", OpenACCClauseKind::NoHost)
113
0
      .Case("present", OpenACCClauseKind::Present)
114
0
      .Case("private", OpenACCClauseKind::Private)
115
0
      .Case("reduction", OpenACCClauseKind::Reduction)
116
0
      .Case("self", OpenACCClauseKind::Self)
117
0
      .Case("seq", OpenACCClauseKind::Seq)
118
0
      .Case("use_device", OpenACCClauseKind::UseDevice)
119
0
      .Case("vector", OpenACCClauseKind::Vector)
120
0
      .Case("worker", OpenACCClauseKind::Worker)
121
0
      .Default(OpenACCClauseKind::Invalid);
122
0
}
123
124
// Since 'atomic' is effectively a compound directive, this will decode the
125
// second part of the directive.
126
0
OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) {
127
0
  if (!Tok.is(tok::identifier))
128
0
    return OpenACCAtomicKind::Invalid;
129
0
  return llvm::StringSwitch<OpenACCAtomicKind>(
130
0
             Tok.getIdentifierInfo()->getName())
131
0
      .Case("read", OpenACCAtomicKind::Read)
132
0
      .Case("write", OpenACCAtomicKind::Write)
133
0
      .Case("update", OpenACCAtomicKind::Update)
134
0
      .Case("capture", OpenACCAtomicKind::Capture)
135
0
      .Default(OpenACCAtomicKind::Invalid);
136
0
}
137
138
0
OpenACCDefaultClauseKind getOpenACCDefaultClauseKind(Token Tok) {
139
0
  if (!Tok.is(tok::identifier))
140
0
    return OpenACCDefaultClauseKind::Invalid;
141
142
0
  return llvm::StringSwitch<OpenACCDefaultClauseKind>(
143
0
             Tok.getIdentifierInfo()->getName())
144
0
      .Case("none", OpenACCDefaultClauseKind::None)
145
0
      .Case("present", OpenACCDefaultClauseKind::Present)
146
0
      .Default(OpenACCDefaultClauseKind::Invalid);
147
0
}
148
149
enum class OpenACCSpecialTokenKind {
150
  ReadOnly,
151
  DevNum,
152
  Queues,
153
  Zero,
154
};
155
156
0
bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {
157
0
  if (!Tok.is(tok::identifier))
158
0
    return false;
159
160
0
  switch (Kind) {
161
0
  case OpenACCSpecialTokenKind::ReadOnly:
162
0
    return Tok.getIdentifierInfo()->isStr("readonly");
163
0
  case OpenACCSpecialTokenKind::DevNum:
164
0
    return Tok.getIdentifierInfo()->isStr("devnum");
165
0
  case OpenACCSpecialTokenKind::Queues:
166
0
    return Tok.getIdentifierInfo()->isStr("queues");
167
0
  case OpenACCSpecialTokenKind::Zero:
168
0
    return Tok.getIdentifierInfo()->isStr("zero");
169
0
  }
170
0
  llvm_unreachable("Unknown 'Kind' Passed");
171
0
}
172
173
/// Used for cases where we have a token we want to check against an
174
/// 'identifier-like' token, but don't want to give awkward error messages in
175
/// cases where it is accidentially a keyword.
176
0
bool isTokenIdentifierOrKeyword(Parser &P, Token Tok) {
177
0
  if (Tok.is(tok::identifier))
178
0
    return true;
179
180
0
  if (!Tok.isAnnotation() && Tok.getIdentifierInfo() &&
181
0
      Tok.getIdentifierInfo()->isKeyword(P.getLangOpts()))
182
0
    return true;
183
184
0
  return false;
185
0
}
186
187
/// Parses and consumes an identifer followed immediately by a single colon, and
188
/// diagnoses if it is not the 'special token' kind that we require. Used when
189
/// the tag is the only valid value.
190
/// Return 'true' if the special token was matched, false if no special token,
191
/// or an invalid special token was found.
192
template <typename DirOrClauseTy>
193
bool tryParseAndConsumeSpecialTokenKind(Parser &P, OpenACCSpecialTokenKind Kind,
194
0
                                        DirOrClauseTy DirOrClause) {
195
0
  Token IdentTok = P.getCurToken();
196
  // If this is an identifier-like thing followed by ':', it is one of the
197
  // OpenACC 'special' name tags, so consume it.
198
0
  if (isTokenIdentifierOrKeyword(P, IdentTok) && P.NextToken().is(tok::colon)) {
199
0
    P.ConsumeToken();
200
0
    P.ConsumeToken();
201
202
0
    if (!isOpenACCSpecialToken(Kind, IdentTok)) {
203
0
      P.Diag(IdentTok, diag::err_acc_invalid_tag_kind)
204
0
          << IdentTok.getIdentifierInfo() << DirOrClause
205
0
          << std::is_same_v<DirOrClauseTy, OpenACCClauseKind>;
206
0
      return false;
207
0
    }
208
209
0
    return true;
210
0
  }
211
212
0
  return false;
213
0
}
Unexecuted instantiation: ParseOpenACC.cpp:bool (anonymous namespace)::tryParseAndConsumeSpecialTokenKind<clang::OpenACCClauseKind>(clang::Parser&, (anonymous namespace)::OpenACCSpecialTokenKind, clang::OpenACCClauseKind)
Unexecuted instantiation: ParseOpenACC.cpp:bool (anonymous namespace)::tryParseAndConsumeSpecialTokenKind<clang::OpenACCDirectiveKind>(clang::Parser&, (anonymous namespace)::OpenACCSpecialTokenKind, clang::OpenACCDirectiveKind)
214
215
0
bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
216
0
  if (!Tok.is(tok::identifier))
217
0
    return false;
218
219
0
  switch (Kind) {
220
0
  case OpenACCDirectiveKind::Parallel:
221
0
    return Tok.getIdentifierInfo()->isStr("parallel");
222
0
  case OpenACCDirectiveKind::Serial:
223
0
    return Tok.getIdentifierInfo()->isStr("serial");
224
0
  case OpenACCDirectiveKind::Kernels:
225
0
    return Tok.getIdentifierInfo()->isStr("kernels");
226
0
  case OpenACCDirectiveKind::Data:
227
0
    return Tok.getIdentifierInfo()->isStr("data");
228
0
  case OpenACCDirectiveKind::HostData:
229
0
    return Tok.getIdentifierInfo()->isStr("host_data");
230
0
  case OpenACCDirectiveKind::Loop:
231
0
    return Tok.getIdentifierInfo()->isStr("loop");
232
0
  case OpenACCDirectiveKind::Cache:
233
0
    return Tok.getIdentifierInfo()->isStr("cache");
234
235
0
  case OpenACCDirectiveKind::ParallelLoop:
236
0
  case OpenACCDirectiveKind::SerialLoop:
237
0
  case OpenACCDirectiveKind::KernelsLoop:
238
0
  case OpenACCDirectiveKind::EnterData:
239
0
  case OpenACCDirectiveKind::ExitData:
240
0
    return false;
241
242
0
  case OpenACCDirectiveKind::Atomic:
243
0
    return Tok.getIdentifierInfo()->isStr("atomic");
244
0
  case OpenACCDirectiveKind::Routine:
245
0
    return Tok.getIdentifierInfo()->isStr("routine");
246
0
  case OpenACCDirectiveKind::Declare:
247
0
    return Tok.getIdentifierInfo()->isStr("declare");
248
0
  case OpenACCDirectiveKind::Init:
249
0
    return Tok.getIdentifierInfo()->isStr("init");
250
0
  case OpenACCDirectiveKind::Shutdown:
251
0
    return Tok.getIdentifierInfo()->isStr("shutdown");
252
0
  case OpenACCDirectiveKind::Set:
253
0
    return Tok.getIdentifierInfo()->isStr("set");
254
0
  case OpenACCDirectiveKind::Update:
255
0
    return Tok.getIdentifierInfo()->isStr("update");
256
0
  case OpenACCDirectiveKind::Wait:
257
0
    return Tok.getIdentifierInfo()->isStr("wait");
258
0
  case OpenACCDirectiveKind::Invalid:
259
0
    return false;
260
0
  }
261
0
  llvm_unreachable("Unknown 'Kind' Passed");
262
0
}
263
264
0
OpenACCReductionOperator ParseReductionOperator(Parser &P) {
265
  // If there is no colon, treat as if the reduction operator was missing, else
266
  // we probably will not recover from it in the case where an expression starts
267
  // with one of the operator tokens.
268
0
  if (P.NextToken().isNot(tok::colon)) {
269
0
    P.Diag(P.getCurToken(), diag::err_acc_expected_reduction_operator);
270
0
    return OpenACCReductionOperator::Invalid;
271
0
  }
272
0
  Token ReductionKindTok = P.getCurToken();
273
  // Consume both the kind and the colon.
274
0
  P.ConsumeToken();
275
0
  P.ConsumeToken();
276
277
0
  switch (ReductionKindTok.getKind()) {
278
0
  case tok::plus:
279
0
    return OpenACCReductionOperator::Addition;
280
0
  case tok::star:
281
0
    return OpenACCReductionOperator::Multiplication;
282
0
  case tok::amp:
283
0
    return OpenACCReductionOperator::BitwiseAnd;
284
0
  case tok::pipe:
285
0
    return OpenACCReductionOperator::BitwiseOr;
286
0
  case tok::caret:
287
0
    return OpenACCReductionOperator::BitwiseXOr;
288
0
  case tok::ampamp:
289
0
    return OpenACCReductionOperator::And;
290
0
  case tok::pipepipe:
291
0
    return OpenACCReductionOperator::Or;
292
0
  case tok::identifier:
293
0
    if (ReductionKindTok.getIdentifierInfo()->isStr("max"))
294
0
      return OpenACCReductionOperator::Max;
295
0
    if (ReductionKindTok.getIdentifierInfo()->isStr("min"))
296
0
      return OpenACCReductionOperator::Min;
297
0
    LLVM_FALLTHROUGH;
298
0
  default:
299
0
    P.Diag(ReductionKindTok, diag::err_acc_invalid_reduction_operator);
300
0
    return OpenACCReductionOperator::Invalid;
301
0
  }
302
0
  llvm_unreachable("Reduction op token kind not caught by 'default'?");
303
0
}
304
305
/// Used for cases where we expect an identifier-like token, but don't want to
306
/// give awkward error messages in cases where it is accidentially a keyword.
307
0
bool expectIdentifierOrKeyword(Parser &P) {
308
0
  Token Tok = P.getCurToken();
309
310
0
  if (isTokenIdentifierOrKeyword(P, Tok))
311
0
    return false;
312
313
0
  P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;
314
0
  return true;
315
0
}
316
317
OpenACCDirectiveKind
318
ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
319
0
                                   OpenACCDirectiveKindEx ExtDirKind) {
320
0
  Token SecondTok = P.getCurToken();
321
322
0
  if (SecondTok.isAnnotation()) {
323
0
    P.Diag(FirstTok, diag::err_acc_invalid_directive)
324
0
        << 0 << FirstTok.getIdentifierInfo();
325
0
    return OpenACCDirectiveKind::Invalid;
326
0
  }
327
328
  // Consume the second name anyway, this way we can continue on without making
329
  // this oddly look like a clause.
330
0
  P.ConsumeAnyToken();
331
332
0
  if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTok)) {
333
0
    if (!SecondTok.is(tok::identifier))
334
0
      P.Diag(SecondTok, diag::err_expected) << tok::identifier;
335
0
    else
336
0
      P.Diag(FirstTok, diag::err_acc_invalid_directive)
337
0
          << 1 << FirstTok.getIdentifierInfo()->getName()
338
0
          << SecondTok.getIdentifierInfo()->getName();
339
0
    return OpenACCDirectiveKind::Invalid;
340
0
  }
341
342
0
  return ExtDirKind == OpenACCDirectiveKindEx::Enter
343
0
             ? OpenACCDirectiveKind::EnterData
344
0
             : OpenACCDirectiveKind::ExitData;
345
0
}
346
347
0
OpenACCAtomicKind ParseOpenACCAtomicKind(Parser &P) {
348
0
  Token AtomicClauseToken = P.getCurToken();
349
350
  // #pragma acc atomic is equivilent to update:
351
0
  if (AtomicClauseToken.isAnnotation())
352
0
    return OpenACCAtomicKind::Update;
353
354
0
  OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(AtomicClauseToken);
355
356
  // If we don't know what this is, treat it as 'nothing', and treat the rest of
357
  // this as a clause list, which, despite being invalid, is likely what the
358
  // user was trying to do.
359
0
  if (AtomicKind == OpenACCAtomicKind::Invalid)
360
0
    return OpenACCAtomicKind::Update;
361
362
0
  P.ConsumeToken();
363
0
  return AtomicKind;
364
0
}
365
366
// Parse and consume the tokens for OpenACC Directive/Construct kinds.
367
0
OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
368
0
  Token FirstTok = P.getCurToken();
369
370
  // Just #pragma acc can get us immediately to the end, make sure we don't
371
  // introspect on the spelling before then.
372
0
  if (FirstTok.isNot(tok::identifier)) {
373
0
    P.Diag(FirstTok, diag::err_acc_missing_directive);
374
375
0
    if (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
376
0
      P.ConsumeAnyToken();
377
378
0
    return OpenACCDirectiveKind::Invalid;
379
0
  }
380
381
0
  P.ConsumeToken();
382
383
0
  OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTok);
384
385
  // OpenACCDirectiveKindEx is meant to be an extended list
386
  // over OpenACCDirectiveKind, so any value below Invalid is one of the
387
  // OpenACCDirectiveKind values.  This switch takes care of all of the extra
388
  // parsing required for the Extended values.  At the end of this block,
389
  // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can
390
  // immediately cast it and use it as that.
391
0
  if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {
392
0
    switch (ExDirKind) {
393
0
    case OpenACCDirectiveKindEx::Invalid: {
394
0
      P.Diag(FirstTok, diag::err_acc_invalid_directive)
395
0
          << 0 << FirstTok.getIdentifierInfo();
396
0
      return OpenACCDirectiveKind::Invalid;
397
0
    }
398
0
    case OpenACCDirectiveKindEx::Enter:
399
0
    case OpenACCDirectiveKindEx::Exit:
400
0
      return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExDirKind);
401
0
    }
402
0
  }
403
404
0
  OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind);
405
406
  // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any
407
  // other attempt at a combined construct will be diagnosed as an invalid
408
  // clause.
409
0
  Token SecondTok = P.getCurToken();
410
0
  if (!SecondTok.isAnnotation() &&
411
0
      isOpenACCDirectiveKind(OpenACCDirectiveKind::Loop, SecondTok)) {
412
0
    switch (DirKind) {
413
0
    default:
414
      // Nothing to do except in the below cases, as they should be diagnosed as
415
      // a clause.
416
0
      break;
417
0
    case OpenACCDirectiveKind::Parallel:
418
0
      P.ConsumeToken();
419
0
      return OpenACCDirectiveKind::ParallelLoop;
420
0
    case OpenACCDirectiveKind::Serial:
421
0
      P.ConsumeToken();
422
0
      return OpenACCDirectiveKind::SerialLoop;
423
0
    case OpenACCDirectiveKind::Kernels:
424
0
      P.ConsumeToken();
425
0
      return OpenACCDirectiveKind::KernelsLoop;
426
0
    }
427
0
  }
428
429
0
  return DirKind;
430
0
}
431
432
enum ClauseParensKind {
433
  None,
434
  Optional,
435
  Required
436
};
437
438
ClauseParensKind getClauseParensKind(OpenACCDirectiveKind DirKind,
439
0
                                     OpenACCClauseKind Kind) {
440
0
  switch (Kind) {
441
0
  case OpenACCClauseKind::Self:
442
0
    return DirKind == OpenACCDirectiveKind::Update ? ClauseParensKind::Required
443
0
                                                   : ClauseParensKind::Optional;
444
445
0
  case OpenACCClauseKind::Default:
446
0
  case OpenACCClauseKind::If:
447
0
  case OpenACCClauseKind::Create:
448
0
  case OpenACCClauseKind::Copy:
449
0
  case OpenACCClauseKind::CopyIn:
450
0
  case OpenACCClauseKind::CopyOut:
451
0
  case OpenACCClauseKind::UseDevice:
452
0
  case OpenACCClauseKind::NoCreate:
453
0
  case OpenACCClauseKind::Present:
454
0
  case OpenACCClauseKind::DevicePtr:
455
0
  case OpenACCClauseKind::Attach:
456
0
  case OpenACCClauseKind::Detach:
457
0
  case OpenACCClauseKind::Private:
458
0
  case OpenACCClauseKind::FirstPrivate:
459
0
  case OpenACCClauseKind::Delete:
460
0
  case OpenACCClauseKind::DeviceResident:
461
0
  case OpenACCClauseKind::Device:
462
0
  case OpenACCClauseKind::Link:
463
0
  case OpenACCClauseKind::Host:
464
0
  case OpenACCClauseKind::Reduction:
465
0
    return ClauseParensKind::Required;
466
467
0
  case OpenACCClauseKind::Auto:
468
0
  case OpenACCClauseKind::Finalize:
469
0
  case OpenACCClauseKind::IfPresent:
470
0
  case OpenACCClauseKind::Independent:
471
0
  case OpenACCClauseKind::Invalid:
472
0
  case OpenACCClauseKind::NoHost:
473
0
  case OpenACCClauseKind::Seq:
474
0
  case OpenACCClauseKind::Worker:
475
0
  case OpenACCClauseKind::Vector:
476
0
    return ClauseParensKind::None;
477
0
  }
478
0
  llvm_unreachable("Unhandled clause kind");
479
0
}
480
481
bool ClauseHasOptionalParens(OpenACCDirectiveKind DirKind,
482
0
                             OpenACCClauseKind Kind) {
483
0
  return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Optional;
484
0
}
485
486
bool ClauseHasRequiredParens(OpenACCDirectiveKind DirKind,
487
0
                             OpenACCClauseKind Kind) {
488
0
  return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Required;
489
0
}
490
491
0
ExprResult ParseOpenACCConditionalExpr(Parser &P) {
492
  // FIXME: It isn't clear if the spec saying 'condition' means the same as
493
  // it does in an if/while/etc (See ParseCXXCondition), however as it was
494
  // written with Fortran/C in mind, we're going to assume it just means an
495
  // 'expression evaluating to boolean'.
496
0
  return P.getActions().CorrectDelayedTyposInExpr(P.ParseExpression());
497
0
}
498
499
// Skip until we see the end of pragma token, but don't consume it. This is us
500
// just giving up on the rest of the pragma so we can continue executing. We
501
// have to do this because 'SkipUntil' considers paren balancing, which isn't
502
// what we want.
503
0
void SkipUntilEndOfDirective(Parser &P) {
504
0
  while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
505
0
    P.ConsumeAnyToken();
506
0
}
507
508
} // namespace
509
510
// OpenACC 3.3, section 1.7:
511
// To simplify the specification and convey appropriate constraint information,
512
// a pqr-list is a comma-separated list of pdr items. The one exception is a
513
// clause-list, which is a list of one or more clauses optionally separated by
514
// commas.
515
0
void Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) {
516
0
  bool FirstClause = true;
517
0
  while (getCurToken().isNot(tok::annot_pragma_openacc_end)) {
518
    // Comma is optional in a clause-list.
519
0
    if (!FirstClause && getCurToken().is(tok::comma))
520
0
      ConsumeToken();
521
0
    FirstClause = false;
522
523
    // Recovering from a bad clause is really difficult, so we just give up on
524
    // error.
525
0
    if (ParseOpenACCClause(DirKind)) {
526
0
      SkipUntilEndOfDirective(*this);
527
0
      return;
528
0
    }
529
0
  }
530
0
}
531
532
0
bool Parser::ParseOpenACCClauseVarList(OpenACCClauseKind Kind) {
533
  // FIXME: Future clauses will require 'special word' parsing, check for one,
534
  // then parse it based on whether it is a clause that requires a 'special
535
  // word'.
536
0
  (void)Kind;
537
538
  // If the var parsing fails, skip until the end of the directive as this is
539
  // an expression and gets messy if we try to continue otherwise.
540
0
  if (ParseOpenACCVar())
541
0
    return true;
542
543
0
  while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
544
0
    ExpectAndConsume(tok::comma);
545
546
    // If the var parsing fails, skip until the end of the directive as this is
547
    // an expression and gets messy if we try to continue otherwise.
548
0
    if (ParseOpenACCVar())
549
0
      return true;
550
0
  }
551
0
  return false;
552
0
}
553
// The OpenACC Clause List is a comma or space-delimited list of clauses (see
554
// the comment on ParseOpenACCClauseList).  The concept of a 'clause' doesn't
555
// really have its owner grammar and each individual one has its own definition.
556
// However, they all are named with a single-identifier (or auto/default!)
557
// token, followed in some cases by either braces or parens.
558
0
bool Parser::ParseOpenACCClause(OpenACCDirectiveKind DirKind) {
559
  // A number of clause names are actually keywords, so accept a keyword that
560
  // can be converted to a name.
561
0
  if (expectIdentifierOrKeyword(*this))
562
0
    return true;
563
564
0
  OpenACCClauseKind Kind = getOpenACCClauseKind(getCurToken());
565
566
0
  if (Kind == OpenACCClauseKind::Invalid)
567
0
    return Diag(getCurToken(), diag::err_acc_invalid_clause)
568
0
           << getCurToken().getIdentifierInfo();
569
570
  // Consume the clause name.
571
0
  ConsumeToken();
572
573
0
  return ParseOpenACCClauseParams(DirKind, Kind);
574
0
}
575
576
bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind,
577
0
                                      OpenACCClauseKind Kind) {
578
0
  BalancedDelimiterTracker Parens(*this, tok::l_paren,
579
0
                                  tok::annot_pragma_openacc_end);
580
581
0
  if (ClauseHasRequiredParens(DirKind, Kind)) {
582
0
    if (Parens.expectAndConsume()) {
583
      // We are missing a paren, so assume that the person just forgot the
584
      // parameter.  Return 'false' so we try to continue on and parse the next
585
      // clause.
586
0
      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
587
0
                Parser::StopBeforeMatch);
588
0
      return false;
589
0
    }
590
591
0
    switch (Kind) {
592
0
    case OpenACCClauseKind::Default: {
593
0
      Token DefKindTok = getCurToken();
594
595
0
      if (expectIdentifierOrKeyword(*this))
596
0
        break;
597
598
0
      ConsumeToken();
599
600
0
      if (getOpenACCDefaultClauseKind(DefKindTok) ==
601
0
          OpenACCDefaultClauseKind::Invalid)
602
0
        Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
603
604
0
      break;
605
0
    }
606
0
    case OpenACCClauseKind::If: {
607
0
      ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
608
      // An invalid expression can be just about anything, so just give up on
609
      // this clause list.
610
0
      if (CondExpr.isInvalid())
611
0
        return true;
612
0
      break;
613
0
    }
614
0
    case OpenACCClauseKind::CopyIn:
615
0
      tryParseAndConsumeSpecialTokenKind(
616
0
          *this, OpenACCSpecialTokenKind::ReadOnly, Kind);
617
0
      if (ParseOpenACCClauseVarList(Kind))
618
0
        return true;
619
0
      break;
620
0
    case OpenACCClauseKind::Create:
621
0
    case OpenACCClauseKind::CopyOut:
622
0
      tryParseAndConsumeSpecialTokenKind(*this, OpenACCSpecialTokenKind::Zero,
623
0
                                         Kind);
624
0
      if (ParseOpenACCClauseVarList(Kind))
625
0
        return true;
626
0
      break;
627
0
    case OpenACCClauseKind::Reduction:
628
      // If we're missing a clause-kind (or it is invalid), see if we can parse
629
      // the var-list anyway.
630
0
      ParseReductionOperator(*this);
631
0
      if (ParseOpenACCClauseVarList(Kind))
632
0
        return true;
633
0
      break;
634
0
    case OpenACCClauseKind::Self:
635
      // The 'self' clause is a var-list instead of a 'condition' in the case of
636
      // the 'update' clause, so we have to handle it here.  U se an assert to
637
      // make sure we get the right differentiator.
638
0
      assert(DirKind == OpenACCDirectiveKind::Update);
639
0
      LLVM_FALLTHROUGH;
640
0
    case OpenACCClauseKind::Attach:
641
0
    case OpenACCClauseKind::Copy:
642
0
    case OpenACCClauseKind::Delete:
643
0
    case OpenACCClauseKind::Detach:
644
0
    case OpenACCClauseKind::Device:
645
0
    case OpenACCClauseKind::DeviceResident:
646
0
    case OpenACCClauseKind::DevicePtr:
647
0
    case OpenACCClauseKind::FirstPrivate:
648
0
    case OpenACCClauseKind::Host:
649
0
    case OpenACCClauseKind::Link:
650
0
    case OpenACCClauseKind::NoCreate:
651
0
    case OpenACCClauseKind::Present:
652
0
    case OpenACCClauseKind::Private:
653
0
    case OpenACCClauseKind::UseDevice:
654
0
      if (ParseOpenACCClauseVarList(Kind))
655
0
        return true;
656
0
      break;
657
0
    default:
658
0
      llvm_unreachable("Not a required parens type?");
659
0
    }
660
661
0
    return Parens.consumeClose();
662
0
  } else if (ClauseHasOptionalParens(DirKind, Kind)) {
663
0
    if (!Parens.consumeOpen()) {
664
0
      switch (Kind) {
665
0
      case OpenACCClauseKind::Self: {
666
0
        assert(DirKind != OpenACCDirectiveKind::Update);
667
0
        ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
668
        // An invalid expression can be just about anything, so just give up on
669
        // this clause list.
670
0
        if (CondExpr.isInvalid())
671
0
          return true;
672
0
        break;
673
0
      }
674
0
      default:
675
0
        llvm_unreachable("Not an optional parens type?");
676
0
      }
677
0
      Parens.consumeClose();
678
0
    }
679
0
  }
680
0
  return false;
681
0
}
682
683
/// OpenACC 3.3, section 2.16:
684
/// In this section and throughout the specification, the term wait-argument
685
/// means:
686
/// [ devnum : int-expr : ] [ queues : ] async-argument-list
687
0
bool Parser::ParseOpenACCWaitArgument() {
688
  // [devnum : int-expr : ]
689
0
  if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&
690
0
      NextToken().is(tok::colon)) {
691
    // Consume devnum.
692
0
    ConsumeToken();
693
    // Consume colon.
694
0
    ConsumeToken();
695
696
0
    ExprResult IntExpr =
697
0
        getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
698
0
    if (IntExpr.isInvalid())
699
0
      return true;
700
701
0
    if (ExpectAndConsume(tok::colon))
702
0
      return true;
703
0
  }
704
705
  // [ queues : ]
706
0
  if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&
707
0
      NextToken().is(tok::colon)) {
708
    // Consume queues.
709
0
    ConsumeToken();
710
    // Consume colon.
711
0
    ConsumeToken();
712
0
  }
713
714
  // OpenACC 3.3, section 2.16:
715
  // the term 'async-argument' means a nonnegative scalar integer expression, or
716
  // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined
717
  // in the C header file and the Fortran opacc module.
718
  //
719
  // We are parsing this simply as list of assignment expressions (to avoid
720
  // comma being troublesome), and will ensure it is an integral type.  The
721
  // 'special' types are defined as macros, so we can't really check those
722
  // (other than perhaps as values at one point?), but the standard does say it
723
  // is implementation-defined to use any other negative value.
724
  //
725
  //
726
0
  bool FirstArg = true;
727
0
  while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
728
0
    if (!FirstArg) {
729
0
      if (ExpectAndConsume(tok::comma))
730
0
        return true;
731
0
    }
732
0
    FirstArg = false;
733
734
0
    ExprResult CurArg =
735
0
        getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
736
737
0
    if (CurArg.isInvalid())
738
0
      return true;
739
0
  }
740
741
0
  return false;
742
0
}
743
744
0
ExprResult Parser::ParseOpenACCIDExpression() {
745
0
  ExprResult Res;
746
0
  if (getLangOpts().CPlusPlus) {
747
0
    Res = ParseCXXIdExpression(/*isAddressOfOperand=*/false);
748
0
  } else {
749
    // There isn't anything quite the same as ParseCXXIdExpression for C, so we
750
    // need to get the identifier, then call into Sema ourselves.
751
752
0
    if (Tok.isNot(tok::identifier)) {
753
0
      Diag(Tok, diag::err_expected) << tok::identifier;
754
0
      return ExprError();
755
0
    }
756
757
0
    Token FuncName = getCurToken();
758
0
    UnqualifiedId Name;
759
0
    CXXScopeSpec ScopeSpec;
760
0
    SourceLocation TemplateKWLoc;
761
0
    Name.setIdentifier(FuncName.getIdentifierInfo(), ConsumeToken());
762
763
    // Ensure this is a valid identifier. We don't accept causing implicit
764
    // function declarations per the spec, so always claim to not have trailing
765
    // L Paren.
766
0
    Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
767
0
                                    Name, /*HasTrailingLParen=*/false,
768
0
                                    /*isAddressOfOperand=*/false);
769
0
  }
770
771
0
  return getActions().CorrectDelayedTyposInExpr(Res);
772
0
}
773
774
/// OpenACC 3.3, section 1.6:
775
/// In this spec, a 'var' (in italics) is one of the following:
776
/// - a variable name (a scalar, array, or compisite variable name)
777
/// - a subarray specification with subscript ranges
778
/// - an array element
779
/// - a member of a composite variable
780
/// - a common block name between slashes (fortran only)
781
0
bool Parser::ParseOpenACCVar() {
782
0
  OpenACCArraySectionRAII ArraySections(*this);
783
0
  ExprResult Res =
784
0
      getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
785
0
  return Res.isInvalid();
786
0
}
787
788
/// OpenACC 3.3, section 2.10:
789
/// In C and C++, the syntax of the cache directive is:
790
///
791
/// #pragma acc cache ([readonly:]var-list) new-line
792
0
void Parser::ParseOpenACCCacheVarList() {
793
  // If this is the end of the line, just return 'false' and count on the close
794
  // paren diagnostic to catch the issue.
795
0
  if (getCurToken().isAnnotation())
796
0
    return;
797
798
  // The VarList is an optional `readonly:` followed by a list of a variable
799
  // specifications. Consume something that looks like a 'tag', and diagnose if
800
  // it isn't 'readonly'.
801
0
  if (tryParseAndConsumeSpecialTokenKind(*this,
802
0
                                         OpenACCSpecialTokenKind::ReadOnly,
803
0
                                         OpenACCDirectiveKind::Cache)) {
804
    // FIXME: Record that this is a 'readonly' so that we can use that during
805
    // Sema/AST generation.
806
0
  }
807
808
0
  bool FirstArray = true;
809
0
  while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
810
0
    if (!FirstArray)
811
0
      ExpectAndConsume(tok::comma);
812
0
    FirstArray = false;
813
814
    // OpenACC 3.3, section 2.10:
815
    // A 'var' in a cache directive must be a single array element or a simple
816
    // subarray.  In C and C++, a simple subarray is an array name followed by
817
    // an extended array range specification in brackets, with a start and
818
    // length such as:
819
    //
820
    // arr[lower:length]
821
    //
822
0
    if (ParseOpenACCVar())
823
0
      SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, tok::comma,
824
0
                StopBeforeMatch);
825
0
  }
826
0
}
827
828
0
void Parser::ParseOpenACCDirective() {
829
0
  OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this);
830
831
  // Once we've parsed the construct/directive name, some have additional
832
  // specifiers that need to be taken care of. Atomic has an 'atomic-clause'
833
  // that needs to be parsed.
834
0
  if (DirKind == OpenACCDirectiveKind::Atomic)
835
0
    ParseOpenACCAtomicKind(*this);
836
837
  // We've successfully parsed the construct/directive name, however a few of
838
  // the constructs have optional parens that contain further details.
839
0
  BalancedDelimiterTracker T(*this, tok::l_paren,
840
0
                             tok::annot_pragma_openacc_end);
841
842
0
  if (!T.consumeOpen()) {
843
0
    switch (DirKind) {
844
0
    default:
845
0
      Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren);
846
0
      T.skipToEnd();
847
0
      break;
848
0
    case OpenACCDirectiveKind::Routine: {
849
      // Routine has an optional paren-wrapped name of a function in the local
850
      // scope. We parse the name, emitting any diagnostics
851
0
      ExprResult RoutineName = ParseOpenACCIDExpression();
852
      // If the routine name is invalid, just skip until the closing paren to
853
      // recover more gracefully.
854
0
      if (RoutineName.isInvalid())
855
0
        T.skipToEnd();
856
0
      else
857
0
        T.consumeClose();
858
0
      break;
859
0
    }
860
0
    case OpenACCDirectiveKind::Cache:
861
0
      ParseOpenACCCacheVarList();
862
      // The ParseOpenACCCacheVarList function manages to recover from failures,
863
      // so we can always consume the close.
864
0
      T.consumeClose();
865
0
      break;
866
0
    case OpenACCDirectiveKind::Wait:
867
      // OpenACC has an optional paren-wrapped 'wait-argument'.
868
0
      if (ParseOpenACCWaitArgument())
869
0
        T.skipToEnd();
870
0
      else
871
0
        T.consumeClose();
872
0
      break;
873
0
    }
874
0
  } else if (DirKind == OpenACCDirectiveKind::Cache) {
875
    // Cache's paren var-list is required, so error here if it isn't provided.
876
    // We know that the consumeOpen above left the first non-paren here, so
877
    // diagnose, then continue as if it was completely omitted.
878
0
    Diag(Tok, diag::err_expected) << tok::l_paren;
879
0
  }
880
881
  // Parses the list of clauses, if present.
882
0
  ParseOpenACCClauseList(DirKind);
883
884
0
  Diag(getCurToken(), diag::warn_pragma_acc_unimplemented);
885
0
  assert(Tok.is(tok::annot_pragma_openacc_end) &&
886
0
         "Didn't parse all OpenACC Clauses");
887
0
  ConsumeAnnotationToken();
888
0
}
889
890
// Parse OpenACC directive on a declaration.
891
0
Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() {
892
0
  assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
893
894
0
  ParsingOpenACCDirectiveRAII DirScope(*this);
895
0
  ConsumeAnnotationToken();
896
897
0
  ParseOpenACCDirective();
898
899
0
  return nullptr;
900
0
}
901
902
// Parse OpenACC Directive on a Statement.
903
0
StmtResult Parser::ParseOpenACCDirectiveStmt() {
904
0
  assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
905
906
0
  ParsingOpenACCDirectiveRAII DirScope(*this);
907
0
  ConsumeAnnotationToken();
908
909
0
  ParseOpenACCDirective();
910
911
0
  return StmtEmpty();
912
0
}