zahiraam updated this revision to Diff 507360.

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

https://reviews.llvm.org/D146148

Files:
  clang/docs/LanguageExtensions.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaType.cpp
  clang/test/Sema/Inputs/math.h
  clang/test/Sema/abi-check-1.cpp
  clang/test/Sema/abi-check-2.cpp
  clang/test/Sema/abi-check-3.cpp

Index: clang/test/Sema/abi-check-3.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/abi-check-3.cpp
@@ -0,0 +1,151 @@
+// 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 a;
+  double b;
+  // CHECK: alloca float
+  // CHECK: alloca double
+  return a - b;
+}
+
+float foo2() {
+#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 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 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 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 command line option 'ffp-eval-method=double' is used
+  return a - b;
+}
+
+void foo3() {
+#pragma clang fp eval_method(extended)
+  char buff[sizeof(float_t)];
+  char bufd[sizeof(double_t)];
+  // CHECK:  alloca [4 x i8]
+  // CHECK:  alloca [8 x i8]
+  // CHECK-DBL: alloca [8 x i8]
+  // CHECK-DBL: alloca [8 x i8]
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(extended)' when 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 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 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 command line option 'ffp-eval-method=double' is used
+  buff[1] = bufd[2];
+}
+
+float foo4() {
+#pragma clang fp eval_method(extended)
+  typedef float_t FT;
+  typedef double_t DT;
+  FT a;
+  DT 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 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 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 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 command line option 'ffp-eval-method=double' is used
+  return a - b;
+}
+
+int foo5() {
+#pragma clang fp eval_method(extended)
+  int t = _Generic( 1.0L, float_t:1, default:0);
+  int v = _Generic( 1.0L, double_t:1, default:0);
+  // CHECK: alloca i32
+  // CHECK: alloca i32
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(extended)' when 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 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 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 command line option 'ffp-eval-method=double' is used
+  return t;
+}
+
+void foo6() {
+#pragma clang fp eval_method(extended)
+  auto resf = [](float_t f) { return f; };
+  auto resd = [](double_t g) { return g; };
+  // CHECK:  alloca %class.anon
+  // CHECK:  alloca %class.anon
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(extended)' when 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 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 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 command line option 'ffp-eval-method=double' is used
+}
+
+void foo7() {
+#pragma clang fp eval_method(extended)
+  float f = (float_t)1; 
+  double d = (double_t)2; 
+  // 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(extended)' when 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 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 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 command line option 'ffp-eval-method=double' is used
+}
+
+void foo8() {
+#pragma clang fp eval_method(extended)
+  using Ft = float_t;
+  using Dt = double_t;
+  // 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 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 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 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 command line option 'ffp-eval-method=double' is used
+  Ft a;
+  Dt b;
+}
+
+void foo9() {
+#pragma clang fp eval_method(extended)
+  float c1 = (float_t)12;
+  double c2 = (double_t)13;
+  // 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(extended)' when 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 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 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 command line option 'ffp-eval-method=double' is used
+}
+
+float foo10() {
+#pragma clang fp eval_method(extended)
+  extern float_t f;
+  extern double_t g;
+  // CHECK: load double
+  // CHECK-EXT: load x86_fp80
+  // CHECK-EXT: load x86_fp80
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(extended)' when 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 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 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 command line option 'ffp-eval-method=double' is used
+  return f-g;
+}
Index: clang/test/Sema/abi-check-2.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/abi-check-2.cpp
@@ -0,0 +1,149 @@
+// 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 a;
+  double b;
+  // CHECK: alloca float
+  // CHECK: alloca double
+  return a - b;
+}
+
+float foo2() {
+#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 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 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 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 command line option 'ffp-eval-method=extended' is used
+  return a - b;
+}
+
+void foo3() {
+#pragma clang fp eval_method(double)
+  char buff[sizeof(float_t)];
+  char bufd[sizeof(double_t)];
+  // CHECK:  alloca [4 x i8]
+  // CHECK:  alloca [8 x i8]
+  // CHECK-DBL: alloca [8 x i8]
+  // CHECK-DBL: alloca [8 x i8]
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(double)' when 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 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 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 command line option 'ffp-eval-method=extended' is used
+  buff[1] = bufd[2];
+}
+
+float foo4() {
+#pragma clang fp eval_method(double)
+  typedef float_t FT;
+  typedef double_t DT;
+  FT a;
+  DT 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 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 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 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 command line option 'ffp-eval-method=extended' is used
+  return a - b;
+}
+
+int foo5() {
+#pragma clang fp eval_method(double)
+  int t = _Generic( 1.0L, float_t:1, default:0);
+  int v = _Generic( 1.0L, double_t:1, default:0);
+  // CHECK: alloca i32
+  // CHECK: alloca i32
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(double)' when 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 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 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 command line option 'ffp-eval-method=extended' is used
+  return t;
+}
+
+void foo6() {
+#pragma clang fp eval_method(double)
+  auto resf = [](float_t f) { return f; };
+  auto resd = [](double_t g) { return g; };
+  // CHECK:  alloca %class.anon
+  // CHECK:  alloca %class.anon
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(double)' when 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 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 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 command line option 'ffp-eval-method=extended' is used
+}
+
+void foo7() {
+#pragma clang fp eval_method(double)
+  float f = (float_t)1; 
+  double d = (double_t)2; 
+  // 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(double)' when 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 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 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 command line option 'ffp-eval-method=extended' is used
+}
+
+void foo8() {
+#pragma clang fp eval_method(double)
+  using Ft = float_t;
+  using Dt = double_t;
+  // 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 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 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 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 command line option 'ffp-eval-method=extended' is used
+  Ft a;
+  Dt b;
+}
+
+void foo9() {
+#pragma clang fp eval_method(double)
+  float c1 = (float_t)12;
+  double c2 = (double_t)13;
+  // 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(double)' when 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 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 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 command line option 'ffp-eval-method=extended' is used
+}
+
+float foo10() {
+#pragma clang fp eval_method(double)
+  extern float_t f;
+  extern double_t g;
+  // CHECK: load double
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(double)' when 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 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 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 command line option 'ffp-eval-method=extended' is used
+  return f-g;
+}
Index: clang/test/Sema/abi-check-1.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/abi-check-1.cpp
@@ -0,0 +1,139 @@
+// 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 a;
+  double b;
+  // CHECK: alloca float
+  // CHECK: alloca double
+  return a - b;
+}
+
+float foo2() {
+#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 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 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 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 command line option 'ffp-eval-method=extended' is used
+  return a - b;
+}
+
+void foo3() {
+#pragma clang fp eval_method(source)
+  char buff[sizeof(float_t)];
+  char bufd[sizeof(double_t)];
+  // CHECK:  alloca [4 x i8]
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(source)' when 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 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 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 command line option 'ffp-eval-method=extended' is used
+  buff[1] = bufd[2];
+}
+
+float foo4() {
+#pragma clang fp eval_method(source)
+  typedef float_t FT;
+  typedef double_t DT;
+  FT a;
+  DT 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 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 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 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 command line option 'ffp-eval-method=extended' is used
+  return a - b;
+}
+
+int foo5() {
+#pragma clang fp eval_method(source)
+  int t = _Generic( 1.0L, float_t:1, default:0);
+  int v = _Generic( 1.0L, double_t:1, default:0);
+  // CHECK: alloca i32
+  // CHECK: alloca i32
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(source)' when 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 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 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 command line option 'ffp-eval-method=extended' is used
+  return t;
+}
+
+void foo6() {
+#pragma clang fp eval_method(source)
+  auto resf = [](float_t f) { return f; };
+  auto resd = [](double_t g) { return g; };
+  // CHECK:  alloca %class.anon
+  // CHECK:  alloca %class.anon
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(source)' when 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 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 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 command line option 'ffp-eval-method=extended' is used
+}
+
+void foo7() {
+#pragma clang fp eval_method(source)
+  float f = (float_t)1; 
+  double d = (double_t)2; 
+  // 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 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 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 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 command line option 'ffp-eval-method=extended' is used
+}
+
+void foo8() {
+#pragma clang fp eval_method(source)
+  using Ft = float_t;
+  using Dt = double_t;
+  // 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 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 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 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 command line option 'ffp-eval-method=extended' is used
+  Ft a;
+  Dt b;
+}
+
+void foo9() {
+#pragma clang fp eval_method(source)
+  float c1 = (float_t)12;
+  double c2 = (double_t)13;
+  // 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 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 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 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 command line option 'ffp-eval-method=extended' is used
+}
+
+float foo10() {
+#pragma clang fp eval_method(source)
+  extern float_t f;
+  extern double_t g;
+  // CHECK: load float
+  // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(source)' when 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 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 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 command line option 'ffp-eval-method=extended' is used
+  return f-g;
+}
Index: clang/test/Sema/Inputs/math.h
===================================================================
--- /dev/null
+++ clang/test/Sema/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/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -4601,6 +4601,23 @@
   return false;
 }
 
