[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
This commit is contained in:
parent
660632778f
commit
774388241e
|
@ -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<IgnoredPragmas>;
|
||||
def warn_pragma_ms_fenv_access : Warning<
|
||||
"incorrect use of '#pragma fenv_access (on|off)' - ignored">,
|
||||
InGroup<IgnoredPragmas>;
|
||||
def warn_pragma_extra_tokens_at_eol : Warning<
|
||||
"extra tokens at end of '#pragma %0' - ignored">,
|
||||
InGroup<IgnoredPragmas>;
|
||||
|
@ -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<UnknownPragmas>;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -196,6 +196,7 @@ class Parser : public CodeCompletionHandler {
|
|||
std::unique_ptr<PragmaHandler> MSRuntimeChecks;
|
||||
std::unique_ptr<PragmaHandler> MSIntrinsic;
|
||||
std::unique_ptr<PragmaHandler> MSOptimize;
|
||||
std::unique_ptr<PragmaHandler> MSFenvAccess;
|
||||
std::unique_ptr<PragmaHandler> CUDAForceHostDeviceHandler;
|
||||
std::unique_ptr<PragmaHandler> OptimizeHandler;
|
||||
std::unique_ptr<PragmaHandler> LoopHintHandler;
|
||||
|
|
|
@ -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<Token> Toks(
|
||||
PP.getPreprocessorAllocator().Allocate<Token>(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<void*>(static_cast<uintptr_t>(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<PragmaMSOptimizeHandler>();
|
||||
PP.AddPragmaHandler(MSOptimize.get());
|
||||
MSFenvAccess = std::make_unique<PragmaMSFenvAccessHandler>();
|
||||
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<tok::OnOffSwitch>(
|
||||
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}}
|
||||
}
|
Loading…
Reference in New Issue