diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -2322,8 +2322,9 @@
       return getStoredFPFeatures().applyOverrides(LO);
     return FPOptions::defaultWithoutTrailingStorage(LO);
   }
-  FPOptionsOverride getFPOptionsOverride() const {
-    if (UnaryOperatorBits.HasFPFeatures)
+
+  FPOptionsOverride getFPFeatures() const {
+    if (hasStoredFPFeatures())
       return getStoredFPFeatures();
     return FPOptionsOverride();
   }
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1458,6 +1458,12 @@
     return *getTrailingObjects<FPOptionsOverride>();
   }
 
+  FPOptionsOverride getFPFeatures() const {
+    if (hasStoredFPFeatures())
+      return getStoredFPFeatures();
+    return FPOptionsOverride();
+  }
+
   /// Get FPOptions inside this statement. They may differ from outer options
   /// due to pragmas.
   /// \param CurFPOptions FPOptions outside this statement.
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1570,6 +1570,7 @@
     FPFeaturesStateRAII(Sema &S);
     ~FPFeaturesStateRAII();
     FPOptionsOverride getOverrides() { return OldOverrides; }
+    FPOptions getFPFeatures() { return OldFPFeaturesState; }
 
   private:
     Sema& S;
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -7177,10 +7177,10 @@
   if (Err)
     return std::move(Err);
 
-  return UnaryOperator::Create(
-      Importer.getToContext(), ToSubExpr, E->getOpcode(), ToType,
-      E->getValueKind(), E->getObjectKind(), ToOperatorLoc, E->canOverflow(),
-      E->getFPOptionsOverride());
+  return UnaryOperator::Create(Importer.getToContext(), ToSubExpr,
+                               E->getOpcode(), ToType, E->getValueKind(),
+                               E->getObjectKind(), ToOperatorLoc,
+                               E->canOverflow(), E->getFPFeatures());
 }
 
 ExpectedStmt
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5049,7 +5049,8 @@
     Sema::ContextRAII savedContext(*this, Function);
 
     FPFeaturesStateRAII SavedFPFeatures(*this);
-    CurFPFeatures = FPOptions(getLangOpts());
+    if (TSK != TSK_ExplicitInstantiationDefinition)
+      CurFPFeatures = FPOptions(getLangOpts());
 
     if (addInstantiatedParametersToScope(Function, PatternDecl, Scope,
                                          TemplateArgs))
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3814,6 +3814,18 @@
   QualType TransformDependentNameType(TypeLocBuilder &TLB,
                                       DependentNameTypeLoc TL,
                                       bool DeducibleTSTContext);
+
+  /// Sets FP options in Sema for use in instantiation of the given expression.
+  ///
+  /// \tparam TExpr Subclass of \c Expr, which must be able to keep \c FPOption.
+  template <typename TExpr> void setFPOptions(const TExpr *E) {
+    const LangOptions &LO = getSema().getLangOpts();
+    FPOptions &CurFPO = getSema().CurFPFeatures;
+    CurFPO = E->getFPFeatures().applyOverrides(CurFPO);
+    getSema().FpPragmaStack.CurrentValue = CurFPO.getChangesFrom(FPOptions(LO));
+    if (CurFPO.isFPConstrained())
+      getSema().getCurFunction()->setUsesFPIntrin();
+  }
 };
 
 template <typename Derived>
@@ -3910,9 +3922,6 @@
   while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
     Init = Binder->getSubExpr();
 
-  if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init))
-    Init = ICE->getSubExprAsWritten();
-
   if (CXXStdInitializerListExpr *ILE =
           dyn_cast<CXXStdInitializerListExpr>(Init))
     return TransformInitializer(ILE->getSubExpr(), NotCopyInit);
@@ -7300,6 +7309,10 @@
   bool SubStmtInvalid = false;
   bool SubStmtChanged = false;
   SmallVector<Stmt*, 8> Statements;
