zahiraam created this revision.
zahiraam added reviewers: andrew.w.kaylor, aaron.ballman.
Herald added a project: All.
zahiraam requested review of this revision.
Herald added a project: clang.

When float_t and double_t types are used inside a scope with potential ABI 
breakage. See https://godbolt.org/z/56zG4Wo91
This patch prevents this.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D146148

Files:
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/Parse/ParseStmt.cpp
  clang/test/CodeGen/Inputs/math.h
  clang/test/CodeGen/abi-check-1.c
  clang/test/CodeGen/abi-check-2.c
  clang/test/CodeGen/abi-check-3.c

Index: clang/test/CodeGen/abi-check-3.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/abi-check-3.c
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1  -isystem %S/Inputs -triple x86_64-linux-gnu \
+// RUN: -emit-llvm -o - %s | FileCheck %s
+
+// RUN: not %clang_cc1  -isystem %S/Inputs -triple x86_64-linux-gnu \
+// RUN: -ffp-eval-method=source -emit-obj -o %t %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ERROR-1 %s
+
+// RUN: not %clang_cc1  -isystem %S/Inputs -triple x86_64-linux-gnu \
+// RUN: -ffp-eval-method=double -emit-obj -o %t %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ERROR-2 %s
+
+// RUN: %clang_cc1  -isystem %S/Inputs -triple x86_64-linux-gnu \
+// RUN: -ffp-eval-method=extended -emit-llvm -o - %s \
+// RUN: | FileCheck -check-prefix=CHECK-EXT %s
+
+#include <math.h>
+
+float foo1() {
+#pragma clang fp eval_method(extended)
+
+  float_t a; 
+  double_t b; 
+  // CHECK: alloca float
+  // CHECK: alloca double
+  // CHECK-EXT: alloca x86_fp80
+  // CHECK-EXT: alloca x86_fp80
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(extended)' when a command line option 'ffp-eval-method=source' is used
+  // ERROR-1: error: double_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(extended)' when a command line option 'ffp-eval-method=source' is used
+  // ERROR-2: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(extended)' when a command line option 'ffp-eval-method=double' is used
+  // ERROR-2: error: double_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(extended)' when a command line option 'ffp-eval-method=double' is used
+
+  return  a - b;
+}
+
Index: clang/test/CodeGen/abi-check-2.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/abi-check-2.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1  -isystem %S/Inputs -triple x86_64-linux-gnu \
+// RUN: -emit-llvm -o - %s | FileCheck %s
+
+// RUN: not %clang_cc1  -isystem %S/Inputs -triple x86_64-linux-gnu \
+// RUN: -ffp-eval-method=source -emit-obj -o %t %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ERROR-1 %s
+
+// RUN: %clang_cc1  -isystem %S/Inputs -triple x86_64-linux-gnu \
+// RUN: -ffp-eval-method=double -emit-llvm -o - %s \
+// RUN: | FileCheck -check-prefix=CHECK-DBL %s
+
+// RUN: not %clang_cc1  -isystem %S/Inputs -triple x86_64-linux-gnu \
+// RUN: -ffp-eval-method=extended -emit-obj -o %t %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ERROR-2 %s
+
+#include <math.h>
+
+float foo1() {
+#pragma clang fp eval_method(double)
+
+  float_t a; 
+  double_t b; 
+  // CHECK: alloca float
+  // CHECK: alloca double
+  // CHECK-DBL: alloca double
+  // CHECK-DBL: alloca double
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(double)' when a command line option 'ffp-eval-method=source' is used
+  // ERROR-1: error: double_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(double)' when a command line option 'ffp-eval-method=source' is used
+  // ERROR-2: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(double)' when a command line option 'ffp-eval-method=extended' is used
+  // ERROR-2: error: double_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(double)' when a command line option 'ffp-eval-method=extended' is used
+  return  a - b;
+}
+
Index: clang/test/CodeGen/abi-check-1.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/abi-check-1.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1  -isystem %S/Inputs -triple x86_64-linux-gnu \
+// RUN: -emit-llvm -o - %s | FileCheck %s
+
+// RUN: %clang_cc1  -isystem %S/Inputs -ffp-eval-method=source \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// RUN: not %clang_cc1  -isystem %S/Inputs -triple x86_64-linux-gnu \
+// RUN: -ffp-eval-method=double -emit-obj -o %t %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ERROR-1 %s
+
+// RUN: not %clang_cc1  -isystem %S/Inputs -triple x86_64-linux-gnu \
+// RUN: -ffp-eval-method=extended -emit-obj -o %t %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ERROR-2 %s
+
+#include <math.h>
+
+float foo1() {
+#pragma clang fp eval_method(source)
+
+  float_t a; 
+  double_t b; 
+  // CHECK: alloca float
+  // CHECK: alloca double
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(source)' when a command line option 'ffp-eval-method=double' is used
+  // ERROR-1: error: double_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(source)' when a command line option 'ffp-eval-method=double' is used
+  // ERROR-2: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(source)' when a command line option 'ffp-eval-method=extended' is used
+  // ERROR-2: error: double_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(source)' when a command line option 'ffp-eval-method=extended' is used
+  return  a - b;
+}
+
Index: clang/test/CodeGen/Inputs/math.h
===================================================================
--- /dev/null
+++ clang/test/CodeGen/Inputs/math.h
@@ -0,0 +1,43 @@
+#ifdef __FLT_EVAL_METHOD__
+#if __FLT_EVAL_METHOD__ == -1
+#define __GLIBC_FLT_EVAL_METHOD 2
+#else
+#define __GLIBC_FLT_EVAL_METHOD __FLT_EVAL_METHOD__
+#endif
+#elif defined __x86_64__
+#define __GLIBC_FLT_EVAL_METHOD 0
+#else
+#define __GLIBC_FLT_EVAL_METHOD 2
+#endif
+
+# if __GLIBC_FLT_EVAL_METHOD == 0 || __GLIBC_FLT_EVAL_METHOD == 16
+typedef float float_t;
+typedef double double_t;
+# elif __GLIBC_FLT_EVAL_METHOD == 1
+typedef double float_t;
+typedef double double_t;
+# elif __GLIBC_FLT_EVAL_METHOD == 2
+typedef long double float_t;
+typedef long double double_t;
+# elif __GLIBC_FLT_EVAL_METHOD == 32
+typedef _Float32 float_t;
+typedef double double_t;
+# elif __GLIBC_FLT_EVAL_METHOD == 33
+typedef _Float32x float_t;
+typedef _Float32x double_t;
+# elif __GLIBC_FLT_EVAL_METHOD == 64
+typedef _Float64 float_t;
+typedef _Float64 double_t;
+# elif __GLIBC_FLT_EVAL_METHOD == 65
+typedef _Float64x float_t;
+typedef _Float64x double_t;
+# elif __GLIBC_FLT_EVAL_METHOD == 128
+typedef _Float128 float_t;
+typedef _Float128 double_t;
+# elif __GLIBC_FLT_EVAL_METHOD == 129
+typedef _Float128x float_t;
+typedef _Float128x double_t;
+# else
+#  error "Unknown __GLIBC_FLT_EVAL_METHOD"
+# endif
+
Index: clang/lib/Parse/ParseStmt.cpp
===================================================================
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -1111,6 +1111,19 @@
   return Actions.ActOnExprStmt(E, /*DiscardedValue=*/!IsStmtExprResult);
 }
 
