Skip to content

Commit

Permalink
[OpenACC] Implement 'routine' construct parsing (#73143)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
erichkeane committed Nov 27, 2023
1 parent bf02c84 commit ba1c869
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 11 deletions.
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1364,6 +1364,8 @@ def warn_pragma_acc_unimplemented_clause_parsing
def err_acc_invalid_directive
: Error<"invalid OpenACC directive '%select{%1|%1 %2}0'">;
def err_acc_missing_directive : Error<"expected OpenACC directive">;
def err_acc_invalid_open_paren
: Error<"expected clause-list or newline in OpenACC directive">;

// OpenMP support.
def warn_pragma_omp_ignored : Warning<
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/OpenACCKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ enum class OpenACCDirectiveKind {
Update,
// FIXME: wait construct.

// FIXME: routine construct.
// Procedure Calls in Compute Regions.
Routine,

// Invalid.
Invalid,
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3532,9 +3532,14 @@ class Parser : public CodeCompletionHandler {
/// Placeholder for now, should just ignore the directives after emitting a
/// diagnostic. Eventually will be split into a few functions to parse
/// different situations.
public:
DeclGroupPtrTy ParseOpenACCDirectiveDecl();
StmtResult ParseOpenACCDirectiveStmt();

private:
void ParseOpenACCDirective();
ExprResult ParseOpenACCRoutineName();

private:
//===--------------------------------------------------------------------===//
// C++ 14: Templates [temp]
Expand Down
78 changes: 68 additions & 10 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ OpenACCDirectiveKindEx getOpenACCDirectiveKind(StringRef Name) {
.Case("host_data", OpenACCDirectiveKind::HostData)
.Case("loop", OpenACCDirectiveKind::Loop)
.Case("atomic", OpenACCDirectiveKind::Atomic)
.Case("routine", OpenACCDirectiveKind::Routine)
.Case("declare", OpenACCDirectiveKind::Declare)
.Case("init", OpenACCDirectiveKind::Init)
.Case("shutdown", OpenACCDirectiveKind::Shutdown)
Expand Down Expand Up @@ -97,6 +98,8 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {

case OpenACCDirectiveKind::Atomic:
return Tok == "atomic";
case OpenACCDirectiveKind::Routine:
return Tok == "routine";
case OpenACCDirectiveKind::Declare:
return Tok == "declare";
case OpenACCDirectiveKind::Init:
Expand Down Expand Up @@ -232,32 +235,87 @@ void ParseOpenACCClauseList(Parser &P) {
P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented_clause_parsing);
}

void ParseOpenACCDirective(Parser &P) {
OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(P);
} // namespace

// Routine has an optional paren-wrapped name of a function in the local scope.
// We parse the name, emitting any diagnostics
ExprResult Parser::ParseOpenACCRoutineName() {

ExprResult Res;
if (getLangOpts().CPlusPlus) {
Res = ParseCXXIdExpression(/*isAddressOfOperand=*/false);
} else {
// There isn't anything quite the same as ParseCXXIdExpression for C, so we
// need to get the identifier, then call into Sema ourselves.

if (expectIdentifier())
return ExprError();

Token FuncName = getCurToken();
UnqualifiedId Name;
CXXScopeSpec ScopeSpec;
SourceLocation TemplateKWLoc;
Name.setIdentifier(FuncName.getIdentifierInfo(), ConsumeToken());

// Ensure this is a valid identifier. We don't accept causing implicit
// function declarations per the spec, so always claim to not have trailing
// L Paren.
Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
Name, /*HasTrailingLParen=*/false,
/*isAddressOfOperand=*/false);
}

return getActions().CorrectDelayedTyposInExpr(Res);
}

void Parser::ParseOpenACCDirective() {
OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this);

// Once we've parsed the construct/directive name, some have additional
// specifiers that need to be taken care of. Atomic has an 'atomic-clause'
// that needs to be parsed.
if (DirKind == OpenACCDirectiveKind::Atomic)
ParseOpenACCAtomicKind(P);
ParseOpenACCAtomicKind(*this);

// We've successfully parsed the construct/directive name, however a few of
// the constructs have optional parens that contain further details.
BalancedDelimiterTracker T(*this, tok::l_paren,
tok::annot_pragma_openacc_end);

if (!T.consumeOpen()) {
switch (DirKind) {
default:
Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren);
T.skipToEnd();
break;
case OpenACCDirectiveKind::Routine: {
ExprResult RoutineName = ParseOpenACCRoutineName();
// If the routine name is invalid, just skip until the closing paren to
// recover more gracefully.
if (RoutineName.isInvalid())
T.skipToEnd();
else
T.consumeClose();
break;
}
}
}

// Parses the list of clauses, if present.
ParseOpenACCClauseList(P);
ParseOpenACCClauseList(*this);

P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented);
P.SkipUntil(tok::annot_pragma_openacc_end);
Diag(getCurToken(), diag::warn_pragma_acc_unimplemented);
SkipUntil(tok::annot_pragma_openacc_end);
}

} // namespace

// Parse OpenACC directive on a declaration.
Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() {
assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");

ParsingOpenACCDirectiveRAII DirScope(*this);
ConsumeAnnotationToken();

ParseOpenACCDirective(*this);
ParseOpenACCDirective();

return nullptr;
}
Expand All @@ -269,7 +327,7 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() {
ParsingOpenACCDirectiveRAII DirScope(*this);
ConsumeAnnotationToken();

ParseOpenACCDirective(*this);
ParseOpenACCDirective();

return StmtEmpty();
}
42 changes: 42 additions & 0 deletions clang/test/ParserOpenACC/parse-constructs.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,16 @@ void func() {
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc parallel clause list
for(;;){}
// expected-error@+3{{expected clause-list or newline in OpenACC directive}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc parallel() clause list
for(;;){}
// expected-error@+4{{expected clause-list or newline in OpenACC directive}}
// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc parallel( clause list
for(;;){}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
Expand Down Expand Up @@ -144,3 +151,38 @@ void func() {
#pragma acc update clause list
for(;;){}
}

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine
void routine_func();
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine clause list
void routine_func();

// expected-error@+2{{use of undeclared identifier 'func_name'}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine (func_name)
// expected-error@+3{{use of undeclared identifier 'func_name'}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine (func_name) clause list

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine (routine_func)
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine (routine_func) clause list

// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine (routine_func())

// expected-error@+2{{expected identifier}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine()

// expected-error@+2{{expected identifier}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine(int)
46 changes: 46 additions & 0 deletions clang/test/ParserOpenACC/parse-constructs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// RUN: %clang_cc1 %s -verify -fopenacc

namespace NS {
void foo(); // expected-note{{declared here}}

template<typename T>
void templ(); // expected-note 2{{declared here}}
}

// expected-error@+2{{use of undeclared identifier 'foo'; did you mean 'NS::foo'?}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine(foo)
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine(NS::foo)

// expected-error@+2{{use of undeclared identifier 'templ'; did you mean 'NS::templ'?}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine(templ)
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine(NS::templ)

// expected-error@+2{{use of undeclared identifier 'templ'; did you mean 'NS::templ'?}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine(templ<int>)
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine(NS::templ<int>)

// expected-error@+2{{use of undeclared identifier 'T'}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine(templ<T>)
// expected-error@+2{{use of undeclared identifier 'T'}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine(NS::templ<T>)

// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine (NS::foo())

// expected-error@+2 {{expected unqualified-id}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine()

// expected-error@+2 {{expected unqualified-id}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc routine(int)

0 comments on commit ba1c869

Please sign in to comment.