92 changes: 67 additions & 25 deletions clang/lib/Parse/ParsePragma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,18 +166,51 @@ struct PragmaFPHandler : public PragmaHandler {
Token &FirstToken) override;
};

struct PragmaNoOpenMPHandler : public PragmaHandler {
PragmaNoOpenMPHandler() : PragmaHandler("omp") { }
// A pragma handler to be the base of the NoOpenMPHandler and NoOpenACCHandler,
// which are identical other than the name given to them, and the diagnostic
// emitted.
template <diag::kind IgnoredDiag>
struct PragmaNoSupportHandler : public PragmaHandler {
PragmaNoSupportHandler(StringRef Name) : PragmaHandler(Name) {}
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
Token &FirstToken) override;
};

struct PragmaOpenMPHandler : public PragmaHandler {
PragmaOpenMPHandler() : PragmaHandler("omp") { }
struct PragmaNoOpenMPHandler
: public PragmaNoSupportHandler<diag::warn_pragma_omp_ignored> {
PragmaNoOpenMPHandler() : PragmaNoSupportHandler("omp") {}
};

struct PragmaNoOpenACCHandler
: public PragmaNoSupportHandler<diag::warn_pragma_acc_ignored> {
PragmaNoOpenACCHandler() : PragmaNoSupportHandler("acc") {}
};

// A pragma handler to be the base for the OpenMPHandler and OpenACCHandler,
// which are identical other than the tokens used for the start/end of a pragma
// section, and some diagnostics.
template <tok::TokenKind StartTok, tok::TokenKind EndTok,
diag::kind UnexpectedDiag>
struct PragmaSupportHandler : public PragmaHandler {
PragmaSupportHandler(StringRef Name) : PragmaHandler(Name) {}
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
Token &FirstToken) override;
};

struct PragmaOpenMPHandler
: public PragmaSupportHandler<tok::annot_pragma_openmp,
tok::annot_pragma_openmp_end,
diag::err_omp_unexpected_directive> {
PragmaOpenMPHandler() : PragmaSupportHandler("omp") {}
};

struct PragmaOpenACCHandler
: public PragmaSupportHandler<tok::annot_pragma_openacc,
tok::annot_pragma_openacc_end,
diag::err_acc_unexpected_directive> {
PragmaOpenACCHandler() : PragmaSupportHandler("acc") {}
};

