mibintc updated this revision to Diff 294074.
mibintc added a comment.

Responded to @rsmith's review


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87528/new/

https://reviews.llvm.org/D87528

Files:
  clang/include/clang/Basic/DiagnosticASTKinds.td
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ExprConstant.cpp
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/CodeGen/CodeGenModule.h
  clang/lib/Parse/ParsePragma.cpp
  clang/lib/Parse/ParseStmt.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/CXX/expr/expr.const/p2-0x.cpp
  clang/test/CodeGen/fp-floatcontrol-pragma.cpp
  clang/test/CodeGen/pragma-fenv_access.c
  clang/test/Parser/fp-floatcontrol-syntax.cpp
  clang/test/Parser/pragma-fenv_access.c
  clang/test/Preprocessor/pragma_unknown.c

Index: clang/test/Preprocessor/pragma_unknown.c
===================================================================
--- clang/test/Preprocessor/pragma_unknown.c
+++ 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 
Index: clang/test/Parser/pragma-fenv_access.c
===================================================================
--- /dev/null
+++ clang/test/Parser/pragma-fenv_access.c
@@ -0,0 +1,45 @@
+// 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;
+}
+
+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) & defined(STRICT)
+//expected-error@+3 {{constexpr variable 'frac' must be initialized by a constant expression}}
+//expected-note@+2 {{compile time floating point arithmetic suppressed in strict evaluation modes}}
+#endif
+  CONST float frac = one/three; // rounding
+  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) & defined(STRICT)
+//expected-error@+6 {{constexpr variable 'fbig' must be initialized by a constant expression}}
+//expected-note@+5 {{compile time floating point arithmetic suppressed in strict evaluation modes}}
+#endif
+#if defined(CPP)
+//expected-warning@+2{{implicit conversion}}
+#endif
+  CONST float fbig = too_big; // inexact
+  if (one <= four)  return 0;
+  return -1;
+}
Index: clang/test/Parser/fp-floatcontrol-syntax.cpp
===================================================================
--- clang/test/Parser/fp-floatcontrol-syntax.cpp
+++ clang/test/Parser/fp-floatcontrol-syntax.cpp
@@ -26,19 +26,14 @@
 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@+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
+#ifndef FAST
 // 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}}
+#pragma STDC FENV_ACCESS ON
+#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when fenv_access is enabled}}
+#endif
 #endif
 
 #pragma float_control(precise, on)
Index: clang/test/CodeGen/pragma-fenv_access.c
===================================================================
--- /dev/null
+++ 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.tonearest", 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: fadd float {{.*}}
+
+
+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.tonearest", 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: fadd float {{.*}}
+
+
+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.tonearest", metadata !"fpexcept.strict")
+
+
+float func_06(float x, float y) {
+  #pragma float_control(except, off)
+  return x + y;
+}
+// CHECK-LABEL: @func_06
+// CHECK: fadd float {{.*}}
+
+
+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.tonearest", metadata !"fpexcept.strict")
+// CHECK: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
Index: clang/test/CodeGen/fp-floatcontrol-pragma.cpp
===================================================================
--- clang/test/CodeGen/fp-floatcontrol-pragma.cpp
+++ 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 @@
 // CHECK-LABEL define float  {{.*}}test_OperatorCall{{.*}}
 
 #if FENV_ON
-// expected-warning@+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 @@
 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.fdiv{{.*}}double 1.0{{.*}}double 3.0{{.*}}
+  //CHECK-NOT: fdiv
+  return v;
 }
 
 #if EXCEPT
Index: clang/test/CXX/expr/expr.const/p2-0x.cpp
===================================================================
--- clang/test/CXX/expr/expr.const/p2-0x.cpp
+++ clang/test/CXX/expr/expr.const/p2-0x.cpp
@@ -280,6 +280,16 @@
     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; // expected-error {{constant expression}} expected-note {{floating point arithmetic suppressed in strict evaluation modes}}
+constexpr int ci = (int) pi;
+constexpr float fbig = (float) ubig; // expected-error {{constant expression}} expected-note {{floating point arithmetic suppressed in strict evaluation modes}}
+constexpr float fabspi = __builtin_fabs(pi); // expected-error {{constant expression}} expected-note {{floating point arithmetic suppressed in strict evaluation modes}}
+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), "");
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -389,6 +389,13 @@
   PopCompoundScope();
 }
 
+void Sema::ActOnAfterCompoundStatementLeadingPragmas() {
+  if (getCurFPFeatures().getAllowFEnvAccess()) {
+    FunctionDecl *F = getCurFunctionDecl();
+    F->setUsesFPIntrin(true);
+  }
+}
+
 sema::CompoundScopeInfo &Sema::getCurCompoundScope() const {
   return getCurFunction()->CompoundScopes.back();
 }
