Skip to content

Commit ba1c869

Browse files
authored
[OpenACC] Implement 'routine' construct parsing (#73143)
The 'routine' construct applies either to a function directly, or, when provided a name, applies to the function named (and is visible in the current scope). This patch implements the parsing for this. The identifier provided (or Id Expression) is required to be a valid, declared identifier, though the semantic analysis portion of the Routine directive will need to enforce it being a function/overload set.
1 parent bf02c84 commit ba1c869

File tree

6 files changed

+165
-11
lines changed

6 files changed

+165
-11
lines changed

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,8 @@ def warn_pragma_acc_unimplemented_clause_parsing
13641364
def err_acc_invalid_directive
13651365
: Error<"invalid OpenACC directive '%select{%1|%1 %2}0'">;
13661366
def err_acc_missing_directive : Error<"expected OpenACC directive">;
1367+
def err_acc_invalid_open_paren
1368+
: Error<"expected clause-list or newline in OpenACC directive">;
13671369

13681370
// OpenMP support.
13691371
def warn_pragma_omp_ignored : Warning<

clang/include/clang/Basic/OpenACCKinds.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ enum class OpenACCDirectiveKind {
5555
Update,
5656
// FIXME: wait construct.
5757

58-
// FIXME: routine construct.
58+
// Procedure Calls in Compute Regions.
59+
Routine,
5960

6061
// Invalid.
6162
Invalid,

clang/include/clang/Parse/Parser.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3532,9 +3532,14 @@ class Parser : public CodeCompletionHandler {
35323532
/// Placeholder for now, should just ignore the directives after emitting a
35333533
/// diagnostic. Eventually will be split into a few functions to parse
35343534
/// different situations.
3535+
public:
35353536
DeclGroupPtrTy ParseOpenACCDirectiveDecl();
35363537
StmtResult ParseOpenACCDirectiveStmt();
35373538

3539+
private:
3540+
void ParseOpenACCDirective();
3541+
ExprResult ParseOpenACCRoutineName();
3542+
35383543
private:
35393544
//===--------------------------------------------------------------------===//
35403545
// C++ 14: Templates [temp]

clang/lib/Parse/ParseOpenACC.cpp

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ OpenACCDirectiveKindEx getOpenACCDirectiveKind(StringRef Name) {
4646
.Case("host_data", OpenACCDirectiveKind::HostData)
4747
.Case("loop", OpenACCDirectiveKind::Loop)
4848
.Case("atomic", OpenACCDirectiveKind::Atomic)
49+
.Case("routine", OpenACCDirectiveKind::Routine)
4950
.Case("declare", OpenACCDirectiveKind::Declare)
5051
.Case("init", OpenACCDirectiveKind::Init)
5152
.Case("shutdown", OpenACCDirectiveKind::Shutdown)
@@ -97,6 +98,8 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {
9798

9899
case OpenACCDirectiveKind::Atomic:
99100
return Tok == "atomic";
101+
case OpenACCDirectiveKind::Routine:
102+
return Tok == "routine";
100103
case OpenACCDirectiveKind::Declare:
101104
return Tok == "declare";
102105
case OpenACCDirectiveKind::Init:
@@ -232,32 +235,87 @@ void ParseOpenACCClauseList(Parser &P) {
232235
P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented_clause_parsing);
233236
}
234237

235-
void ParseOpenACCDirective(Parser &P) {
236-
OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(P);
238+
} // namespace
239+
240+
// Routine has an optional paren-wrapped name of a function in the local scope.
241+
// We parse the name, emitting any diagnostics
242+
ExprResult Parser::ParseOpenACCRoutineName() {
243+
244+
ExprResult Res;
245+
if (getLangOpts().CPlusPlus) {
246+
Res = ParseCXXIdExpression(/*isAddressOfOperand=*/false);
247+
} else {
248+
// There isn't anything quite the same as ParseCXXIdExpression for C, so we
249+
// need to get the identifier, then call into Sema ourselves.
250+
251+
if (expectIdentifier())
252+
return ExprError();
253+
254+
Token FuncName = getCurToken();
255+
UnqualifiedId Name;
256+
CXXScopeSpec ScopeSpec;
257+
SourceLocation TemplateKWLoc;
258+
Name.setIdentifier(FuncName.getIdentifierInfo(), ConsumeToken());
259+
260+
// Ensure this is a valid identifier. We don't accept causing implicit
261+
// function declarations per the spec, so always claim to not have trailing
262+
// L Paren.
263+
Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
264+
Name, /*HasTrailingLParen=*/false,
265+
/*isAddressOfOperand=*/false);
266+
}
267+
268+
return getActions().CorrectDelayedTyposInExpr(Res);
269+
}
270+
271+
void Parser::ParseOpenACCDirective() {
272+
OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this);
237273

238274
// Once we've parsed the construct/directive name, some have additional
239275
// specifiers that need to be taken care of. Atomic has an 'atomic-clause'
240276
// that needs to be parsed.
241277
if (DirKind == OpenACCDirectiveKind::Atomic)
242-
ParseOpenACCAtomicKind(P);
278+
ParseOpenACCAtomicKind(*this);
279+
280+
// We've successfully parsed the construct/directive name, however a few of
281+
// the constructs have optional parens that contain further details.
282+
BalancedDelimiterTracker T(*this, tok::l_paren,
283+
tok::annot_pragma_openacc_end);
284+
285+
if (!T.consumeOpen()) {
286+
switch (DirKind) {
287+
default:
288+
Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren);
289+
T.skipToEnd();
290+
break;
291+
case OpenACCDirectiveKind::Routine: {
292+
ExprResult RoutineName = ParseOpenACCRoutineName();
293+
// If the routine name is invalid, just skip until the closing paren to
294+
// recover more gracefully.
295+
if (RoutineName.isInvalid())
296+
T.skipToEnd();
297+
else
298+
T.consumeClose();
299+
break;
300+
}
301+
}
302+
}
243303

244304
// Parses the list of clauses, if present.
245-
ParseOpenACCClauseList(P);
305+
ParseOpenACCClauseList(*this);
246306

247-
P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented);
248-
P.SkipUntil(tok::annot_pragma_openacc_end);
307+
Diag(getCurToken(), diag::warn_pragma_acc_unimplemented);
308+
SkipUntil(tok::annot_pragma_openacc_end);
249309
}
250310