+
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
+  setFPOptions(S);
+
   for (auto *B : S->body()) {
     StmtResult Result = getDerived().TransformStmt(
         B, IsStmtExpr && B == ExprResult ? SDK_StmtExprResult : SDK_Discarded);
@@ -7322,8 +7335,8 @@
   if (SubStmtInvalid)
     return StmtError();
 
-  if (!getDerived().AlwaysRebuild() &&
-      !SubStmtChanged)
+  if (!getDerived().AlwaysRebuild() && !SubStmtChanged &&
+      FPFeaturesState.getFPFeatures() == getSema().CurFPFeatures)
     return S;
 
   return getDerived().RebuildCompoundStmt(S->getLBracLoc(),
@@ -10693,7 +10706,11 @@
   if (SubExpr.isInvalid())
     return ExprError();
 
-  if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr())
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
+  setFPOptions(E);
+
+  if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr() &&
+      FPFeaturesState.getFPFeatures() == getSema().CurFPFeatures)
     return E;
 
   return getDerived().RebuildUnaryOperator(E->getOperatorLoc(),
@@ -11054,23 +11071,17 @@
                                   &ArgChanged))
     return ExprError();
 
-  if (!getDerived().AlwaysRebuild() &&
-      Callee.get() == E->getCallee() &&
-      !ArgChanged)
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
+  setFPOptions(E);
+
+  if (!getDerived().AlwaysRebuild() && Callee.get() == E->getCallee() &&
+      !ArgChanged && FPFeaturesState.getFPFeatures() == getSema().CurFPFeatures)
     return SemaRef.MaybeBindToTemporary(E);
 
   // FIXME: Wrong source location information for the '('.
   SourceLocation FakeLParenLoc
     = ((Expr *)Callee.get())->getSourceRange().getBegin();
 
-  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
-  if (E->hasStoredFPFeatures()) {
-    FPOptionsOverride NewOverrides = E->getFPFeatures();
-    getSema().CurFPFeatures =
-        NewOverrides.applyOverrides(getSema().getLangOpts());
-    getSema().FpPragmaStack.CurrentValue = NewOverrides;
-  }
-
   return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc,
                                       Args,
                                       E->getRParenLoc());
@@ -11176,20 +11187,20 @@
   if (RHS.isInvalid())
     return ExprError();
 
-  if (!getDerived().AlwaysRebuild() &&
-      LHS.get() == E->getLHS() &&
-      RHS.get() == E->getRHS())
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
+  setFPOptions(E);
+
+  if (!getDerived().AlwaysRebuild() && LHS.get() == E->getLHS() &&
+      RHS.get() == E->getRHS() &&
+      FPFeaturesState.getFPFeatures() == getSema().CurFPFeatures)
     return E;
 
   if (E->isCompoundAssignmentOp())
-    // FPFeatures has already been established from trailing storage
+    // FPFeatures has already been established from trailing storage by
+    // TransformCompoundAssignOperator.
     return getDerived().RebuildBinaryOperator(
         E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get());
-  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
-  FPOptionsOverride NewOverrides(E->getFPFeatures());
-  getSema().CurFPFeatures =
-      NewOverrides.applyOverrides(getSema().getLangOpts());
-  getSema().FpPragmaStack.CurrentValue = NewOverrides;
+
   return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(),
                                             LHS.get(), RHS.get());
 }
@@ -11253,10 +11264,7 @@
 TreeTransform<Derived>::TransformCompoundAssignOperator(
                                                       CompoundAssignOperator *E) {
   Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
-  FPOptionsOverride NewOverrides(E->getFPFeatures());
-  getSema().CurFPFeatures =
-      NewOverrides.applyOverrides(getSema().getLangOpts());
-  getSema().FpPragmaStack.CurrentValue = NewOverrides;
+  setFPOptions(E);
   return getDerived().TransformBinaryOperator(E);
 }
 