Index: clang/lib/Parse/ParseStmt.cpp
===================================================================
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -366,7 +366,8 @@
 
   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 @@
                                 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 @@
 
   // Parse any pragmas at the beginning of the compound statement.
   ParseCompoundStatementLeadingPragmas();
+  Actions.ActOnAfterCompoundStatementLeadingPragmas();
 
   StmtVector Stmts;
 
Index: clang/lib/Parse/ParsePragma.cpp
===================================================================
--- clang/lib/Parse/ParsePragma.cpp
+++ clang/lib/Parse/ParsePragma.cpp
@@ -106,10 +106,6 @@
     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);
Index: clang/lib/CodeGen/CodeGenModule.h
===================================================================
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -1137,6 +1137,10 @@
   /// 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);
 
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -1725,6 +1725,15 @@
   }
 }
 
+void CodeGenModule::setLLVMFunctionFEnvAttributes(const FunctionDecl *D,
+                                                  llvm::Function *F) {
+  if (D->usesFPIntrin()) {
+    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))
@@ -4554,9 +4563,11 @@
 
   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);
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -2435,11 +2435,17 @@
 }
 
 static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
+                                 const FPOptions fpOptions,
                                  QualType SrcType, const APSInt &Value,
                                  QualType DestType, APFloat &Result) {
   Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
-  Result.convertFromAPInt(Value, Value.isSigned(),
-                          APFloat::rmNearestTiesToEven);
+  if (llvm::APFloatBase::opOK != Result.convertFromAPInt(Value,
+                                   Value.isSigned(),
+                                   APFloat::rmNearestTiesToEven) &&
+      fpOptions.isFPConstrained()) {
+    Info.CCEDiag(E, diag::note_constexpr_float_arithmetic_strict);
+    return false;
+  }
   return true;
 }
 
@@ -2640,31 +2646,38 @@
 }
 
 /// Perform the given binary floating-point operation, in-place, on LHS.
-static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E,
+static bool handleFloatFloatBinOp(EvalInfo &Info, const BinaryOperator *E,
                                   APFloat &LHS, BinaryOperatorKind Opcode,
                                   const APFloat &RHS) {
+  assert(E != nullptr);
+  llvm::APFloatBase::opStatus status;
   switch (Opcode) {
   default:
     Info.FFDiag(E);
     return false;
   case BO_Mul:
-    LHS.multiply(RHS, APFloat::rmNearestTiesToEven);
+    status = LHS.multiply(RHS, APFloat::rmNearestTiesToEven);
     break;
   case BO_Add:
-    LHS.add(RHS, APFloat::rmNearestTiesToEven);
+    status = LHS.add(RHS, APFloat::rmNearestTiesToEven);
     break;
   case BO_Sub:
-    LHS.subtract(RHS, APFloat::rmNearestTiesToEven);
+    status = LHS.subtract(RHS, APFloat::rmNearestTiesToEven);
     break;
   case BO_Div:
     // [expr.mul]p4:
     //   If the second operand of / or % is zero the behavior is undefined.
     if (RHS.isZero())
       Info.CCEDiag(E, diag::note_expr_divide_by_zero);
-    LHS.divide(RHS, APFloat::rmNearestTiesToEven);
+    status = LHS.divide(RHS, APFloat::rmNearestTiesToEven);
     break;
   }
 
+  if (E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).isFPConstrained() &&
+      llvm::APFloatBase::opOK != status) {
+    Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
+    return false;
+  }
   // [expr.pre]p4:
   //   If during the evaluation of an expression, the result is not
   //   mathematically defined [...], the behavior is undefined.
@@ -2811,8 +2824,8 @@
              "Mismatched LHS/RHS/Result Type");
       APFloat LHSFloat = LHSElt.getFloat();
 
-      if (!handleFloatFloatBinOp(Info, E, LHSFloat, Opcode,
-                                 RHSElt.getFloat())) {
+      if (!handleFloatFloatBinOp(Info, dyn_cast<BinaryOperator>(E), LHSFloat,
+                                 Opcode, RHSElt.getFloat())) {
         Info.FFDiag(E);
         return false;
       }
@@ -4142,10 +4155,13 @@
       Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS);
       return true;
     } else if (RHS.isFloat()) {
+      const BinaryOperator *BE = dyn_cast<BinaryOperator>(E);
+      const FPOptions fpOptions = BE->getFPFeaturesInEffect(
+                                    Info.Ctx.getLangOpts());
       APFloat FValue(0.0);
-      return HandleIntToFloatCast(Info, E, SubobjType, Value, PromotedLHSType,
-                                  FValue) &&
-             handleFloatFloatBinOp(Info, E, FValue, Opcode, RHS.getFloat()) &&
+      return HandleIntToFloatCast(Info, E, fpOptions, SubobjType, Value,
+                                  PromotedLHSType, FValue) &&
+             handleFloatFloatBinOp(Info, BE, FValue, Opcode, RHS.getFloat()) &&
              HandleFloatToIntCast(Info, E, PromotedLHSType, FValue, SubobjType,
                                   Value);
     }