+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:
+    // The only way we land here is with the value of Kind being
+    // FEM_Inderterminable, and this should never happen.
+    assert((Kind != LangOptions::FPEvalMethodKind::FEM_Indeterminable) &&
+           "unexpected eval method value");
+    llvm_unreachable("unexpected eval method value");
+  }
+}
+
 static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
                                                 QualType declSpecType,
                                                 TypeSourceInfo *TInfo) {
@@ -4971,6 +4988,18 @@
       checkNullabilityConsistency(S, SimplePointerKind::Array,
                                   D.getDeclSpec().getTypeSpecTypeLoc());
     }
+    if (T->isFloatingType() &&
+        (T.getAsString() == "float_t" || T.getAsString() == "double_t"))
+      if (S.getLangOpts().getFPEvalMethod() !=
+              LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine &&
+          S.PP.getLastFPEvalPragmaLocation().isValid() &&
+          S.PP.getCurrentFPEvalMethod() != S.getLangOpts().getFPEvalMethod())
+        S.Diag(D.getIdentifierLoc(),
+               diag::err_type_definition_cannot_be_modified)
+            << T.getAsString()
+            << EvalMethodValToStr(S.PP.getCurrentFPEvalMethod())
+            << EvalMethodValToStr(S.getLangOpts().getFPEvalMethod());
+
   }
 
   bool ExpectNoDerefChunk =
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11499,6 +11499,11 @@
 
 def err_objc_type_args_wrong_arity : Error<
   "too %select{many|few}0 type arguments for class %1 (have %2, expected %3)">;
+
+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 command line option "
+  "'ffp-eval-method=%2' is used">;
 }
 
 def err_objc_type_arg_not_id_compatible : Error<
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -4320,6 +4320,13 @@
     a = b[i] * c[i] + e;
   }
 
+Note: the types ``float_t`` and ``double_t`` are defined in the math header file.
+Their definition changes with the eval method. If they are used inside a scope
+containing a ``#pragma clang fp eval_method`` their definition end up being
+different than what the user might have intended. This can potentially generate
+incorrect code, leading to an ABI mismatch. This case is prevented by emitting a
+diagnostic.
+
 The ``#pragma float_control`` pragma allows precise floating-point
 semantics and floating-point exception behavior to be specified
 for a section of the source code. This pragma can only appear at file or
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to