diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index c3d06053caa5e..1beddb5808fa2 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1343,13 +1343,20 @@ def err_openclcxx_virtual_function : Error< "virtual functions are not supported in C++ for OpenCL">; // OpenACC Support. -def warn_pragma_acc_ignored : Warning< - "unexpected '#pragma acc ...' in program">, InGroup, DefaultIgnore; -def err_acc_unexpected_directive : Error< - "unexpected OpenACC directive %select{|'#pragma acc %1'}0">; +def warn_pragma_acc_ignored + : Warning<"unexpected '#pragma acc ...' in program">, + InGroup, + DefaultIgnore; +def err_acc_unexpected_directive + : Error<"unexpected OpenACC directive %select{|'#pragma acc %1'}0">; def warn_pragma_acc_unimplemented : Warning<"OpenACC directives not yet implemented, pragma ignored">, InGroup; +def warn_pragma_acc_unimplemented_clause_parsing + : Warning<"OpenACC clause parsing not yet implemented">, + InGroup; +def err_acc_invalid_directive + : Error<"invalid OpenACC directive '%0'">; // OpenMP support. def warn_pragma_omp_ignored : Warning< diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h new file mode 100644 index 0000000000000..79780b7fe6835 --- /dev/null +++ b/clang/include/clang/Basic/OpenACCKinds.h @@ -0,0 +1,30 @@ +//===--- OpenACCKinds.h - OpenACC Enums -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Defines some OpenACC-specific enums and functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_OPENACCKINDS_H +#define LLVM_CLANG_BASIC_OPENACCKINDS_H + +namespace clang { +// Represents the Construct/Directive kind of a pragma directive. Note the +// OpenACC standard is inconsistent between calling these Construct vs +// Directive, but we're calling it a Directive to be consistent with OpenMP. +enum class OpenACCDirectiveKind { + // Compute Constructs. + Parallel, + + // Invalid. + Invalid, +}; +} // namespace clang + +#endif // LLVM_CLANG_BASIC_OPENACCKINDS_H diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 2f56da8439d07..d20a26dbf2562 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -53,6 +53,7 @@ namespace clang { class Parser : public CodeCompletionHandler { friend class ColonProtectionRAIIObject; friend class ParsingOpenMPDirectiveRAII; + friend class ParsingOpenACCDirectiveRAII; friend class InMessageExpressionRAIIObject; friend class OffsetOfStateRAIIObject; friend class PoisonSEHIdentifiersRAIIObject; @@ -230,6 +231,9 @@ class Parser : public CodeCompletionHandler { /// Parsing OpenMP directive mode. bool OpenMPDirectiveParsing = false; + /// Parsing OpenACC directive mode. + bool OpenACCDirectiveParsing = false; + /// When true, we are directly inside an Objective-C message /// send expression. /// diff --git a/clang/include/clang/Parse/RAIIObjectsForParser.h b/clang/include/clang/Parse/RAIIObjectsForParser.h index cb525c9d0edd6..e1626a7870bb7 100644 --- a/clang/include/clang/Parse/RAIIObjectsForParser.h +++ b/clang/include/clang/Parse/RAIIObjectsForParser.h @@ -309,6 +309,25 @@ namespace clang { ~ParsingOpenMPDirectiveRAII() { restore(); } }; + /// Activates OpenACC parsing mode to preseve OpenACC specific annotation + /// tokens. + class ParsingOpenACCDirectiveRAII { + Parser &P; + bool OldVal; + + public: + ParsingOpenACCDirectiveRAII(Parser &P, bool Value = true) + : P(P), OldVal(P.OpenACCDirectiveParsing) { + P.OpenACCDirectiveParsing = Value; + } + + /// This can be used to restore the state early, before the dtor + /// is run. + void restore() { P.OpenMPDirectiveParsing = OldVal; } + + ~ParsingOpenACCDirectiveRAII() { restore(); } + }; + /// RAII object that makes '>' behave either as an operator /// or as the closing angle bracket for a template argument list. class GreaterThanIsOperatorScope { diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index ab790515caa7e..9f13aadf92e4f 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -10,18 +10,79 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/OpenACCKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" +#include "clang/Parse/RAIIObjectsForParser.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" using namespace clang; +using namespace llvm; +namespace { + +// Translate single-token string representations to the OpenACC Directive Kind. +OpenACCDirectiveKind GetOpenACCDirectiveKind(StringRef Name) { + return llvm::StringSwitch(Name) + .Case("parallel", OpenACCDirectiveKind::Parallel) + .Default(OpenACCDirectiveKind::Invalid); +} + +// Parse and consume the tokens for OpenACC Directive/Construct kinds. +OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) { + Token FirstTok = P.getCurToken(); + P.ConsumeToken(); + std::string FirstTokSpelling = P.getPreprocessor().getSpelling(FirstTok); + + OpenACCDirectiveKind DirKind = GetOpenACCDirectiveKind(FirstTokSpelling); + + if (DirKind == OpenACCDirectiveKind::Invalid) + P.Diag(FirstTok, diag::err_acc_invalid_directive) << FirstTokSpelling; + + return DirKind; +} + +void ParseOpenACCClauseList(Parser &P) { + // FIXME: In the future, we'll start parsing the clauses here, but for now we + // haven't implemented that, so just emit the unimplemented diagnostic and + // fail reasonably. + if (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) + P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented_clause_parsing); +} + +void ParseOpenACCDirective(Parser &P) { + ParseOpenACCDirectiveKind(P); + + // Parses the list of clauses, if present. + ParseOpenACCClauseList(P); + + P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented); + P.SkipUntil(tok::annot_pragma_openacc_end); +} + +} // namespace + +// Parse OpenACC directive on a declaration. Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() { - Diag(Tok, diag::warn_pragma_acc_unimplemented); - SkipUntil(tok::annot_pragma_openacc_end); + assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token"); + + ParsingOpenACCDirectiveRAII DirScope(*this); + ConsumeAnnotationToken(); + + ParseOpenACCDirective(*this); + return nullptr; } + +// Parse OpenACC Directive on a Statement. StmtResult Parser::ParseOpenACCDirectiveStmt() { - Diag(Tok, diag::warn_pragma_acc_unimplemented); - SkipUntil(tok::annot_pragma_openacc_end); + assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token"); + + ParsingOpenACCDirectiveRAII DirScope(*this); + ConsumeAnnotationToken(); + + ParseOpenACCDirective(*this); + return StmtEmpty(); } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 9eed088208871..1baeb2aeb021f 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -320,8 +320,9 @@ bool Parser::SkipUntil(ArrayRef Toks, SkipUntilFlags Flags) { break; case tok::annot_pragma_openacc: case tok::annot_pragma_openacc_end: - // FIXME: Like OpenMP above, we should not be doing this if we're parsing - // an OpenACC Directive. + // Stop before an OpenACC pragma boundary. + if (OpenACCDirectiveParsing) + return false; ConsumeAnnotationToken(); break; case tok::annot_module_begin: diff --git a/clang/test/ParserOpenACC/parse-constructs.c b/clang/test/ParserOpenACC/parse-constructs.c new file mode 100644 index 0000000000000..4c2188cc3cef1 --- /dev/null +++ b/clang/test/ParserOpenACC/parse-constructs.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -verify -fopenacc + +void func() { + // expected-error@+2{{invalid OpenACC directive 'invalid'}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc invalid + for(;;){} + + // 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-warning@+2{{OpenACC clause parsing not yet implemented}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc parallel() clause list +} diff --git a/clang/test/ParserOpenACC/unimplemented.c b/clang/test/ParserOpenACC/unimplemented.c index c1228c8f2b97f..dd2e8bea74709 100644 --- a/clang/test/ParserOpenACC/unimplemented.c +++ b/clang/test/ParserOpenACC/unimplemented.c @@ -1,12 +1,16 @@ // RUN: %clang_cc1 %s -verify -fopenacc // Parser::ParseExternalDeclaration +// expected-error@+3{{invalid OpenACC directive 'not'}} +// expected-warning@+2{{OpenACC clause parsing not yet implemented}} // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} #pragma acc not yet implemented int foo; struct S { // Parser::ParseStructUnionBody +// expected-error@+3{{invalid OpenACC directive 'not'}} +// expected-warning@+2{{OpenACC clause parsing not yet implemented}} // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} #pragma acc not yet implemented int foo; @@ -14,6 +18,8 @@ struct S { void func() { // Parser::ParseStmtOrDeclarationAfterAttributes +// expected-error@+3{{invalid OpenACC directive 'not'}} +// expected-warning@+2{{OpenACC clause parsing not yet implemented}} // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} #pragma acc not yet implemented while(0) {} diff --git a/clang/test/ParserOpenACC/unimplemented.cpp b/clang/test/ParserOpenACC/unimplemented.cpp index 095cbf570a41a..4f6c5a649065e 100644 --- a/clang/test/ParserOpenACC/unimplemented.cpp +++ b/clang/test/ParserOpenACC/unimplemented.cpp @@ -1,12 +1,16 @@ // RUN: %clang_cc1 %s -verify -fopenacc // Parser::ParseExternalDeclaration +// expected-error@+3{{invalid OpenACC directive 'not'}} +// expected-warning@+2{{OpenACC clause parsing not yet implemented}} // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} #pragma acc not yet implemented int foo; struct S { // Parser::ParseCXXClassMemberDeclarationWithPragmas +// expected-error@+3{{invalid OpenACC directive 'not'}} +// expected-warning@+2{{OpenACC clause parsing not yet implemented}} // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} #pragma acc not yet implemented int foo; @@ -14,6 +18,8 @@ struct S { void func() { // Parser::ParseStmtOrDeclarationAfterAttributes +// expected-error@+3{{invalid OpenACC directive 'not'}} +// expected-warning@+2{{OpenACC clause parsing not yet implemented}} // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} #pragma acc not yet implemented while(false) {}