+StringRef EvalMethodValToStr(LangOptions::FPEvalMethodKind Kind) {
+  switch (Kind) {
+  case LangOptions::FPEvalMethodKind::FEM_Double:
+    return "double";
+  case LangOptions::FPEvalMethodKind::FEM_Extended:
+    return "extended";
+  case LangOptions::FPEvalMethodKind::FEM_Source:
+    return "source";
+  default:
+    llvm_unreachable("unexpected eval method value");
+  }
+}
+
 /// ParseCompoundStatementBody - Parse a sequence of statements optionally
 /// followed by a label and invoke the ActOnCompoundStmt action.  This expects
 /// the '{' to be the current token, and consume the '}' at the end of the
@@ -1182,6 +1195,19 @@
       continue;
 
     StmtResult R;
+    if (Tok.is(tok::identifier)) {
+      if (Tok.getIdentifierInfo()->getName().str() == "float_t" ||
+          Tok.getIdentifierInfo()->getName().str() == "double_t") {
+        if (getLangOpts().getFPEvalMethod() !=
+                LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine &&
+            PP.getLastFPEvalPragmaLocation().isValid() &&
+            PP.getCurrentFPEvalMethod() != getLangOpts().getFPEvalMethod())
+          Diag(Tok.getLocation(), diag::err_type_definition_cannot_be_modified)
+              << Tok.getIdentifierInfo()->getName().str()
+              << EvalMethodValToStr(PP.getCurrentFPEvalMethod())
+              << EvalMethodValToStr(getLangOpts().getFPEvalMethod());
+      }
+    }
     if (Tok.isNot(tok::kw___extension__)) {
       R = ParseStatementOrDeclaration(Stmts, SubStmtCtx);
     } else {
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -659,6 +659,10 @@
 def warn_cxx20_compat_consteval_if : Warning<
   "consteval if is incompatible with C++ standards before C++2b">,
   InGroup<CXXPre2bCompat>, DefaultIgnore;
+def err_type_definition_cannot_be_modified : Error<
+  "%0 type definition cannot be modified inside a scope containing "
+  "'#pragma clang fp eval_method(%1)' when a command line "
+  "option 'ffp-eval-method=%2' is used">;
 
 def ext_init_statement : ExtWarn<
   "'%select{if|switch}0' initialization statements are a C++17 extension">,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to