@@ -11317,9 +11325,50 @@
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) {
+  ExprResult SubExpr = getDerived().TransformExpr(E->getSubExprAsWritten());
+  if (SubExpr.isInvalid())
+    return ExprError();
+
   // Implicit casts are eliminated during transformation, since they
   // will be recomputed by semantic analysis after transformation.
-  return getDerived().TransformExpr(E->getSubExprAsWritten());
+  // If however the cast involves floating-point transformations, it may keep
+  // FP options with it. In this case the implicit cast must be processed here,
+  // because semantic actions made latter have no access to the FP options.
+  switch (E->getCastKind()) {
+  default:
+    return SubExpr;
+  case CastKind::CK_FloatingCast:
+  case CastKind::CK_FloatingComplexCast:
+  case CastKind::CK_FloatingComplexToIntegralComplex:
+  case CastKind::CK_IntegralComplexToFloatingComplex:
+  case CastKind::CK_IntegralToFloating:
+  case CastKind::CK_FloatingToIntegral:
+  case CastKind::CK_FloatingToBoolean:
+  case CastKind::CK_FloatingComplexToBoolean:
+    break;
+  }
+
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
+  setFPOptions(E);
+
+  if (FPFeaturesState.getFPFeatures() == getSema().CurFPFeatures)
+    return SubExpr;
+
+  if (SubExpr.get()->isLValue())
+    SubExpr = ImplicitCastExpr::Create(
+        getSema().getASTContext(),
+        SubExpr.get()->getType().getNonReferenceType(), CK_LValueToRValue,
+        SubExpr.get(), nullptr, VK_PRValue, getSema().CurFPFeatureOverrides());
+  if (SubExpr.isInvalid())
+    return ExprError();
+
+  QualType T = getDerived().TransformType(E->getType());
+  if (T.isNull())
+    return ExprError();
+
+  return ImplicitCastExpr::Create(
+      getSema().getASTContext(), T, E->getCastKind(), SubExpr.get(), nullptr,
+      VK_PRValue, getSema().CurFPFeatureOverrides());
 }
 
 template<typename Derived>
@@ -11334,9 +11383,12 @@
   if (SubExpr.isInvalid())
     return ExprError();
 
-  if (!getDerived().AlwaysRebuild() &&
-      Type == E->getTypeInfoAsWritten() &&
-      SubExpr.get() == E->getSubExpr())
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
+  setFPOptions(E);
+
+  if (!getDerived().AlwaysRebuild() && Type == E->getTypeInfoAsWritten() &&
+      SubExpr.get() == E->getSubExpr() &&
+      FPFeaturesState.getFPFeatures() == getSema().CurFPFeatures)
     return E;
 
   return getDerived().RebuildCStyleCastExpr(E->getLParenLoc(),
@@ -11728,18 +11780,15 @@
       return ExprError();
   }
 
-  if (!getDerived().AlwaysRebuild() &&
-      Callee.get() == E->getCallee() &&
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
+  setFPOptions(E);
+
+  if (!getDerived().AlwaysRebuild() && Callee.get() == E->getCallee() &&
       First.get() == E->getArg(0) &&
-      (E->getNumArgs() != 2 || Second.get() == E->getArg(1)))
+      (E->getNumArgs() != 2 || Second.get() == E->getArg(1)) &&
+      FPFeaturesState.getFPFeatures() == getSema().CurFPFeatures)
     return SemaRef.MaybeBindToTemporary(E);
 
-  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
-  FPOptionsOverride NewOverrides(E->getFPFeatures());
-  getSema().CurFPFeatures =
-      NewOverrides.applyOverrides(getSema().getLangOpts());
-  getSema().FpPragmaStack.CurrentValue = NewOverrides;
-
   return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),
                                                  E->getOperatorLoc(),
                                                  Callee.get(),
@@ -11811,10 +11860,14 @@
   if (SubExpr.isInvalid())
     return ExprError();
 
-  if (!getDerived().AlwaysRebuild() &&
-      Type == E->getTypeInfoAsWritten() &&
-      SubExpr.get() == E->getSubExpr())
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
+  setFPOptions(E);
+
+  if (!getDerived().AlwaysRebuild() && Type == E->getTypeInfoAsWritten() &&
+      SubExpr.get() == E->getSubExpr() &&
+      FPFeaturesState.getFPFeatures() == getSema().CurFPFeatures)
     return E;