251-
} // namespace
252-
253311
// Parse OpenACC directive on a declaration.
254312
Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() {
255313
assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
256314

257315
ParsingOpenACCDirectiveRAII DirScope(*this);
258316
ConsumeAnnotationToken();
259317

260-
ParseOpenACCDirective(*this);
318+
ParseOpenACCDirective();
261319

262320
return nullptr;
263321
}
@@ -269,7 +327,7 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() {
269327
ParsingOpenACCDirectiveRAII DirScope(*this);
270328
ConsumeAnnotationToken();
271329

272-
ParseOpenACCDirective(*this);
330+
ParseOpenACCDirective();
273331

274332
return StmtEmpty();
275333
}

clang/test/ParserOpenACC/parse-constructs.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,16 @@ void func() {
1616
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
1717
#pragma acc parallel clause list
1818
for(;;){}
19+
// expected-error@+3{{expected clause-list or newline in OpenACC directive}}
1920
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
2021
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
2122
#pragma acc parallel() clause list
23+
for(;;){}
24+
// expected-error@+4{{expected clause-list or newline in OpenACC directive}}
25+
// expected-error@+3{{expected ')'}}
26+
// expected-note@+2{{to match this '('}}
27+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
28+
#pragma acc parallel( clause list
2229
for(;;){}
2330
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
2431
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
@@ -144,3 +151,38 @@ void func() {
144151
#pragma acc update clause list
145152
for(;;){}
146153
}
154+
155+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
156+
#pragma acc routine
157+
void routine_func();
158+
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
159+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
160+
#pragma acc routine clause list
161+
void routine_func();
162+
163+
// expected-error@+2{{use of undeclared identifier 'func_name'}}
164+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
165+
#pragma acc routine (func_name)
166+
// expected-error@+3{{use of undeclared identifier 'func_name'}}
167+
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
168+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
169+
#pragma acc routine (func_name) clause list
170+
171+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
172+
#pragma acc routine (routine_func)
173+
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
174+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
175+
#pragma acc routine (routine_func) clause list
176+
177+
// expected-error@+3{{expected ')'}}
178+
// expected-note@+2{{to match this '('}}
179+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
180+
#pragma acc routine (routine_func())
181+
182+
// expected-error@+2{{expected identifier}}
183+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
184+
#pragma acc routine()
185+
186+
// expected-error@+2{{expected identifier}}
187+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
188+
#pragma acc routine(int)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %clang_cc1 %s -verify -fopenacc
2+
3+
namespace NS {
4+
void foo(); // expected-note{{declared here}}
5+
6+
template<typename T>
7+
void templ(); // expected-note 2{{declared here}}
8+
}
9+
10+
// expected-error@+2{{use of undeclared identifier 'foo'; did you mean 'NS::foo'?}}
11+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
12+
#pragma acc routine(foo)
13+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
14+
#pragma acc routine(NS::foo)
15+
16+
// expected-error@+2{{use of undeclared identifier 'templ'; did you mean 'NS::templ'?}}
17+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
18+
#pragma acc routine(templ)
19+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
20+
#pragma acc routine(NS::templ)
21+
22+
// expected-error@+2{{use of undeclared identifier 'templ'; did you mean 'NS::templ'?}}
23+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
24+
#pragma acc routine(templ<int>)
25+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
26+
#pragma acc routine(NS::templ<int>)
27+
28+
// expected-error@+2{{use of undeclared identifier 'T'}}
29+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
30+
#pragma acc routine(templ<T>)
31+
// expected-error@+2{{use of undeclared identifier 'T'}}
32+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
33+
#pragma acc routine(NS::templ<T>)
34+
35+
// expected-error@+3{{expected ')'}}
36+
// expected-note@+2{{to match this '('}}
37+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
38+
#pragma acc routine (NS::foo())
39+
40+
// expected-error@+2 {{expected unqualified-id}}
41+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
42+
#pragma acc routine()
43+
44+
// expected-error@+2 {{expected unqualified-id}}
45+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
46+
#pragma acc routine(int)

0 commit comments

Comments
 (0)