[clang] Set FP options in Sema when instantiating CompoundStmt
authorSerge Pavlov <sepavloff@gmail.com>
Mon, 21 Aug 2023 05:20:37 +0000 (12:20 +0700)
committerTobias Hieta <tobias@hieta.se>
Fri, 25 Aug 2023 07:34:51 +0000 (09:34 +0200)
When an expression is instantiated, TreeTransform skips ImplicitCastExpr
nodes, assuming they are recreated when the instantiated expression is
built. It breaks functions that use non-default floating-point options,
because they are kept in these ImplicitCastExprs. In this case the
recreated ImplicitCastExpr takes FP options from the current Sema state
and not from AST node.

To fix this issue the FP options in Sema object are set when a compound
statement is cloned in TreeTransform.

This change fixes https://github.com/llvm/llvm-project/issues/64605
([Regression 16 -> 17] Template instantiation ignores FENV_ACCESS being
ON for both definition and instantiation).

Differential Revision: https://reviews.llvm.org/D158158

(cherry picked from commit 0baf85c331090fbe2d2b42214ed0664d55feb0b5)

clang/lib/Sema/TreeTransform.h
clang/test/SemaCXX/template-64605.cpp [new file with mode: 0644]

index 10b3587..097e81e 100644 (file)
@@ -7478,6 +7478,10 @@ StmtResult
 TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
                                               bool IsStmtExpr) {
   Sema::CompoundScopeRAII CompoundScope(getSema());
+  Sema::FPFeaturesStateRAII FPSave(getSema());
+  if (S->hasStoredFPFeatures())
+    getSema().resetFPOptions(
+        S->getStoredFPFeatures().applyOverrides(getSema().getLangOpts()));
 
   const Stmt *ExprResult = S->getStmtExprResult();
   bool SubStmtInvalid = false;
diff --git a/clang/test/SemaCXX/template-64605.cpp b/clang/test/SemaCXX/template-64605.cpp
new file mode 100644 (file)
index 0000000..b13acbf
--- /dev/null
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -ast-dump -ast-dump-filter=b_64605 %s | FileCheck %s
+
+// https://github.com/llvm/llvm-project/issues/64605
+
+#pragma STDC FENV_ACCESS ON
+template <typename>
+int b_64605() {
+  int x;
+  if ((float)0xFFFFFFFF != (float)0x100000000) {
+    x = 1;
+  }
+  return x;
+}
+int f() { return b_64605<void>(); }
+
+// CHECK:      ImplicitCastExpr {{.*}} 'float' <IntegralToFloating> RoundingMath=1 AllowFEnvAccess=1
+// CHECK-NEXT: IntegerLiteral {{.*}} 4294967295
+
+// CHECK:      FunctionDecl {{.*}} b_64605 'int ()' implicit_instantiation
+// CHECK-NEXT: TemplateArgument type 'void'
+
+// CHECK:      ImplicitCastExpr {{.*}} 'float' <IntegralToFloating> RoundingMath=1 AllowFEnvAccess=1
+// CHECK-NEXT: IntegerLiteral {{.*}} 4294967295