Skip to content

Commit 7743882

Browse files
committed
[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
1 parent 6606327 commit 7743882

File tree

8 files changed

+105
-6
lines changed

8 files changed

+105
-6
lines changed

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,9 @@ def warn_pragma_expected_integer : Warning<
11161116
def warn_pragma_ms_struct : Warning<
11171117
"incorrect use of '#pragma ms_struct on|off' - ignored">,
11181118
InGroup<IgnoredPragmas>;
1119+
def warn_pragma_ms_fenv_access : Warning<
1120+
"incorrect use of '#pragma fenv_access (on|off)' - ignored">,
1121+
InGroup<IgnoredPragmas>;
11191122
def warn_pragma_extra_tokens_at_eol : Warning<
11201123
"extra tokens at end of '#pragma %0' - ignored">,
11211124
InGroup<IgnoredPragmas>;
@@ -1181,9 +1184,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
11811184
// The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either
11821185
// outside external declarations or preceding all explicit declarations and
11831186
// statements inside a compound statement.
1184-
def err_pragma_stdc_fenv_access_scope : Error<
1185-
"'#pragma STDC FENV_ACCESS' can only appear at file scope or at the start of"
1186-
" a compound statement">;
11871187
def warn_stdc_fenv_round_not_supported :
11881188
Warning<"pragma STDC FENV_ROUND is not supported">,
11891189
InGroup<UnknownPragmas>;

clang/include/clang/Basic/TokenKinds.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,10 +828,11 @@ PRAGMA_ANNOTATION(pragma_redefine_extname)
828828
// handles them.
829829
PRAGMA_ANNOTATION(pragma_fp_contract)
830830

831-
// Annotation for #pragma STDC FENV_ACCESS
831+
// Annotations for #pragma STDC FENV_ACCESS and #pragma fenv_access (MS compat)
832832
// The lexer produces these so that they only take effect when the parser
833833
// handles them.
834834
PRAGMA_ANNOTATION(pragma_fenv_access)
835+
PRAGMA_ANNOTATION(pragma_fenv_access_ms)
835836

836837
// Annotation for #pragma STDC FENV_ROUND
837838
// The lexer produces these so that they only take effect when the parser

clang/include/clang/Parse/Parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ class Parser : public CodeCompletionHandler {
196196
std::unique_ptr<PragmaHandler> MSRuntimeChecks;
197197
std::unique_ptr<PragmaHandler> MSIntrinsic;
198198
std::unique_ptr<PragmaHandler> MSOptimize;
199+
std::unique_ptr<PragmaHandler> MSFenvAccess;
199200
std::unique_ptr<PragmaHandler> CUDAForceHostDeviceHandler;
200201
std::unique_ptr<PragmaHandler> OptimizeHandler;
201202
std::unique_ptr<PragmaHandler> LoopHintHandler;

clang/lib/Parse/ParsePragma.cpp

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,68 @@ struct PragmaMSOptimizeHandler : public PragmaHandler {
261261
Token &FirstToken) override;
262262
};
263263

264+
// "\#pragma fenv_access (on)".
265+
struct PragmaMSFenvAccessHandler : public PragmaHandler {
266+
PragmaMSFenvAccessHandler() : PragmaHandler("fenv_access") {}
267+
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
268+
Token &FirstToken) override {
269+
StringRef PragmaName = FirstToken.getIdentifierInfo()->getName();
270+
if (!PP.getTargetInfo().hasStrictFP() && !PP.getLangOpts().ExpStrictFP) {
271+
PP.Diag(FirstToken.getLocation(), diag::warn_pragma_fp_ignored)
272+
<< PragmaName;
273+
return;
274+
}
275+
276+
Token Tok;
277+
PP.Lex(Tok);
278+
if (Tok.isNot(tok::l_paren)) {
279+
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
280+
<< PragmaName;
281+
return;
282+
}
283+
PP.Lex(Tok); // Consume the l_paren.
284+
if (Tok.isNot(tok::identifier)) {
285+
PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_fenv_access);
286+
return;
287+
}
288+
const IdentifierInfo *II = Tok.getIdentifierInfo();
289+
tok::OnOffSwitch OOS;
290+
if (II->isStr("on")) {
291+
OOS = tok::OOS_ON;
292+
PP.Lex(Tok);
293+
} else if (II->isStr("off")) {
294+
OOS = tok::OOS_OFF;
295+
PP.Lex(Tok);
296+
} else {
297+
PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_fenv_access);
298+
return;
299+
}
300+
if (Tok.isNot(tok::r_paren)) {
301+
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen)
302+
<< PragmaName;
303+
return;
304+
}
305+
PP.Lex(Tok); // Consume the r_paren.
306+
307+
if (Tok.isNot(tok::eod)) {
308+
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
309+
<< PragmaName;
310+
return;
311+
}
312+
313+
MutableArrayRef<Token> Toks(
314+
PP.getPreprocessorAllocator().Allocate<Token>(1), 1);
315+
Toks[0].startToken();
316+
Toks[0].setKind(tok::annot_pragma_fenv_access_ms);
317+
Toks[0].setLocation(FirstToken.getLocation());
318+
Toks[0].setAnnotationEndLoc(Tok.getLocation());
319+
Toks[0].setAnnotationValue(
320+
reinterpret_cast<void*>(static_cast<uintptr_t>(OOS)));
321+
PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
322+
/*IsReinject=*/false);
323+
}
324+
};
325+
264326
struct PragmaForceCUDAHostDeviceHandler : public PragmaHandler {
265327
PragmaForceCUDAHostDeviceHandler(Sema &Actions)
266328
: PragmaHandler("force_cuda_host_device"), Actions(Actions) {}
@@ -389,6 +451,8 @@ void Parser::initializePragmaHandlers() {
389451
PP.AddPragmaHandler(MSIntrinsic.get());
390452
MSOptimize = std::make_unique<PragmaMSOptimizeHandler>();
391453
PP.AddPragmaHandler(MSOptimize.get());
454+
MSFenvAccess = std::make_unique<PragmaMSFenvAccessHandler>();
455+
PP.AddPragmaHandler(MSFenvAccess.get());
392456
}
393457

394458
if (getLangOpts().CUDA) {
@@ -496,6 +560,8 @@ void Parser::resetPragmaHandlers() {
496560
MSIntrinsic.reset();
497561
PP.RemovePragmaHandler(MSOptimize.get());
498562
MSOptimize.reset();
563+
PP.RemovePragmaHandler(MSFenvAccess.get());
564+
MSFenvAccess.reset();
499565
}
500566

501567
if (getLangOpts().CUDA) {
@@ -701,7 +767,8 @@ void Parser::HandlePragmaFloatControl() {
701767
}
702768

703769
void Parser::HandlePragmaFEnvAccess() {
704-
assert(Tok.is(tok::annot_pragma_fenv_access));
770+
assert(Tok.is(tok::annot_pragma_fenv_access) ||
771+
Tok.is(tok::annot_pragma_fenv_access_ms));
705772
tok::OnOffSwitch OOS =
706773
static_cast<tok::OnOffSwitch>(
707774
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));

clang/lib/Parse/ParseStmt.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,11 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
374374
return StmtError();
375375

376376
case tok::annot_pragma_fenv_access:
377+
case tok::annot_pragma_fenv_access_ms:
377378
ProhibitAttributes(Attrs);
378-
Diag(Tok, diag::err_pragma_stdc_fenv_access_scope);
379+
Diag(Tok, diag::err_pragma_file_or_compound_scope)
380+
<< (Kind == tok::annot_pragma_fenv_access ? "STDC FENV_ACCESS"
381+
: "fenv_access");
379382
ConsumeAnnotationToken();
380383
return StmtEmpty();
381384

@@ -955,6 +958,7 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
955958
HandlePragmaFP();
956959
break;
957960
case tok::annot_pragma_fenv_access:
961+
case tok::annot_pragma_fenv_access_ms:
958962
HandlePragmaFEnvAccess();
959963
break;
960964
case tok::annot_pragma_fenv_round:

clang/lib/Parse/Parser.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
785785
HandlePragmaFPContract();
786786
return nullptr;
787787
case tok::annot_pragma_fenv_access:
788+
case tok::annot_pragma_fenv_access_ms:
788789
HandlePragmaFEnvAccess();
789790
return nullptr;
790791
case tok::annot_pragma_fenv_round:

clang/test/CodeGen/pragma-fenv_access.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
// RUN: %clang_cc1 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
2+
// RUN: %clang_cc1 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - -fms-extensions -DMS | FileCheck %s
23

4+
#ifdef MS
5+
#pragma fenv_access (on)
6+
#else
37
#pragma STDC FENV_ACCESS ON
8+
#endif
49

510
float func_01(float x, float y) {
611
return x + y;
@@ -25,7 +30,11 @@ float func_03(float x, float y) {
2530
// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
2631

2732

33+
#ifdef MS
34+
#pragma fenv_access (off)
35+
#else
2836
#pragma STDC FENV_ACCESS OFF
37+
#endif
2938

3039
float func_04(float x, float y) {
3140
#pragma float_control(except, off)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_cc1 -triple i686-pc-win32 -fms-extensions -fsyntax-only -verify %s
2+
3+
#pragma fenv_access (on)
4+
#pragma fenv_access (off)
5+
6+
#pragma fenv_access // expected-warning{{missing '(' after '#pragma fenv_access'}}
7+
#pragma fenv_access foo // expected-warning{{missing '(' after '#pragma fenv_access'}}
8+
#pragma fenv_access on // expected-warning{{missing '(' after '#pragma fenv_access'}}
9+
#pragma fenv_access ( // expected-warning{{incorrect use of '#pragma fenv_access}}
10+
#pragma fenv_access (on // expected-warning{{missing ')' after '#pragma fenv_access'}}
11+
#pragma fenv_access (on) foo // expected-warning{{extra tokens at end of '#pragma fenv_access'}}
12+
13+
void f() {
14+
(void)0;
15+
#pragma fenv_access (on) // expected-error{{'#pragma fenv_access' can only appear at file scope or at the start of a compound statement}}
16+
}

0 commit comments

Comments
 (0)