/// PragmaCommentHandler - "\#pragma comment ...".
struct PragmaCommentHandler : public PragmaHandler {
PragmaCommentHandler(Sema &Actions)
Expand Down Expand Up @@ -423,6 +456,12 @@ void Parser::initializePragmaHandlers() {
OpenMPHandler = std::make_unique<PragmaNoOpenMPHandler>();
PP.AddPragmaHandler(OpenMPHandler.get());

if (getLangOpts().OpenACC)
OpenACCHandler = std::make_unique<PragmaOpenACCHandler>();
else
OpenACCHandler = std::make_unique<PragmaNoOpenACCHandler>();
PP.AddPragmaHandler(OpenACCHandler.get());

if (getLangOpts().MicrosoftExt ||
getTargetInfo().getTriple().isOSBinFormatELF()) {
MSCommentHandler = std::make_unique<PragmaCommentHandler>(Actions);
Expand Down Expand Up @@ -542,6 +581,9 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler(OpenMPHandler.get());
OpenMPHandler.reset();

PP.RemovePragmaHandler(OpenACCHandler.get());
OpenACCHandler.reset();

if (getLangOpts().MicrosoftExt ||
getTargetInfo().getTriple().isOSBinFormatELF()) {
PP.RemovePragmaHandler(MSCommentHandler.get());
Expand Down Expand Up @@ -2610,50 +2652,50 @@ void PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
StateLoc, State);
}

/// Handle '#pragma omp ...' when OpenMP is disabled.
///
void PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducer Introducer,
Token &FirstTok) {
if (!PP.getDiagnostics().isIgnored(diag::warn_pragma_omp_ignored,
FirstTok.getLocation())) {
PP.Diag(FirstTok, diag::warn_pragma_omp_ignored);
PP.getDiagnostics().setSeverity(diag::warn_pragma_omp_ignored,
diag::Severity::Ignored, SourceLocation());
/// Handle '#pragma omp ...' when OpenMP is disabled and '#pragma acc ...' when
/// OpenACC is disabled.
template <diag::kind IgnoredDiag>
void PragmaNoSupportHandler<IgnoredDiag>::HandlePragma(
Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstTok) {
if (!PP.getDiagnostics().isIgnored(IgnoredDiag, FirstTok.getLocation())) {
PP.Diag(FirstTok, IgnoredDiag);
PP.getDiagnostics().setSeverity(IgnoredDiag, diag::Severity::Ignored,
SourceLocation());
}
PP.DiscardUntilEndOfDirective();
}

/// Handle '#pragma omp ...' when OpenMP is enabled.
///
void PragmaOpenMPHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducer Introducer,
Token &FirstTok) {
/// Handle '#pragma omp ...' when OpenMP is enabled, and handle '#pragma acc...'
/// when OpenACC is enabled.
template <tok::TokenKind StartTok, tok::TokenKind EndTok,
diag::kind UnexpectedDiag>
void PragmaSupportHandler<StartTok, EndTok, UnexpectedDiag>::HandlePragma(
Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstTok) {
SmallVector<Token, 16> Pragma;
Token Tok;
Tok.startToken();
Tok.setKind(tok::annot_pragma_openmp);
Tok.setKind(StartTok);
Tok.setLocation(Introducer.Loc);

while (Tok.isNot(tok::eod) && Tok.isNot(tok::eof)) {
Pragma.push_back(Tok);
PP.Lex(Tok);
if (Tok.is(tok::annot_pragma_openmp)) {
PP.Diag(Tok, diag::err_omp_unexpected_directive) << 0;
if (Tok.is(StartTok)) {
PP.Diag(Tok, UnexpectedDiag) << 0;
unsigned InnerPragmaCnt = 1;
while (InnerPragmaCnt != 0) {
PP.Lex(Tok);
if (Tok.is(tok::annot_pragma_openmp))
if (Tok.is(StartTok))
++InnerPragmaCnt;
else if (Tok.is(tok::annot_pragma_openmp_end))
else if (Tok.is(EndTok))
--InnerPragmaCnt;
}
PP.Lex(Tok);
}
}
SourceLocation EodLoc = Tok.getLocation();
Tok.startToken();
Tok.setKind(tok::annot_pragma_openmp_end);
Tok.setKind(EndTok);
Tok.setLocation(EodLoc);
Pragma.push_back(Tok);

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,9 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
// Do not prohibit attributes if they were OpenMP attributes.
return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx);

case tok::annot_pragma_openacc:
return ParseOpenACCDirectiveStmt();

case tok::annot_pragma_ms_pointers_to_members:
ProhibitAttributes(CXX11Attrs);
ProhibitAttributes(GNUAttrs);
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,12 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
return false;
ConsumeAnnotationToken();
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.
ConsumeAnnotationToken();
break;
case tok::annot_module_begin:
case tok::annot_module_end:
case tok::annot_module_include:
Expand Down Expand Up @@ -850,6 +856,8 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
AccessSpecifier AS = AS_none;
return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
}
case tok::annot_pragma_openacc:
return ParseOpenACCDirective();
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
return nullptr;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1819,6 +1819,8 @@ Token ASTReader::ReadToken(ModuleFile &F, const RecordDataImpl &Record,
case tok::annot_pragma_openmp:
case tok::annot_pragma_openmp_end:
case tok::annot_pragma_unused:
case tok::annot_pragma_openacc:
case tok::annot_pragma_openacc_end:
break;
default:
llvm_unreachable("missing deserialization code for annotation token");
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4499,6 +4499,8 @@ void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) {
case tok::annot_pragma_openmp:
case tok::annot_pragma_openmp_end:
case tok::annot_pragma_unused:
case tok::annot_pragma_openacc:
case tok::annot_pragma_openacc_end:
break;
default:
llvm_unreachable("missing serialization code for annotation token");
Expand Down
14 changes: 14 additions & 0 deletions clang/test/Driver/openacc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %clang -S -### -fopenacc %s 2>&1 | FileCheck %s --check-prefix=CHECK-DRIVER
// CHECK-DRIVER: "-cc1" {{.*}} "-fopenacc"
bcardosolopes marked this conversation as resolved.
Show resolved Hide resolved

// RUN: %clang -S -### -fopenacc -fexperimental-openacc-macro-override=202211 %s 2>&1 | FileCheck %s --check-prefix=CHECK-MACRO-OVERRIDE
// RUN: %clang -S -### -fopenacc -fexperimental-openacc-macro-override 202211 %s 2>&1 | FileCheck %s --check-prefix=CHECK-MACRO-OVERRIDE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need this new option fexperimental-openacc-macro-override? Can you just rely on -D_OPENACC instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot, because this is a 'builtin' macro, overriding it on the command line is essentially UB. Additionally, this clarifies that it is an experimental patch, which is less likely to be a concern when we remove it in the future. That is, the intent is to prevent folks from coming to depend on this in the future.

// CHECK-MACRO-OVERRIDE: "-cc1"{{.*}} "-fexperimental-openacc-macro-override" "202211"

// RUN: not %clang -S -fopenacc -fexperimental-openacc-macro-override=202211L %s 2>&1 | FileCheck %s --check-prefix=INVALID
// RUN: not %clang -S -fopenacc -fexperimental-openacc-macro-override 202211L %s 2>&1 | FileCheck %s --check-prefix=INVALID
// RUN: not %clang -S -fopenacc -fexperimental-openacc-macro-override=L202211 %s 2>&1 | FileCheck %s --check-prefix=INVALID
// RUN: not %clang -S -fopenacc -fexperimental-openacc-macro-override L202211 %s 2>&1 | FileCheck %s --check-prefix=INVALID
// RUN: not %clang -S -fopenacc -fexperimental-openacc-macro-override=2022L11 %s 2>&1 | FileCheck %s --check-prefix=INVALID
// RUN: not %clang -S -fopenacc -fexperimental-openacc-macro-override 2022L11 %s 2>&1 | FileCheck %s --check-prefix=INVALID
// INVALID: error: the clang compiler does not support
4 changes: 4 additions & 0 deletions clang/test/ParserOpenACC/disabled.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// RUN: %clang_cc1 %s -verify -Wsource-uses-openacc
// expected-warning@+1{{unexpected '#pragma acc ...' in program}}
#pragma acc foo bar baz blitz.
int foo;
20 changes: 20 additions & 0 deletions clang/test/ParserOpenACC/unimplemented.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %clang_cc1 %s -verify -fopenacc

// Parser::ParseExternalDeclaration
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc not yet implemented
int foo;

struct S {
// Parser::ParseStructUnionBody
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc not yet implemented
int foo;
};

void func() {
// Parser::ParseStmtOrDeclarationAfterAttributes
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc not yet implemented
while(0) {}
}
20 changes: 20 additions & 0 deletions clang/test/ParserOpenACC/unimplemented.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %clang_cc1 %s -verify -fopenacc

// Parser::ParseExternalDeclaration
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc not yet implemented
int foo;

struct S {
// Parser::ParseCXXClassMemberDeclarationWithPragmas
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc not yet implemented
int foo;
};

void func() {
// Parser::ParseStmtOrDeclarationAfterAttributes
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc not yet implemented
while(false) {}
}
13 changes: 13 additions & 0 deletions clang/test/Preprocessor/openacc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %clang_cc1 -E -fopenacc %s | FileCheck %s --check-prefix=DEFAULT
// RUN: %clang_cc1 -E -fopenacc -fexperimental-openacc-macro-override 202211 %s | FileCheck %s --check-prefix=OVERRIDE

// DEFAULT: OpenACC:1:
// OVERRIDE: OpenACC:202211:
OpenACC:_OPENACC:

// RUN: %clang_cc1 -E -dM -fopenacc %s | FileCheck %s --check-prefix=MACRO_PRINT_DEF
// RUN: %clang_cc1 -E -dM -fopenacc -fexperimental-openacc-macro-override 202211 %s | FileCheck %s --check-prefix=MACRO_PRINT_OVR
// MACRO_PRINT_DEF: #define _OPENACC 1
// MACRO_PRINT_OVR: #define _OPENACC 202211