diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index c3753ca2828e2..54b5ba6e6414b 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1362,7 +1362,7 @@ 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'">; + : Error<"invalid OpenACC directive '%select{%1|%1 %2}0'">; def err_acc_missing_directive : Error<"expected OpenACC directive">; // OpenMP support. diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h index d53b7223b5334..2a818638720ab 100644 --- a/clang/include/clang/Basic/OpenACCKinds.h +++ b/clang/include/clang/Basic/OpenACCKinds.h @@ -24,9 +24,12 @@ enum class OpenACCDirectiveKind { Serial, Kernels, - // Data Environment. + // Data Environment. "enter data" and "exit data" are also referred to in the + // Executable Directives section, but just as a back reference to the Data + // Environment. Data, - // FIXME: 'enter data', 'exit data'. + EnterData, + ExitData, HostData, // Misc. diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index fdf0f24daf985..a0f8fa97f6fa7 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -21,24 +21,45 @@ using namespace clang; using namespace llvm; namespace { - -/// This doesn't completely comprehend 'Compound Constructs' (as it just -/// identifies the first token) just the first token of each. So -/// this should only be used by `ParseOpenACCDirectiveKind`. -OpenACCDirectiveKind getOpenACCDirectiveKind(StringRef Name) { - return llvm::StringSwitch(Name) - .Case("parallel", OpenACCDirectiveKind::Parallel) - .Case("serial", OpenACCDirectiveKind::Serial) - .Case("kernels", OpenACCDirectiveKind::Kernels) - .Case("data", OpenACCDirectiveKind::Data) - .Case("host_data", OpenACCDirectiveKind::HostData) - .Case("loop", OpenACCDirectiveKind::Loop) - .Case("declare", OpenACCDirectiveKind::Declare) - .Case("init", OpenACCDirectiveKind::Init) - .Case("shutdown", OpenACCDirectiveKind::Shutdown) - .Case("set", OpenACCDirectiveKind::Shutdown) - .Case("update", OpenACCDirectiveKind::Update) - .Default(OpenACCDirectiveKind::Invalid); +// An enum that contains the extended 'partial' parsed variants. This type +// should never escape the initial parse functionality, but is useful for +// simplifying the implementation. +enum class OpenACCDirectiveKindEx { + Invalid = static_cast(OpenACCDirectiveKind::Invalid), + // 'enter data' and 'exit data' + Enter, + Exit, + // FIXME: Atomic Variants +}; + +// Translate single-token string representations to the OpenACC Directive Kind. +// This doesn't completely comprehend 'Compound Constructs' (as it just +// identifies the first token), and doesn't fully handle 'enter data', 'exit +// data', nor any of the 'atomic' variants, just the first token of each. So +// this should only be used by `ParseOpenACCDirectiveKind`. +OpenACCDirectiveKindEx getOpenACCDirectiveKind(StringRef Name) { + OpenACCDirectiveKind DirKind = + llvm::StringSwitch(Name) + .Case("parallel", OpenACCDirectiveKind::Parallel) + .Case("serial", OpenACCDirectiveKind::Serial) + .Case("kernels", OpenACCDirectiveKind::Kernels) + .Case("data", OpenACCDirectiveKind::Data) + .Case("host_data", OpenACCDirectiveKind::HostData) + .Case("loop", OpenACCDirectiveKind::Loop) + .Case("declare", OpenACCDirectiveKind::Declare) + .Case("init", OpenACCDirectiveKind::Init) + .Case("shutdown", OpenACCDirectiveKind::Shutdown) + .Case("set", OpenACCDirectiveKind::Shutdown) + .Case("update", OpenACCDirectiveKind::Update) + .Default(OpenACCDirectiveKind::Invalid); + + if (DirKind != OpenACCDirectiveKind::Invalid) + return static_cast(DirKind); + + return llvm::StringSwitch(Name) + .Case("enter", OpenACCDirectiveKindEx::Enter) + .Case("exit", OpenACCDirectiveKindEx::Exit) + .Default(OpenACCDirectiveKindEx::Invalid); } bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) { @@ -59,6 +80,8 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) { case OpenACCDirectiveKind::ParallelLoop: case OpenACCDirectiveKind::SerialLoop: case OpenACCDirectiveKind::KernelsLoop: + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ExitData: return false; case OpenACCDirectiveKind::Declare: @@ -77,6 +100,32 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) { llvm_unreachable("Unknown 'Kind' Passed"); } +OpenACCDirectiveKind +ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok, + StringRef FirstTokSpelling, + OpenACCDirectiveKindEx ExtDirKind) { + Token SecondTok = P.getCurToken(); + + if (SecondTok.isAnnotation()) { + P.Diag(FirstTok, diag::err_acc_invalid_directive) << 0 << FirstTokSpelling; + return OpenACCDirectiveKind::Invalid; + } + + std::string SecondTokSpelling = P.getPreprocessor().getSpelling(SecondTok); + + if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTokSpelling)) { + P.Diag(FirstTok, diag::err_acc_invalid_directive) + << 1 << FirstTokSpelling << SecondTokSpelling; + return OpenACCDirectiveKind::Invalid; + } + + P.ConsumeToken(); + + return ExtDirKind == OpenACCDirectiveKindEx::Enter + ? OpenACCDirectiveKind::EnterData + : OpenACCDirectiveKind::ExitData; +} + // Parse and consume the tokens for OpenACC Directive/Construct kinds. OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) { Token FirstTok = P.getCurToken(); @@ -91,10 +140,28 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) { P.ConsumeToken(); std::string FirstTokSpelling = P.getPreprocessor().getSpelling(FirstTok); - OpenACCDirectiveKind DirKind = getOpenACCDirectiveKind(FirstTokSpelling); + OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTokSpelling); + + // OpenACCDirectiveKindEx is meant to be an extended list + // over OpenACCDirectiveKind, so any value below Invalid is one of the + // OpenACCDirectiveKind values. This switch takes care of all of the extra + // parsing required for the Extended values. At the end of this block, + // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can + // immediately cast it and use it as that. + if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) { + switch (ExDirKind) { + case OpenACCDirectiveKindEx::Invalid: + P.Diag(FirstTok, diag::err_acc_invalid_directive) + << 0 << FirstTokSpelling; + return OpenACCDirectiveKind::Invalid; + case OpenACCDirectiveKindEx::Enter: + case OpenACCDirectiveKindEx::Exit: + return ParseOpenACCEnterExitDataDirective(P, FirstTok, FirstTokSpelling, + ExDirKind); + } + } - if (DirKind == OpenACCDirectiveKind::Invalid) - P.Diag(FirstTok, diag::err_acc_invalid_directive) << FirstTokSpelling; + OpenACCDirectiveKind DirKind = static_cast(ExDirKind); // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any // other attempt at a combined construct will be diagnosed as an invalid diff --git a/clang/test/ParserOpenACC/parse-constructs.c b/clang/test/ParserOpenACC/parse-constructs.c index fcad4507e7c1d..a5270daf6034c 100644 --- a/clang/test/ParserOpenACC/parse-constructs.c +++ b/clang/test/ParserOpenACC/parse-constructs.c @@ -34,6 +34,33 @@ void func() { for(;;){} // expected-warning@+2{{OpenACC clause parsing not yet implemented}} // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc enter data clause list + for(;;){} + // expected-warning@+2{{OpenACC clause parsing not yet implemented}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc exit data clause list + for(;;){} + // expected-error@+3{{invalid OpenACC directive 'enter invalid'}} + // expected-warning@+2{{OpenACC clause parsing not yet implemented}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc enter invalid + for(;;){} + // expected-error@+3{{invalid OpenACC directive 'exit invalid'}} + // expected-warning@+2{{OpenACC clause parsing not yet implemented}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc exit invalid + for(;;){} + // expected-error@+2{{invalid OpenACC directive 'enter'}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc enter + for(;;){} + // expected-error@+3{{invalid OpenACC directive 'exit }'}} + // expected-warning@+2{{OpenACC clause parsing not yet implemented}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc exit } + for(;;){} + // expected-warning@+2{{OpenACC clause parsing not yet implemented}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} #pragma acc host_data clause list for(;;){} // expected-warning@+2{{OpenACC clause parsing not yet implemented}}