@@ -4157,7 +4173,8 @@
     return checkConst(SubobjType) &&
            HandleFloatToFloatCast(Info, E, SubobjType, PromotedLHSType,
                                   Value) &&
-           handleFloatFloatBinOp(Info, E, Value, Opcode, RHS.getFloat()) &&
+           handleFloatFloatBinOp(Info, dyn_cast<BinaryOperator>(E), Value,
+                                 Opcode, RHS.getFloat()) &&
            HandleFloatToFloatCast(Info, E, PromotedLHSType, SubobjType, Value);
   }
   bool foundPointer(APValue &Subobj, QualType SubobjType) {
@@ -12220,6 +12237,10 @@
 
   if (LHSTy->isRealFloatingType() &&
       RHSTy->isRealFloatingType()) {
+    // Note: Compares may raise invalid in some cases involving NaN or sNaN.
+    // but this doesn't affect constant folding since NaN are
+    // not constant expressions.
+
     APFloat RHS(0.0), LHS(0.0);
 
     bool LHSOK = EvaluateFloat(E->getRHS(), RHS, Info);
@@ -13266,6 +13287,10 @@
   case Builtin::BI__builtin_fabsf:
   case Builtin::BI__builtin_fabsl:
   case Builtin::BI__builtin_fabsf128:
+    // The c lang ref says that "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.
     if (!EvaluateFloat(E->getArg(0), Result, Info))
       return false;
 
@@ -13319,6 +13344,8 @@
 }
 
 bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
+  // In C lang ref, the unary - raises no floating point exceptions,
+  // even if the operand is signalling.
   switch (E->getOpcode()) {
   default: return Error(E);
   case UO_Plus:
@@ -13348,6 +13375,14 @@
   return true;
 }
 
+static bool isWideningFPConversion(const QualType DestType,
+                                   const QualType SourceType) {
+  const BuiltinType *ST = dyn_cast<BuiltinType>(SourceType);
+  const BuiltinType *DT = dyn_cast<BuiltinType>(DestType);
+  return ST && DT && DT->isRealFloatingType() && ST->isRealFloatingType() &&
+         ST->getKind() <= DT->getKind();
+}
+
 bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
   const Expr* SubExpr = E->getSubExpr();
 
@@ -13357,14 +13392,24 @@
 
   case CK_IntegralToFloating: {
     APSInt IntResult;
+    const FPOptions fpOptions = E->getFPFeaturesInEffect(
+                                  Info.Ctx.getLangOpts());
     return EvaluateInteger(SubExpr, IntResult, Info) &&
-           HandleIntToFloatCast(Info, E, SubExpr->getType(), IntResult,
-                                E->getType(), Result);
+           HandleIntToFloatCast(Info, E, fpOptions, SubExpr->getType(),
+                                IntResult, E->getType(), Result);
   }
 
   case CK_FloatingCast: {
     if (!Visit(SubExpr))
       return false;
+    if (E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).isFPConstrained() &&
+        !isWideningFPConversion(E->getType(), SubExpr->getType())) {
+      // In C lang ref, footnote, cast may raise inexact exception.
+      // Cast may also raise invalid.
+      // Widening conversions do not raise FP exceptions.
+      Info.CCEDiag(E, diag::note_constexpr_float_arithmetic_strict);
+      return false;
+    }
     return HandleFloatToFloatCast(Info, E, SubExpr->getType(), E->getType(),
                                   Result);
   }
@@ -13587,13 +13632,15 @@
     if (!Visit(E->getSubExpr()))
       return false;
 
+    const FPOptions fpOptions = 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, fpOptions, From, Result.IntReal,
                                 To, Result.FloatReal) &&
-           HandleIntToFloatCast(Info, E, From, Result.IntImag,
+           HandleIntToFloatCast(Info, E, fpOptions, From, Result.IntImag,
                                 To, Result.FloatImag);
   }
   }
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -4344,6 +4344,7 @@
   void ActOnFinishOfCompoundStmt();
   StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
                                ArrayRef<Stmt *> Elts, bool isStmtExpr);
+  void ActOnAfterCompoundStatementLeadingPragmas();
 
   /// A RAII object to enter scope of a compound statement.
   class CompoundScopeRAII {
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1133,9 +1133,9 @@
 // - #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>;
+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>;
Index: clang/include/clang/Basic/DiagnosticASTKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticASTKinds.td
+++ clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -72,6 +72,8 @@
   "in a constant expression">;
 def note_constexpr_float_arithmetic : Note<
   "floating point arithmetic produces %select{an infinity|a NaN}0">;
+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<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to