[clang] 2e204e2 - [clang] Enable support for #pragma STDC FENV_ACCESS
Melanie Blower via cfe-commits
cfe-commits at lists.llvm.org
Sun Oct 25 07:10:14 PDT 2020
Author: Melanie Blower
Date: 2020-10-25T06:46:25-07:00
New Revision: 2e204e23911b1f8bd1463535da40c6e48747a138
URL: https://github.com/llvm/llvm-project/commit/2e204e23911b1f8bd1463535da40c6e48747a138
DIFF: https://github.com/llvm/llvm-project/commit/2e204e23911b1f8bd1463535da40c6e48747a138.diff
LOG: [clang] Enable support for #pragma STDC FENV_ACCESS
Reviewers: rjmccall, rsmith, sepavloff
Differential Revision: https://reviews.llvm.org/D87528
Added:
clang/test/CodeGen/pragma-fenv_access.c
clang/test/Parser/pragma-fenv_access.c
Modified:
clang/docs/UsersManual.rst
clang/include/clang/AST/Decl.h
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/DiagnosticASTKinds.td
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Basic/LangOptions.h
clang/include/clang/Sema/ScopeInfo.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/ExprConstant.cpp
clang/lib/CodeGen/CGCall.cpp
clang/lib/CodeGen/CodeGenFunction.cpp
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/CodeGen/CodeGenModule.h
clang/lib/Parse/ParsePragma.cpp
clang/lib/Parse/ParseStmt.cpp
clang/lib/Sema/ScopeInfo.cpp
clang/lib/Sema/SemaAttr.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaStmt.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/CXX/expr/expr.const/p2-0x.cpp
clang/test/CodeGen/fp-floatcontrol-pragma.cpp
clang/test/Parser/fp-floatcontrol-syntax.cpp
clang/test/Preprocessor/pragma_unknown.c
Removed:
################################################################################
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 9726a25f7f63..5d18435aab6c 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -1386,7 +1386,7 @@ Note that floating-point operations performed as part of constant initialization
Details:
* ``precise`` Disables optimizations that are not value-safe on floating-point data, although FP contraction (FMA) is enabled (``-ffp-contract=fast``). This is the default behavior.
- * ``strict`` Enables ``-frounding-math`` and ``-ffp-exception-behavior=strict``, and disables contractions (FMA). All of the ``-ffast-math`` enablements are disabled.
+ * ``strict`` Enables ``-frounding-math`` and ``-ffp-exception-behavior=strict``, and disables contractions (FMA). All of the ``-ffast-math`` enablements are disabled. Enables ``STDC FENV_ACCESS``: by default ``FENV_ACCESS`` is disabled. This option setting behaves as though ``#pragma STDC FENV_ACESS ON`` appeared at the top of the source file.
* ``fast`` Behaves identically to specifying both ``-ffast-math`` and ``ffp-contract=fast``
Note: If your command line specifies multiple instances
@@ -1408,6 +1408,44 @@ Note that floating-point operations performed as part of constant initialization
* ``strict`` The compiler ensures that all transformations strictly preserve the floating point exception semantics of the original code.
+.. _fp-constant-eval:
+
+A note about Floating Point Constant Evaluation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In C, the only place floating point operations are guaranteed to be evaluated
+during translation is in the initializers of variables of static storage
+duration, which are all notionally initialized before the program begins
+executing (and thus before a non-default floating point environment can be
+entered). But C++ has many more contexts where floating point constant
+evaluation occurs. Specifically: for static/thread-local variables,
+first try evaluating the initializer in a constant context, including in the
+constant floating point environment (just like in C), and then, if that fails,
+fall back to emitting runtime code to perform the initialization (which might
+in general be in a
diff erent floating point environment).
+
+Consider this example when compiled with ``-frounding-math``
+
+ .. code-block:: console
+
+constexpr float func_01(float x, float y) {
+ return x + y;
+}
+float V1 = func_01(1.0F, 0x0.000001p0F);
+
+The C++ rule is that initializers for static storage duration variables are
+first evaluated during translation (therefore, in the default rounding mode),
+and only evaluated at runtime (and therefore in the runtime rounding mode) if
+the compile-time evaluation fails. This is in line with the C rules;
+C11 F.8.5 says: *All computation for automatic initialization is done (as if)
+at execution time; thus, it is affected by any operative modes and raises
+floating-point exceptions as required by IEC 60559 (provided the state for the
+FENV_ACCESS pragma is ββonββ). All computation for initialization of objects
+that have static or thread storage duration is done (as if) at translation
+time.* C++ generalizes this by adding another phase of initialization
+(at runtime) if the translation-time initialization fails, but the
+translation-time evaluation of the initializer of succeeds, it will be
+treated as a constant initializer.
.. _controlling-code-generation:
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 0a9474c3ee86..5d4f18806ff4 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2253,10 +2253,6 @@ class FunctionDecl : public DeclaratorDecl,
bool usesSEHTry() const { return FunctionDeclBits.UsesSEHTry; }
void setUsesSEHTry(bool UST) { FunctionDeclBits.UsesSEHTry = UST; }
- /// Indicates the function uses Floating Point constrained intrinsics
- bool usesFPIntrin() const { return FunctionDeclBits.UsesFPIntrin; }
- void setUsesFPIntrin(bool Val) { FunctionDeclBits.UsesFPIntrin = Val; }
-
/// Whether this function has been deleted.
///
/// A function that is "deleted" (via the C++0x "= delete" syntax)
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index f58870d76013..56079db4d9c5 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -2267,6 +2267,14 @@ def PragmaClangRelroSection : InheritableAttr {
let Documentation = [Undocumented];
}
+def StrictFP : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ // Function uses strict floating point operations.
+ let Spellings = [];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [Undocumented];
+}
+
def PragmaClangTextSection : InheritableAttr {
// This attribute has no spellings as it is only ever created implicitly.
let Spellings = [];
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index b6262518b81f..f6b936f5ccd9 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -74,6 +74,8 @@ def note_constexpr_float_arithmetic : Note<
"floating point arithmetic produces %select{an infinity|a NaN}0">;
def note_constexpr_dynamic_rounding : Note<
"cannot evaluate this expression if rounding mode is dynamic">;
+def note_constexpr_float_arithmetic_strict : Note<
+ "compile time floating point arithmetic suppressed in strict evaluation modes">;
def note_constexpr_pointer_subtraction_not_same_array : Note<
"subtracted pointers are not elements of the same array">;
def note_constexpr_pointer_subtraction_zero_size : Note<
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 78d3a08b3028..24ca8340ef6f 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1135,9 +1135,12 @@ def err_pragma_file_or_compound_scope : Error<
// - #pragma stdc unknown
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
InGroup<UnknownPragmas>;
-def warn_stdc_fenv_access_not_supported :
- Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">,
- InGroup<UnknownPragmas>;
+// 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>;
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 860b97aace54..dea9d217cf0c 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -413,13 +413,20 @@ class FPOptions {
setFPContractMode(LO.getDefaultFPContractMode());
setRoundingMode(LO.getFPRoundingMode());
setFPExceptionMode(LO.getFPExceptionMode());
- setAllowFEnvAccess(LangOptions::FPM_Off);
setAllowFPReassociate(LO.AllowFPReassoc);
setNoHonorNaNs(LO.NoHonorNaNs);
setNoHonorInfs(LO.NoHonorInfs);
setNoSignedZero(LO.NoSignedZero);
setAllowReciprocal(LO.AllowRecip);
setAllowApproxFunc(LO.ApproxFunc);
+ if (getFPContractMode() == LangOptions::FPM_On &&
+ getRoundingMode() == llvm::RoundingMode::Dynamic &&
+ getFPExceptionMode() == LangOptions::FPE_Strict)
+ // If the FP settings are set to the "strict" model, then
+ // FENV access is set to true. (ffp-model=strict)
+ setAllowFEnvAccess(true);
+ else
+ setAllowFEnvAccess(LangOptions::FPM_Off);
}
bool allowFPContractWithinStatement() const {
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index f0f9cb9e40ae..ff2a20923415 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -127,6 +127,9 @@ class FunctionScopeInfo {
/// Whether there is a fallthrough statement in this function.
bool HasFallthroughStmt : 1;
+ /// Whether this function uses constrained floating point intrinsics
+ bool UsesFPIntrin : 1;
+
/// Whether we make reference to a declaration that could be
/// unavailable.
bool HasPotentialAvailabilityViolations : 1;
@@ -369,7 +372,8 @@ class FunctionScopeInfo {
: Kind(SK_Function), HasBranchProtectedScope(false),
HasBranchIntoScope(false), HasIndirectGoto(false),
HasDroppedStmt(false), HasOMPDeclareReductionCombiner(false),
- HasFallthroughStmt(false), HasPotentialAvailabilityViolations(false),
+ HasFallthroughStmt(false), UsesFPIntrin(false),
+ HasPotentialAvailabilityViolations(false),
ObjCShouldCallSuper(false), ObjCIsDesignatedInit(false),
ObjCWarnForNoDesignatedInitChain(false), ObjCIsSecondaryInit(false),
ObjCWarnForNoInitDelegation(false), NeedsCoroutineSuspends(true),
@@ -431,6 +435,10 @@ class FunctionScopeInfo {
HasFallthroughStmt = true;
}
+ void setUsesFPIntrin() {
+ UsesFPIntrin = true;
+ }
+
void setHasCXXTry(SourceLocation TryLoc) {
setHasBranchProtectedScope();
FirstCXXTryLoc = TryLoc;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ed409b93545e..4b2311dce31d 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4478,6 +4478,7 @@ class Sema final {
bool HasLeadingEmptyMacro = false);
void ActOnStartOfCompoundStmt(bool IsStmtExpr);
+ void ActOnAfterCompoundStatementLeadingPragmas();
void ActOnFinishOfCompoundStmt();
StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
ArrayRef<Stmt *> Elts, bool isStmtExpr);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 7bd57a80f7f2..b8891055ab61 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2601,6 +2601,14 @@ static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E,
return false;
}
+ if ((St != APFloat::opOK) &&
+ (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
+ FPO.getFPExceptionMode() != LangOptions::FPE_Ignore ||
+ FPO.getAllowFEnvAccess())) {
+ Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
+ return false;
+ }
+
if ((St & APFloat::opStatus::opInvalidOp) &&
FPO.getFPExceptionMode() != LangOptions::FPE_Ignore) {
// There is no usefully definable result.
@@ -2644,11 +2652,17 @@ static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E,
}
static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
+ const FPOptions FPO,
QualType SrcType, const APSInt &Value,
QualType DestType, APFloat &Result) {
Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
- Result.convertFromAPInt(Value, Value.isSigned(),
- APFloat::rmNearestTiesToEven);
+ APFloat::opStatus St = Result.convertFromAPInt(Value, Value.isSigned(),
+ APFloat::rmNearestTiesToEven);
+ if (!Info.InConstantContext && St != llvm::APFloatBase::opOK &&
+ FPO.isFPConstrained()) {
+ Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
+ return false;
+ }
return true;
}
@@ -4370,9 +4384,11 @@ struct CompoundAssignSubobjectHandler {
Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS);
return true;
} else if (RHS.isFloat()) {
+ const FPOptions FPO = E->getFPFeaturesInEffect(
+ Info.Ctx.getLangOpts());
APFloat FValue(0.0);
- return HandleIntToFloatCast(Info, E, SubobjType, Value, PromotedLHSType,
- FValue) &&
+ return HandleIntToFloatCast(Info, E, FPO, SubobjType, Value,
+ PromotedLHSType, FValue) &&
handleFloatFloatBinOp(Info, E, FValue, Opcode, RHS.getFloat()) &&
HandleFloatToIntCast(Info, E, PromotedLHSType, FValue, SubobjType,
Value);
@@ -12545,8 +12561,16 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
return false;
assert(E->isComparisonOp() && "Invalid binary operator!");
+ llvm::APFloatBase::cmpResult CmpResult = LHS.compare(RHS);
+ if (!Info.InConstantContext &&
+ CmpResult == APFloat::cmpUnordered &&
+ E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).isFPConstrained()) {
+ // Note: Compares may raise invalid in some cases involving NaN or sNaN.
+ Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
+ return false;
+ }
auto GetCmpRes = [&]() {
- switch (LHS.compare(RHS)) {
+ switch (CmpResult) {
case APFloat::cmpEqual:
return CmpResult::Equal;
case APFloat::cmpLessThan:
@@ -13604,6 +13628,11 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_fabsf:
case Builtin::BI__builtin_fabsl:
case Builtin::BI__builtin_fabsf128:
+ // The C standard says "fabs raises no floating-point exceptions,
+ // even if x is a signaling NaN. The returned value is independent of
+ // the current rounding direction mode." Therefore constant folding can
+ // proceed without regard to the floating point settings.
+ // Reference, WG14 N2478 F.10.4.3
if (!EvaluateFloat(E->getArg(0), Result, Info))
return false;
@@ -13662,6 +13691,9 @@ bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
case UO_Plus:
return EvaluateFloat(E->getSubExpr(), Result, Info);
case UO_Minus:
+ // In C standard, WG14 N2478 F.3 p4
+ // "the unary - raises no floating point exceptions,
+ // even if the operand is signalling."
if (!EvaluateFloat(E->getSubExpr(), Result, Info))
return false;
Result.changeSign();
@@ -13695,9 +13727,11 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralToFloating: {
APSInt IntResult;
+ const FPOptions FPO = E->getFPFeaturesInEffect(
+ Info.Ctx.getLangOpts());
return EvaluateInteger(SubExpr, IntResult, Info) &&
- HandleIntToFloatCast(Info, E, SubExpr->getType(), IntResult,
- E->getType(), Result);
+ HandleIntToFloatCast(Info, E, FPO, SubExpr->getType(),
+ IntResult, E->getType(), Result);
}
case CK_FixedPointToFloating: {
@@ -13936,13 +13970,15 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
+ const FPOptions FPO = E->getFPFeaturesInEffect(
+ Info.Ctx.getLangOpts());
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
QualType From
= E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.makeComplexFloat();
- return HandleIntToFloatCast(Info, E, From, Result.IntReal,
+ return HandleIntToFloatCast(Info, E, FPO, From, Result.IntReal,
To, Result.FloatReal) &&
- HandleIntToFloatCast(Info, E, From, Result.IntImag,
+ HandleIntToFloatCast(Info, E, FPO, From, Result.IntImag,
To, Result.FloatImag);
}
}
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 93be1b874350..f148397e7fb9 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -4837,7 +4837,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
/*AttrOnCallSite=*/true);
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
- if (FD->usesFPIntrin())
+ if (FD->hasAttr<StrictFPAttr>())
// All calls within a strictfp function are marked strictfp
Attrs =
Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
@@ -4902,7 +4902,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
getBundlesForFunclet(CalleePtr);
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
- if (FD->usesFPIntrin())
+ if (FD->hasAttr<StrictFPAttr>())
// All calls within a strictfp function are marked strictfp
Attrs =
Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 2dcb5314c61e..2498e2ed687f 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -915,8 +915,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
}
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
- Builder.setIsFPConstrained(FD->usesFPIntrin());
- if (FD->usesFPIntrin())
+ Builder.setIsFPConstrained(FD->hasAttr<StrictFPAttr>());
+ if (FD->hasAttr<StrictFPAttr>())
Fn->addFnAttr(llvm::Attribute::StrictFP);
}
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 809e877e42aa..a1511e099e15 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1742,6 +1742,15 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
}
}
+void CodeGenModule::setLLVMFunctionFEnvAttributes(const FunctionDecl *D,
+ llvm::Function *F) {
+ if (D->hasAttr<StrictFPAttr>()) {
+ llvm::AttrBuilder FuncAttrs;
+ FuncAttrs.addAttribute("strictfp");
+ F->addAttributes(llvm::AttributeList::FunctionIndex, FuncAttrs);
+ }
+}
+
void CodeGenModule::SetCommonAttributes(GlobalDecl GD, llvm::GlobalValue *GV) {
const Decl *D = GD.getDecl();
if (dyn_cast_or_null<NamedDecl>(D))
@@ -4587,9 +4596,11 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
MaybeHandleStaticInExternC(D, Fn);
-
maybeSetTrivialComdat(*D, *Fn);
+ // Set CodeGen attributes that represent floating point environment.
+ setLLVMFunctionFEnvAttributes(D, Fn);
+
CodeGenFunction(*this).GenerateCode(GD, Fn, FI);
setNonAliasAttributes(GD, Fn);
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index fc732dbea521..b3babc8dc6e0 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1131,6 +1131,10 @@ class CodeGenModule : public CodeGenTypeCache {
/// definition.
void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F);
+ /// Set the LLVM function attributes that represent floating point
+ /// environment.
+ void setLLVMFunctionFEnvAttributes(const FunctionDecl *D, llvm::Function *F);
+
/// Return true iff the given type uses 'sret' when used as a return type.
bool ReturnTypeUsesSRet(const CGFunctionInfo &FI);
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 572fc7115b87..36bfeeebfef3 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -106,10 +106,6 @@ struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler {
tok::OnOffSwitch OOS;
if (PP.LexOnOffSwitch(OOS))
return;
- if (OOS == tok::OOS_ON) {
- PP.Diag(Tok, diag::warn_stdc_fenv_access_not_supported);
- return;
- }
MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1),
1);
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index ee35b24b3c81..a48db31ca42d 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -366,7 +366,8 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
case tok::annot_pragma_fenv_access:
ProhibitAttributes(Attrs);
- HandlePragmaFEnvAccess();
+ Diag(Tok, diag::err_pragma_stdc_fenv_access_scope);
+ ConsumeAnnotationToken();
return StmtEmpty();
case tok::annot_pragma_fenv_round:
@@ -1033,9 +1034,9 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
Tok.getLocation(),
"in compound statement ('{}')");
- // Record the state of the FPFeatures, restore on leaving the
+ // Record the current FPFeatures, restore on leaving the
// compound statement.
- Sema::FPFeaturesStateRAII SaveFPContractState(Actions);
+ Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
InMessageExpressionRAIIObject InMessage(*this, false);
BalancedDelimiterTracker T(*this, tok::l_brace);
@@ -1046,6 +1047,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
// Parse any pragmas at the beginning of the compound statement.
ParseCompoundStatementLeadingPragmas();
+ Actions.ActOnAfterCompoundStatementLeadingPragmas();
StmtVector Stmts;
diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp
index b2a26af9b4a5..4857346018ae 100644
--- a/clang/lib/Sema/ScopeInfo.cpp
+++ b/clang/lib/Sema/ScopeInfo.cpp
@@ -29,6 +29,7 @@ void FunctionScopeInfo::Clear() {
HasDroppedStmt = false;
HasOMPDeclareReductionCombiner = false;
HasFallthroughStmt = false;
+ UsesFPIntrin = false;
HasPotentialAvailabilityViolations = false;
ObjCShouldCallSuper = false;
ObjCIsDesignatedInit = false;
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 91ca2514158d..a7751707649a 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -1002,6 +1002,7 @@ void Sema::setExceptionMode(SourceLocation Loc,
void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
+ auto LO = getLangOpts();
if (IsEnabled) {
// Verify Microsoft restriction:
// You can't enable fenv_access unless precise semantics are enabled.
@@ -1010,10 +1011,15 @@ void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
if (!isPreciseFPEnabled())
Diag(Loc, diag::err_pragma_fenv_requires_precise);
NewFPFeatures.setAllowFEnvAccessOverride(true);
- } else
+ // Enabling FENV access sets the RoundingMode to Dynamic.
+ // and ExceptionBehavior to Strict
+ NewFPFeatures.setRoundingModeOverride(llvm::RoundingMode::Dynamic);
+ NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict);
+ } else {
NewFPFeatures.setAllowFEnvAccessOverride(false);
+ }
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
- CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
+ CurFPFeatures = NewFPFeatures.applyOverrides(LO);
}
void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 283d663c5d26..2bffd2a87d08 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14285,12 +14285,16 @@ static void diagnoseImplicitlyRetainedSelf(Sema &S) {
Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
bool IsInstantiation) {
+ FunctionScopeInfo *FSI = getCurFunction();
FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr;
+ if (FSI->UsesFPIntrin && !FD->hasAttr<StrictFPAttr>())
+ FD->addAttr(StrictFPAttr::CreateImplicit(Context));
+
sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
- if (getLangOpts().Coroutines && getCurFunction()->isCoroutine())
+ if (getLangOpts().Coroutines && FSI->isCoroutine())
CheckCompletedCoroutineBody(FD, Body);
// Do not call PopExpressionEvaluationContext() if it is a lambda because one
@@ -14367,7 +14371,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// to deduce an implicit return type.
if (FD->getReturnType()->isRecordType() &&
(!getLangOpts().CPlusPlus || !FD->isDependentContext()))
- computeNRVO(Body, getCurFunction());
+ computeNRVO(Body, FSI);
}
// GNU warning -Wmissing-prototypes:
@@ -14491,14 +14495,14 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
MD->getReturnType(), MD);
if (Body)
- computeNRVO(Body, getCurFunction());
+ computeNRVO(Body, FSI);
}
- if (getCurFunction()->ObjCShouldCallSuper) {
+ if (FSI->ObjCShouldCallSuper) {
Diag(MD->getEndLoc(), diag::warn_objc_missing_super_call)
<< MD->getSelector().getAsString();
- getCurFunction()->ObjCShouldCallSuper = false;
+ FSI->ObjCShouldCallSuper = false;
}
- if (getCurFunction()->ObjCWarnForNoDesignatedInitChain) {
+ if (FSI->ObjCWarnForNoDesignatedInitChain) {
const ObjCMethodDecl *InitMethod = nullptr;
bool isDesignated =
MD->isDesignatedInitializerForTheInterface(&InitMethod);
@@ -14523,14 +14527,14 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
Diag(InitMethod->getLocation(),
diag::note_objc_designated_init_marked_here);
}
- getCurFunction()->ObjCWarnForNoDesignatedInitChain = false;
+ FSI->ObjCWarnForNoDesignatedInitChain = false;
}
- if (getCurFunction()->ObjCWarnForNoInitDelegation) {
+ if (FSI->ObjCWarnForNoInitDelegation) {
// Don't issue this warning for unavaialable inits.
if (!MD->isUnavailable())
Diag(MD->getLocation(),
diag::warn_objc_secondary_init_missing_init_call);
- getCurFunction()->ObjCWarnForNoInitDelegation = false;
+ FSI->ObjCWarnForNoInitDelegation = false;
}
diagnoseImplicitlyRetainedSelf(*this);
@@ -14541,10 +14545,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
return nullptr;
}
- if (Body && getCurFunction()->HasPotentialAvailabilityViolations)
+ if (Body && FSI->HasPotentialAvailabilityViolations)
DiagnoseUnguardedAvailabilityViolations(dcl);
- assert(!getCurFunction()->ObjCShouldCallSuper &&
+ assert(!FSI->ObjCShouldCallSuper &&
"This should only be set for ObjC methods, which should have been "
"handled in the block above.");
@@ -14557,7 +14561,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
// Verify that gotos and switch cases don't jump into scopes illegally.
- if (getCurFunction()->NeedsScopeChecking() &&
+ if (FSI->NeedsScopeChecking() &&
!PP.isCodeCompletionEnabled())
DiagnoseInvalidJumps(Body);
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index e994ab216fe6..e6314fd65f8c 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -385,6 +385,14 @@ void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) {
PushCompoundScope(IsStmtExpr);
}
+void Sema::ActOnAfterCompoundStatementLeadingPragmas() {
+ if (getCurFPFeatures().isFPConstrained()) {
+ FunctionScopeInfo *FSI = getCurFunction();
+ assert(FSI);
+ FSI->setUsesFPIntrin();
+ }
+}
+
void Sema::ActOnFinishOfCompoundStmt() {
PopCompoundScope();
}
@@ -397,11 +405,6 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
ArrayRef<Stmt *> Elts, bool isStmtExpr) {
const unsigned NumElts = Elts.size();
- // Mark the current function as usng floating point constrained intrinsics
- if (getCurFPFeatures().isFPConstrained())
- if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext))
- F->setUsesFPIntrin(true);
-
// If we're in C89 mode, check that we don't have any decls after stmts. If
// so, emit an extension diagnostic.
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 51f74d0b1d99..0be868d2a0f4 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1951,7 +1951,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
D->hasWrittenPrototype(), D->getConstexprKind(),
TrailingRequiresClause);
Function->setRangeEnd(D->getSourceRange().getEnd());
- Function->setUsesFPIntrin(D->usesFPIntrin());
}
if (D->isInlined())
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index fd3b981150a0..797232885687 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -888,7 +888,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->ODRHash = Record.readInt();
FD->setHasODRHash(true);
- FD->setUsesFPIntrin(Record.readInt());
if (FD->isDefaulted()) {
if (unsigned NumLookups = Record.readInt()) {
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index df7304457419..47ed44898f49 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -566,7 +566,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.AddSourceLocation(D->getEndLoc());
Record.push_back(D->getODRHash());
- Record.push_back(D->usesFPIntrin());
if (D->isDefaulted()) {
if (auto *FDI = D->getDefaultedFunctionInfo()) {
diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp
index e7b6929199ff..82c92b77bd17 100644
--- a/clang/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp
@@ -280,6 +280,16 @@ namespace UndefinedBehavior {
constexpr float f10 = f2 - f2; // expected-error {{constant expression}} expected-note {{produces a NaN}}
constexpr float f11 = f2 + f4; // expected-error {{constant expression}} expected-note {{produces a NaN}}
constexpr float f12 = f2 / f2; // expected-error {{constant expression}} expected-note {{produces a NaN}}
+#pragma float_control(push)
+#pragma float_control(except, on)
+constexpr float pi = 3.14f;
+constexpr unsigned ubig = 0xFFFFFFFF;
+constexpr float ce = 1.0 / 3.0; // not-expected-error {{constant expression}} not-expected-note {{floating point arithmetic suppressed in strict evaluation modes}}
+constexpr int ci = (int) pi;
+constexpr float fbig = (float) ubig; // not-expected-error {{constant expression}} not-expected-note {{floating point arithmetic suppressed in strict evaluation modes}}
+constexpr float fabspi = __builtin_fabs(pi); // no error expected
+constexpr float negpi = -pi; // expect no error on unary operator
+#pragma float_control(pop)
static_assert(!isinf(f1), "");
static_assert(isinf(f2), "");
static_assert(!isinf(f3), "");
diff --git a/clang/test/CodeGen/fp-floatcontrol-pragma.cpp b/clang/test/CodeGen/fp-floatcontrol-pragma.cpp
index 548809521f7f..45eb14bccc06 100644
--- a/clang/test/CodeGen/fp-floatcontrol-pragma.cpp
+++ b/clang/test/CodeGen/fp-floatcontrol-pragma.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -DEXCEPT=1 -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NS %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -verify -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-FENV %s
// RUN: %clang_cc1 -triple %itanium_abi_triple -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-O3 %s
// Verify float_control(precise, off) enables fast math flags on fp operations.
@@ -138,7 +138,6 @@ float test_OperatorCall() {
// CHECK-LABEL define float {{.*}}test_OperatorCall{{.*}}
#if FENV_ON
-// expected-warning at +1{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}}
#pragma STDC FENV_ACCESS ON
#endif
// CHECK-LABEL: define {{.*}}callt{{.*}}
@@ -146,7 +145,21 @@ float test_OperatorCall() {
void callt() {
volatile float z;
z = z * z;
-//CHECK: = fmul float
+ //CHECK-FENV: llvm.experimental.constrained.fmul{{.*}}
+}
+
+// CHECK-LABEL: define {{.*}}myAdd{{.*}}
+float myAdd(int i, float f) {
+ if (i<0)
+ return 1.0 + 2.0;
+ // Check that floating point constant folding doesn't occur if
+ // #pragma STC FENV_ACCESS is enabled.
+ //CHECK-FENV: llvm.experimental.constrained.fadd{{.*}}double 1.0{{.*}}double 2.0{{.*}}
+ //CHECK: store float 3.0{{.*}}retval{{.*}}
+ static double v = 1.0 / 3.0;
+ //CHECK-FENV: llvm.experimental.constrained.fptrunc.f32.f64{{.*}}
+ //CHECK-NOT: fdiv
+ return v;
}
#if EXCEPT
@@ -201,3 +214,18 @@ float xx(double x, float z) {
return fc_template_namespace::exc_on<float>(x, z);
}
#endif // EXCEPT
+
+float try_lam(float x, unsigned n) {
+// CHECK: define {{.*}}try_lam{{.*}}class.anon{{.*}}
+ float result;
+ auto t =
+ // Lambda expression begins
+ [](float a, float b) {
+#pragma float_control( except, on)
+ return a * b;
+//CHECK: llvm.experimental.constrained.fmul{{.*}}fpexcept.strict
+ } // end of lambda expression
+ (1.0f,2.0f);
+ result = x + t;
+ return result;
+}
diff --git a/clang/test/CodeGen/pragma-fenv_access.c b/clang/test/CodeGen/pragma-fenv_access.c
new file mode 100644
index 000000000000..87d12a3a7ab1
--- /dev/null
+++ b/clang/test/CodeGen/pragma-fenv_access.c
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
+
+#pragma STDC FENV_ACCESS ON
+
+float func_01(float x, float y) {
+ return x + y;
+}
+// CHECK-LABEL: @func_01
+// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+
+
+float func_02(float x, float y) {
+ #pragma float_control(except, off)
+ #pragma STDC FENV_ACCESS OFF
+ return x + y;
+}
+// CHECK-LABEL: @func_02
+// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+
+
+float func_03(float x, float y) {
+ return x + y;
+}
+// CHECK-LABEL: @func_03
+// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+
+
+#pragma STDC FENV_ACCESS OFF
+
+float func_04(float x, float y) {
+ #pragma float_control(except, off)
+ return x + y;
+}
+// CHECK-LABEL: @func_04
+// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+
+
+float func_05(float x, float y) {
+ #pragma STDC FENV_ACCESS ON
+ return x + y;
+}
+// CHECK-LABEL: @func_05
+// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+
+
+float func_06(float x, float y) {
+ #pragma float_control(except, off)
+ return x + y;
+}
+// CHECK-LABEL: @func_06
+// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+
+
+float func_07(float x, float y) {
+ x -= y;
+ if (x) {
+ #pragma STDC FENV_ACCESS ON
+ y *= 2;
+ }
+ return y + 4;
+}
+// CHECK-LABEL: @func_07
+// CHECK: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// CHECK: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
diff --git a/clang/test/Parser/fp-floatcontrol-syntax.cpp b/clang/test/Parser/fp-floatcontrol-syntax.cpp
index 0593c2a0385e..5e7e8b1b03bc 100644
--- a/clang/test/Parser/fp-floatcontrol-syntax.cpp
+++ b/clang/test/Parser/fp-floatcontrol-syntax.cpp
@@ -26,19 +26,13 @@ void check_stack() {
double a = 0.0;
double b = 1.0;
-//FIXME At some point this warning will be removed, until then
-// document the warning
-#ifdef FAST
-// expected-warning at +1{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}}
-#pragma STDC FENV_ACCESS ON
-#else
-#pragma STDC FENV_ACCESS ON // expected-warning{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}}
-#endif
#ifdef STRICT
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
#else
-// Currently FENV_ACCESS cannot be enabled by pragma, skip error check
-#pragma float_control(precise, off) // not-expected-error {{'#pragma float_control(precise, off)' is illegal when fenv_access is enabled}}
+#ifndef FAST
+#pragma STDC FENV_ACCESS ON
+#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
+#endif
#endif
#pragma float_control(precise, on)
diff --git a/clang/test/Parser/pragma-fenv_access.c b/clang/test/Parser/pragma-fenv_access.c
new file mode 100644
index 000000000000..c789f3313132
--- /dev/null
+++ b/clang/test/Parser/pragma-fenv_access.c
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -ffp-exception-behavior=strict -DSTRICT -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c++ -DCPP -DSTRICT -ffp-exception-behavior=strict -fsyntax-only -verify %s
+#ifdef CPP
+#define CONST constexpr
+#else
+#define CONST const
+#endif
+
+#pragma STDC FENV_ACCESS IN_BETWEEN // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}}
+
+#pragma STDC FENV_ACCESS OFF
+
+float func_04(int x, float y) {
+ if (x)
+ return y + 2;
+ #pragma STDC FENV_ACCESS ON // expected-error{{'#pragma STDC FENV_ACCESS' can only appear at file scope or at the start of a compound statement}}
+ return x + y;
+}
+
+#pragma STDC FENV_ACCESS ON
+int main() {
+ CONST float one = 1.0F ;
+ CONST float three = 3.0F ;
+ CONST float four = 4.0F ;
+ CONST float frac_ok = one/four;
+#if !defined(CPP)
+//expected-note at +2 {{declared here}}
+#endif
+ CONST float frac = one/three;
+ CONST double d = one;
+ CONST int not_too_big = 255;
+ CONST float fnot_too_big = not_too_big;
+ CONST int too_big = 0x7ffffff0;
+#if defined(CPP)
+//expected-warning at +2{{implicit conversion}}
+#endif
+ CONST float fbig = too_big; // inexact
+#if !defined(CPP)
+#define static_assert _Static_assert
+#endif
+enum {
+ e1 = (int)one, e3 = (int)three, e4 = (int)four, e_four_quarters = (int)(frac_ok * 4)
+};
+static_assert(e1 == 1 && e3 == 3 && e4 == 4 && e_four_quarters == 1, "");
+enum {
+#if !defined(CPP)
+// expected-error at +2 {{not an integer constant expression}} expected-note at +2 {{is not a constant expression}}
+#endif
+ e_three_thirds = (int)(frac * 3)
+};
+ if (one <= four) return 0;
+ return -1;
+}
diff --git a/clang/test/Preprocessor/pragma_unknown.c b/clang/test/Preprocessor/pragma_unknown.c
index 81fe88cd3855..a7c4829c279d 100644
--- a/clang/test/Preprocessor/pragma_unknown.c
+++ b/clang/test/Preprocessor/pragma_unknown.c
@@ -16,15 +16,6 @@
// CHECK: {{^}}#pragma STDC FP_CONTRACT DEFAULT{{$}}
// CHECK: {{^}}#pragma STDC FP_CONTRACT IN_BETWEEN{{$}}
-#pragma STDC FENV_ACCESS ON // expected-warning {{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}}
-#pragma STDC FENV_ACCESS OFF
-#pragma STDC FENV_ACCESS DEFAULT
-#pragma STDC FENV_ACCESS IN_BETWEEN // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}}
-// CHECK: {{^}}#pragma STDC FENV_ACCESS ON{{$}}
-// CHECK: {{^}}#pragma STDC FENV_ACCESS OFF{{$}}
-// CHECK: {{^}}#pragma STDC FENV_ACCESS DEFAULT{{$}}
-// CHECK: {{^}}#pragma STDC FENV_ACCESS IN_BETWEEN{{$}}
-
#pragma STDC CX_LIMITED_RANGE ON
#pragma STDC CX_LIMITED_RANGE OFF
#pragma STDC CX_LIMITED_RANGE DEFAULT
More information about the cfe-commits
mailing list