+
   return getDerived().RebuildCXXNamedCastExpr(
       E->getOperatorLoc(), E->getStmtClass(), E->getAngleBrackets().getBegin(),
       Type, E->getAngleBrackets().getEnd(),
@@ -11883,9 +11936,12 @@
   if (SubExpr.isInvalid())
     return ExprError();
 
-  if (!getDerived().AlwaysRebuild() &&
-      Type == E->getTypeInfoAsWritten() &&
-      SubExpr.get() == E->getSubExpr())
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
+  setFPOptions(E);
+
+  if (!getDerived().AlwaysRebuild() && Type == E->getTypeInfoAsWritten() &&
+      SubExpr.get() == E->getSubExpr() &&
+      FPFeaturesState.getFPFeatures() == getSema().CurFPFeatures)
     return E;
 
   return getDerived().RebuildCXXFunctionalCastExpr(Type,
diff --git a/clang/test/CodeGen/fp-pragma-template.cpp b/clang/test/CodeGen/fp-pragma-template.cpp
new file mode 100644
--- /dev/null
+++ b/clang/test/CodeGen/fp-pragma-template.cpp
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -S -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+
+// If a pragma is used inside template, it has effect on all instantiations.
+
+template <typename Ty>
+float func_01(float x, float y) {
+#pragma STDC FENV_ROUND FE_DOWNWARD
+  return x + y;
+}
+
+#pragma STDC FENV_ROUND FE_TONEAREST
+template float func_01<short>(float, float); 
+// CHECK-LABEL: define {{.*}}float @_Z7func_01IsEfff(float {{.*}}, float {{.*}}) {{.*}}{
+// CHECK: float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.downward", metadata !"fpexcept.ignore")
+
+float func_02(float x, float y) {
+  return func_01<long>(x, y);
+}
+// CHECK-LABEL: define {{.*}}float @_Z7func_02ff(float {{.*}}, float {{.*}}) {{.*}}{
+// CHECK: call {{.*}}float @_Z7func_01IlEfff(
+
+// CHECK-LABEL: define {{.*}}float @_Z7func_01IlEfff(float {{.*}}, float {{.*}}) {{.*}}{
+// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.downward", metadata !"fpexcept.ignore")
+
+template <typename Ty>
+float func_03(float x, float y, float z) {
+#pragma STDC FENV_ROUND FE_TOWARDZERO
+  float res = 3.0F * x;
+  {
+    #pragma STDC FENV_ROUND FE_UPWARD
+    res += y;
+  }
+  return res - z;
+}
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+template float func_03<short>(float, float, float); 
+// CHECK-LABEL: define {{.*}}float @_Z7func_03IsEffff(float {{.*}}, float {{.*}}) {{.*}}{
+// CHECK: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.ignore")
+// CHECK: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+
+
+// A pragma at file level has the same effect as if the same pragma were
+// specified at the start of each affected function.
+
+#pragma STDC FENV_ROUND FE_UPWARD
+template <typename Ty>
+float func_04(float x, float y) {
+  return x + y;
+}
+
+#pragma STDC FENV_ROUND FE_TONEAREST
+template float func_04<short>(float, float); 
+// CHECK-LABEL: define {{.*}}float @_Z7func_04IsEfff(float {{.*}}, float {{.*}}) {{.*}}{
+// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.ignore")
+
+
+// Explicit instantiation inherits FP features of the point of instantiation,
+// unless they are explicitly overridden by pragmas in the template.
+
+#pragma STDC FENV_ROUND FE_DYNAMIC
+template <typename Ty>
+float func_05(float x, float y) {
+  return x + y;
+}
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+template float func_05<short>(float, float); 
+// CHECK-LABEL: define {{.*}}float @_Z7func_05IsEfff(float {{.*}}, float {{.*}}) {{.*}}{
+// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.downward", metadata !"fpexcept.ignore")
+
+#pragma STDC FENV_ROUND FE_DYNAMIC
+float func_06(float x, float y) {
+  return func_05<long>(x, y);
+}
+// CHECK-LABEL: define {{.*}}float @_Z7func_06ff(float {{.*}}, float {{.*}}) {{.*}}{
+// CHECK: call {{.*}}float @_Z7func_05IlEfff(
+
+// CHECK-LABEL: define {{.*}}float @_Z7func_05IlEfff(float {{.*}}, float {{.*}}) {{.*}}{
+// CHECK: fadd