From 774388241e25529308c8bbac6012a20b62b82f29 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Fri, 8 Oct 2021 14:21:50 +0200 Subject: [PATCH] [MS compat] Handle #pragma fenv_access like #pragma STDC FENV_ACCESS (PR50694) This adds support for the MSVC spelling of the pragma in -fms-extensions mode. Differential revision: https://reviews.llvm.org/D111440 --- .../clang/Basic/DiagnosticParseKinds.td | 6 +- clang/include/clang/Basic/TokenKinds.def | 3 +- clang/include/clang/Parse/Parser.h | 1 + clang/lib/Parse/ParsePragma.cpp | 69 ++++++++++++++++++- clang/lib/Parse/ParseStmt.cpp | 6 +- clang/lib/Parse/Parser.cpp | 1 + clang/test/CodeGen/pragma-fenv_access.c | 9 +++ clang/test/Parser/pragma-fenv_access-ms.c | 16 +++++ 8 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 clang/test/Parser/pragma-fenv_access-ms.c diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 8ae264caddcb..f42c55be63f9 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1116,6 +1116,9 @@ def warn_pragma_expected_integer : Warning< def warn_pragma_ms_struct : Warning< "incorrect use of '#pragma ms_struct on|off' - ignored">, InGroup; +def warn_pragma_ms_fenv_access : Warning< + "incorrect use of '#pragma fenv_access (on|off)' - ignored">, + InGroup; def warn_pragma_extra_tokens_at_eol : Warning< "extra tokens at end of '#pragma %0' - ignored">, InGroup; @@ -1181,9 +1184,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either // outside external declarations or preceding all explicit declarations and // statements inside a compound statement. -def err_pragma_stdc_fenv_access_scope : Error< - "'#pragma STDC FENV_ACCESS' can only appear at file scope or at the start of" - " a compound statement">; def warn_stdc_fenv_round_not_supported : Warning<"pragma STDC FENV_ROUND is not supported">, InGroup; diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 2b3dfedd020c..0dd5936aa3e6 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -828,10 +828,11 @@ PRAGMA_ANNOTATION(pragma_redefine_extname) // handles them. PRAGMA_ANNOTATION(pragma_fp_contract) -// Annotation for #pragma STDC FENV_ACCESS +// Annotations for #pragma STDC FENV_ACCESS and #pragma fenv_access (MS compat) // The lexer produces these so that they only take effect when the parser // handles them. PRAGMA_ANNOTATION(pragma_fenv_access) +PRAGMA_ANNOTATION(pragma_fenv_access_ms) // Annotation for #pragma STDC FENV_ROUND // The lexer produces these so that they only take effect when the parser diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index de25760017b5..62c0a0d4c0a8 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -196,6 +196,7 @@ class Parser : public CodeCompletionHandler { std::unique_ptr MSRuntimeChecks; std::unique_ptr MSIntrinsic; std::unique_ptr MSOptimize; + std::unique_ptr MSFenvAccess; std::unique_ptr CUDAForceHostDeviceHandler; std::unique_ptr OptimizeHandler; std::unique_ptr LoopHintHandler; diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index c33605ef9025..27e850127862 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -261,6 +261,68 @@ struct PragmaMSOptimizeHandler : public PragmaHandler { Token &FirstToken) override; }; +// "\#pragma fenv_access (on)". +struct PragmaMSFenvAccessHandler : public PragmaHandler { + PragmaMSFenvAccessHandler() : PragmaHandler("fenv_access") {} + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &FirstToken) override { + StringRef PragmaName = FirstToken.getIdentifierInfo()->getName(); + if (!PP.getTargetInfo().hasStrictFP() && !PP.getLangOpts().ExpStrictFP) { + PP.Diag(FirstToken.getLocation(), diag::warn_pragma_fp_ignored) + << PragmaName; + return; + } + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) + << PragmaName; + return; + } + PP.Lex(Tok); // Consume the l_paren. + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_fenv_access); + return; + } + const IdentifierInfo *II = Tok.getIdentifierInfo(); + tok::OnOffSwitch OOS; + if (II->isStr("on")) { + OOS = tok::OOS_ON; + PP.Lex(Tok); + } else if (II->isStr("off")) { + OOS = tok::OOS_OFF; + PP.Lex(Tok); + } else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_fenv_access); + return; + } + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) + << PragmaName; + return; + } + PP.Lex(Tok); // Consume the r_paren. + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << PragmaName; + return; + } + + MutableArrayRef Toks( + PP.getPreprocessorAllocator().Allocate(1), 1); + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_fenv_access_ms); + Toks[0].setLocation(FirstToken.getLocation()); + Toks[0].setAnnotationEndLoc(Tok.getLocation()); + Toks[0].setAnnotationValue( + reinterpret_cast(static_cast(OOS))); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); + } +}; + struct PragmaForceCUDAHostDeviceHandler : public PragmaHandler { PragmaForceCUDAHostDeviceHandler(Sema &Actions) : PragmaHandler("force_cuda_host_device"), Actions(Actions) {} @@ -389,6 +451,8 @@ void Parser::initializePragmaHandlers() { PP.AddPragmaHandler(MSIntrinsic.get()); MSOptimize = std::make_unique(); PP.AddPragmaHandler(MSOptimize.get()); + MSFenvAccess = std::make_unique(); + PP.AddPragmaHandler(MSFenvAccess.get()); } if (getLangOpts().CUDA) { @@ -496,6 +560,8 @@ void Parser::resetPragmaHandlers() { MSIntrinsic.reset(); PP.RemovePragmaHandler(MSOptimize.get()); MSOptimize.reset(); + PP.RemovePragmaHandler(MSFenvAccess.get()); + MSFenvAccess.reset(); } if (getLangOpts().CUDA) { @@ -701,7 +767,8 @@ void Parser::HandlePragmaFloatControl() { } void Parser::HandlePragmaFEnvAccess() { - assert(Tok.is(tok::annot_pragma_fenv_access)); + assert(Tok.is(tok::annot_pragma_fenv_access) || + Tok.is(tok::annot_pragma_fenv_access_ms)); tok::OnOffSwitch OOS = static_cast( reinterpret_cast(Tok.getAnnotationValue())); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 9e259e15bd56..4d76dfe91052 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -374,8 +374,11 @@ Retry: return StmtError(); case tok::annot_pragma_fenv_access: + case tok::annot_pragma_fenv_access_ms: ProhibitAttributes(Attrs); - Diag(Tok, diag::err_pragma_stdc_fenv_access_scope); + Diag(Tok, diag::err_pragma_file_or_compound_scope) + << (Kind == tok::annot_pragma_fenv_access ? "STDC FENV_ACCESS" + : "fenv_access"); ConsumeAnnotationToken(); return StmtEmpty(); @@ -955,6 +958,7 @@ void Parser::ParseCompoundStatementLeadingPragmas() { HandlePragmaFP(); break; case tok::annot_pragma_fenv_access: + case tok::annot_pragma_fenv_access_ms: HandlePragmaFEnvAccess(); break; case tok::annot_pragma_fenv_round: diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index c81dd03ffaaa..11113fa1a060 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -785,6 +785,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, HandlePragmaFPContract(); return nullptr; case tok::annot_pragma_fenv_access: + case tok::annot_pragma_fenv_access_ms: HandlePragmaFEnvAccess(); return nullptr; case tok::annot_pragma_fenv_round: diff --git a/clang/test/CodeGen/pragma-fenv_access.c b/clang/test/CodeGen/pragma-fenv_access.c index fb7b8b2af61d..0e2550bcc477 100644 --- a/clang/test/CodeGen/pragma-fenv_access.c +++ b/clang/test/CodeGen/pragma-fenv_access.c @@ -1,6 +1,11 @@ // RUN: %clang_cc1 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - -fms-extensions -DMS | FileCheck %s +#ifdef MS +#pragma fenv_access (on) +#else #pragma STDC FENV_ACCESS ON +#endif float func_01(float x, float y) { return x + y; @@ -25,7 +30,11 @@ float func_03(float x, float y) { // CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") +#ifdef MS +#pragma fenv_access (off) +#else #pragma STDC FENV_ACCESS OFF +#endif float func_04(float x, float y) { #pragma float_control(except, off) diff --git a/clang/test/Parser/pragma-fenv_access-ms.c b/clang/test/Parser/pragma-fenv_access-ms.c new file mode 100644 index 000000000000..d179dfeb8780 --- /dev/null +++ b/clang/test/Parser/pragma-fenv_access-ms.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple i686-pc-win32 -fms-extensions -fsyntax-only -verify %s + +#pragma fenv_access (on) +#pragma fenv_access (off) + +#pragma fenv_access // expected-warning{{missing '(' after '#pragma fenv_access'}} +#pragma fenv_access foo // expected-warning{{missing '(' after '#pragma fenv_access'}} +#pragma fenv_access on // expected-warning{{missing '(' after '#pragma fenv_access'}} +#pragma fenv_access ( // expected-warning{{incorrect use of '#pragma fenv_access}} +#pragma fenv_access (on // expected-warning{{missing ')' after '#pragma fenv_access'}} +#pragma fenv_access (on) foo // expected-warning{{extra tokens at end of '#pragma fenv_access'}} + +void f() { + (void)0; + #pragma fenv_access (on) // expected-error{{'#pragma fenv_access' can only appear at file scope or at the start of a compound statement}} +}