zahiraam updated this revision to Diff 532293.
zahiraam marked 3 inline comments as done.

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

https://reviews.llvm.org/D146148

Files:
  clang/docs/LanguageExtensions.rst
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Basic/IdentifierTable.h
  clang/include/clang/Basic/TokenKinds.def
  clang/include/clang/Basic/TokenKinds.h
  clang/lib/Basic/Builtins.cpp
  clang/lib/Basic/IdentifierTable.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaLookup.cpp
  clang/test/Sema/abi-check-1.cpp
  clang/test/Sema/abi-check-2.cpp
  clang/test/Sema/abi-check-3.cpp
  clang/test/Sema/attr-only-in-default-eval.cpp

Index: clang/test/Sema/attr-only-in-default-eval.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/attr-only-in-default-eval.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef float float_t [[clang::available_only_in_default_eval_method]];
+using double_t __attribute__((available_only_in_default_eval_method)) = double;
+
+// expected-error@+1{{'available_only_in_default_eval_method' attribute only applies to typedefs}}
+class  __attribute__((available_only_in_default_eval_method)) C1 {
+};
+// expected-error@+1{{'available_only_in_default_eval_method' attribute only applies to typedefs}}
+class  [[clang::available_only_in_default_eval_method]] C2 {
+};
+
+// expected-error@+1{{'available_only_in_default_eval_method' attribute only applies to typedefs}}
+struct [[clang::available_only_in_default_eval_method]] S1;
+// expected-error@+1{{'available_only_in_default_eval_method' attribute only applies to typedefs}}
+struct __attribute__((available_only_in_default_eval_method)) S2;
+
+// expected-error@+1{{'available_only_in_default_eval_method' attribute only applies to typedefs}}
+void __attribute__((available_only_in_default_eval_method)) foo();
+// expected-error@+1{{'available_only_in_default_eval_method' attribute cannot be applied to types}}
+void [[clang::available_only_in_default_eval_method]] goo();
+// expected-error@+1{{'available_only_in_default_eval_method' attribute cannot be applied to types}}
+void bar() [[clang::available_only_in_default_eval_method]];
+// expected-error@+1{{'available_only_in_default_eval_method' attribute only applies to typedefs}}
+void barz() __attribute__((available_only_in_default_eval_method));
+
Index: clang/test/Sema/abi-check-3.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/abi-check-3.cpp
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -DNOERROR %s
+// RUN: %clang_cc1 -fsyntax-only -verify -ffp-eval-method=extended -DNOERROR %s
+
+// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=source %s
+// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=double %s
+
+
+#ifdef NOERROR
+// expected-no-diagnostics
+typedef float float_t;
+typedef double double_t;
+#else
+typedef float float_t; //expected-error 9 {{cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
+
+typedef double double_t; //expected-error 9 {{cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
+#endif
+
+float foo1() {
+#pragma clang fp eval_method(extended)
+  float a;
+  double b;
+  return a - b;
+}
+
+float foo2() {
+#pragma clang fp eval_method(extended)
+  float_t a; 
+  double_t b; 
+  return a - b;
+}
+
+void foo3() {
+#pragma clang fp eval_method(extended)
+  char buff[sizeof(float_t)];
+  char bufd[sizeof(double_t)];
+  buff[1] = bufd[2];
+}
+
+float foo4() {
+#pragma clang fp eval_method(extended)
+  typedef float_t FT;
+  typedef double_t DT;
+  FT a;
+  DT b;
+  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);
+  return t;
+}
+
+void foo6() {
+#pragma clang fp eval_method(extended)
+  auto resf = [](float_t f) { return f; };
+  auto resd = [](double_t g) { return g; };
+}
+
+void foo7() {
+#pragma clang fp eval_method(extended)
+  float f = (float_t)1; 
+  double d = (double_t)2; 
+}
+
+void foo8() {
+#pragma clang fp eval_method(extended)
+  using Ft = float_t;
+  using Dt = double_t;
+  Ft a;
+  Dt b;
+}
+
+void foo9() {
+#pragma clang fp eval_method(extended)
+  float c1 = (float_t)12;
+  double c2 = (double_t)13;
+}
+
+float foo10() {
+#pragma clang fp eval_method(extended)
+  extern float_t f;
+  extern double_t g;
+  return f-g;
+}
Index: clang/test/Sema/abi-check-2.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/abi-check-2.cpp
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -DNOERROR %s
+// RUN: %clang_cc1 -fsyntax-only -verify -ffp-eval-method=double -DNOERROR %s
+
+// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=source %s
+// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=extended %s
+
+#ifdef NOERROR
+// expected-no-diagnostics
+typedef float float_t;
+typedef double double_t;
+#else
+typedef float float_t; //expected-error 9 {{cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
+
+typedef double double_t; //expected-error 9 {{cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
+#endif
+
+float foo1() {
+#pragma clang fp eval_method(double)
+  float a;
+  double b;
+  return a - b;
+}
+
+float foo2() {
+#pragma clang fp eval_method(double)
+  float_t a; 
+  double_t b; 
+  return a - b;
+}
+
+void foo3() {
+#pragma clang fp eval_method(double)
+  char buff[sizeof(float_t)];
+  char bufd[sizeof(double_t)];
+  buff[1] = bufd[2];
+}
+
+float foo4() {
+#pragma clang fp eval_method(double)
+  typedef float_t FT;
+  typedef double_t DT;
+  FT a;
+  DT b;
+  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);
+  return t;
+}
+
+void foo6() {
+#pragma clang fp eval_method(double)
+  auto resf = [](float_t f) { return f; };
+  auto resd = [](double_t g) { return g; };
+}
+
+void foo7() {
+#pragma clang fp eval_method(double)
+  float f = (float_t)1; 
+  double d = (double_t)2; 
+}
+
+void foo8() {
+#pragma clang fp eval_method(double)
+  using Ft = float_t;
+  using Dt = double_t;
+  Ft a;
+  Dt b;
+}
+
+void foo9() {
+#pragma clang fp eval_method(double)
+  float c1 = (float_t)12;
+  double c2 = (double_t)13;
+}
+
+float foo10() {
+#pragma clang fp eval_method(double)
+  extern float_t f;
+  extern double_t g;
+  return f-g;
+}
Index: clang/test/Sema/abi-check-1.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/abi-check-1.cpp
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -DNOERROR %s
+// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=source -DNOERROR %s
+
+// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=double %s
+// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=extended %s
+
+#ifdef NOERROR
+// expected-no-diagnostics
+typedef float float_t;
+typedef double double_t;
+#else
+typedef float float_t; //expected-error 9 {{cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
+
+typedef double double_t; //expected-error 9 {{cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
+#endif
+
+float foo1() {
+#pragma clang fp eval_method(source)
+  float a;
+  double b;
+  return a - b;
+}
+
+float foo2() {
+#pragma clang fp eval_method(source)
+  float_t a; 
+  double_t b; 
+  return a - b;
+}
+
+void foo3() {
+#pragma clang fp eval_method(source)
+  char buff[sizeof(float_t)];
+  char bufd[sizeof(double_t)];
+  buff[1] = bufd[2];
+}
+
+float foo4() {
+#pragma clang fp eval_method(source)
+  typedef float_t FT;
+  typedef double_t DT;
+  FT a;
+  DT b;
+  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);
+  return t;
+}
+
+void foo6() {
+#pragma clang fp eval_method(source)
+  auto resf = [](float_t f) { return f; };
+  auto resd = [](double_t g) { return g; };
+}
+
+void foo7() {
+#pragma clang fp eval_method(source)
+  float f = (float_t)1; 
+  double d = (double_t)2; 
+}
+
+void foo8() {
+#pragma clang fp eval_method(source)
+  using Ft = float_t;
+  using Dt = double_t;
+  Ft a;
+  Dt b;
+}
+
+void foo9() {
+#pragma clang fp eval_method(source)
+  float c1 = (float_t)12;
+  double c2 = (double_t)13;
+}
+
+float foo10() {
+#pragma clang fp eval_method(source)
+  extern float_t f;
+  extern double_t g;
+  return f-g;
+}
+
Index: clang/lib/Sema/SemaLookup.cpp
===================================================================
--- clang/lib/Sema/SemaLookup.cpp
+++ clang/lib/Sema/SemaLookup.cpp
@@ -320,9 +320,10 @@
   // Compiler builtins are always visible, regardless of where they end
   // up being declared.
   if (IdentifierInfo *Id = NameInfo.getName().getAsIdentifierInfo()) {
-    if (unsigned BuiltinID = Id->getBuiltinID()) {
-      if (!getSema().Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
-        AllowHidden = true;
+     if (!Id->getInterestingIdentifierID())
+       if (unsigned BuiltinID = Id->getBuiltinID()) {
+         if (!getSema().Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+           AllowHidden = true;
     }
   }
 }
@@ -943,6 +944,10 @@
 
       // If this is a builtin on this (or all) targets, create the decl.
       if (unsigned BuiltinID = II->getBuiltinID()) {
+        if (unsigned ID = II->getInterestingIdentifierID()) {
+          // Don't think we should LazyCreate the interesting identifier?
+          return true;
+        }
         // In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined
         // library functions like 'malloc'. Instead, we'll just error.
         if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL) &&
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -374,6 +374,16 @@
 
   diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc);
 
+  if (D->hasAttr<AvailableOnlyInDefaultEvalMethodAttr>()) {
+    if (getLangOpts().getFPEvalMethod() !=
+	    LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine &&
+        PP.getLastFPEvalPragmaLocation().isValid() &&
+        PP.getCurrentFPEvalMethod() != getLangOpts().getFPEvalMethod())
+      Diag(D->getLocation(),
+           diag::err_type_available_only_in_default_eval_method)
+          << D->getName();
+  }
+
   if (auto *VD = dyn_cast<ValueDecl>(D))
     checkTypeSupport(VD->getType(), Loc, VD);
 
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -8369,6 +8369,12 @@
   D->addAttr(FunctionReturnThunksAttr::Create(S.Context, Kind, AL));
 }
 
+static void handleAvailableOnlyInDefaultEvalMethod(Sema &S, Decl *D,
+                                                   const ParsedAttr &AL) {
+  assert(isa<TypedefNameDecl>(D) && "This attribute only applies to a typedef");
+  handleSimpleAttribute<AvailableOnlyInDefaultEvalMethodAttr>(S, D, AL);
+}
+
 static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   // The 'sycl_kernel' attribute applies only to function templates.
   const auto *FD = cast<FunctionDecl>(D);
@@ -9250,6 +9256,10 @@
     handleFunctionReturnThunksAttr(S, D, AL);
     break;
 
+  case ParsedAttr::AT_AvailableOnlyInDefaultEvalMethod:
+    handleAvailableOnlyInDefaultEvalMethod(S, D, AL);
+    break;
+
   // Microsoft attributes:
   case ParsedAttr::AT_LayoutVersion:
     handleLayoutVersion(S, D, AL);
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -6441,6 +6441,15 @@
   if (!New)
     return nullptr;
 
+  if (New->hasAttr<AvailableOnlyInDefaultEvalMethodAttr>()) {
+    if (getLangOpts().getFPEvalMethod() !=
+            LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine &&
+        PP.getLastFPEvalPragmaLocation().isValid() &&
+        PP.getCurrentFPEvalMethod() != getLangOpts().getFPEvalMethod())
+      Diag(New->getLocation(),
+           diag::err_type_available_only_in_default_eval_method)
+          << New->getName();
+  }
   // If this has an identifier and is not a function template specialization,
   // add it to the scope stack.
   if (New->getDeclName() && AddToScope)
@@ -6771,6 +6780,8 @@
         Context.setsigjmp_bufDecl(NewTD);
       else if (II->isStr("ucontext_t"))
         Context.setucontext_tDecl(NewTD);
+      if (II->getInterestingIdentifierID() != 0)
+        NewTD->addAttr(AvailableOnlyInDefaultEvalMethodAttr::Create(Context));
     }
 
   return NewTD;
Index: clang/lib/Basic/IdentifierTable.cpp
===================================================================
--- clang/lib/Basic/IdentifierTable.cpp
+++ clang/lib/Basic/IdentifierTable.cpp
@@ -279,6 +279,13 @@
   Table.get(Name).setObjCKeywordID(ObjCID);
 }
 
+static void AddInterestingIdentifier(StringRef Name,
+                                     tok::InterestingIdentifierKind BTID,
+                                     IdentifierTable &Table) {
+  IdentifierInfo &Info = Table.get(Name, tok::identifier);
+  Info.setInterestingIdentifierID(BTID);
+}
+
 /// AddKeywords - Add all keywords to the symbol table.
 ///
 void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
@@ -295,6 +302,9 @@
 #define OBJC_AT_KEYWORD(NAME)  \
   if (LangOpts.ObjC)           \
     AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this);
+#define INTERESTING_IDENTIFIER(NAME)  \
+  AddInterestingIdentifier(StringRef(#NAME), tok::##NAME, *this);
+
 #define TESTING_KEYWORD(NAME, FLAGS)
 #include "clang/Basic/TokenKinds.def"
 
Index: clang/lib/Basic/Builtins.cpp
===================================================================
--- clang/lib/Basic/Builtins.cpp
+++ clang/lib/Basic/Builtins.cpp
@@ -151,7 +151,7 @@
       unsigned ID = NameIt->second->getBuiltinID();
       if (ID != Builtin::NotBuiltin && isPredefinedLibFunction(ID) &&
           isInStdNamespace(ID) == InStdNamespace) {
-        Table.get(Name).setBuiltinID(Builtin::NotBuiltin);
+        NameIt->second->clearBuiltinID();
       }
     }
   }
Index: clang/include/clang/Basic/TokenKinds.h
===================================================================
--- clang/include/clang/Basic/TokenKinds.h
+++ clang/include/clang/Basic/TokenKinds.h
@@ -44,6 +44,14 @@
   NUM_OBJC_KEYWORDS
 };
 
+/// Provides a namespace for interesting identifers such as float_t and
+/// double_t.
+enum InterestingIdentifierKind {
+#define INTERESTING_IDENTIFIER(X) X,
+#include "clang/Basic/TokenKinds.def"
+  NUM_INTERESTING_IDENTIFIERS
+};
+
 /// Defines the possible values of an on-off-switch (C99 6.10.6p2).
 enum OnOffSwitch {
   OOS_ON, OOS_OFF, OOS_DEFAULT
Index: clang/include/clang/Basic/TokenKinds.def
===================================================================
--- clang/include/clang/Basic/TokenKinds.def
+++ clang/include/clang/Basic/TokenKinds.def
@@ -85,6 +85,9 @@
 #ifndef PRAGMA_ANNOTATION
 #define PRAGMA_ANNOTATION(X) ANNOTATION(X)
 #endif
+#ifndef INTERESTING_IDENTIFIER
+#define INTERESTING_IDENTIFIER(X)
+#endif
 
 //===----------------------------------------------------------------------===//
 // Preprocessor keywords.
@@ -794,6 +797,13 @@
 OBJC_AT_KEYWORD(import)
 OBJC_AT_KEYWORD(available)
 
+//===----------------------------------------------------------------------===//
+// Interesting idenitifiers.
+//===----------------------------------------------------------------------===//
+INTERESTING_IDENTIFIER(not_interesting)
+INTERESTING_IDENTIFIER(float_t)
+INTERESTING_IDENTIFIER(double_t)
+
 // TODO: What to do about context-sensitive keywords like:
 //       bycopy/byref/in/inout/oneway/out?
 
@@ -974,3 +984,4 @@
 #undef TOK
 #undef C99_KEYWORD
 #undef C2X_KEYWORD
+#undef INTERESTING_IDENTIFIER
Index: clang/include/clang/Basic/IdentifierTable.h
===================================================================
--- clang/include/clang/Basic/IdentifierTable.h
+++ clang/include/clang/Basic/IdentifierTable.h
@@ -76,6 +76,21 @@
 
 static constexpr int ObjCOrBuiltinIDBits = 16;
 
+/// The "layout" of ObjCOrBuiltinID is:
+///  - The first value (0) represents "not a special identifier".
+///  - The next (NUM_OBJC_KEYWORDS - 1) values represent ObjCKeywordKinds (not
+///    including objc_not_keyword).
+///  - The next (NUM_INTERESTING_IDENTIFIERS - 1) values represent
+///    InterestingIdentifierKinds (not including not_interesting).
+///  - The rest of the values represent builtin IDs (not including NotBuiltin).
+static constexpr int FirstObjCKeywordID = 1;
+static constexpr int LastObjCKeywordID =
+    FirstObjCKeywordID + tok::NUM_OBJC_KEYWORDS - 2;
+static constexpr int FirstInterestingIdentifierID = LastObjCKeywordID + 1;
+static constexpr int LastInterestingIdentifierID =
+    FirstInterestingIdentifierID + tok::NUM_INTERESTING_IDENTIFIERS - 2;
+static constexpr int FirstBuiltinID = LastInterestingIdentifierID + 1;
+
 /// One of these records is kept for each identifier that
 /// is lexed.  This contains information about whether the token was \#define'd,
 /// is a language keyword, or if it is a front-end token of some sort (e.g. a
@@ -290,7 +305,9 @@
   ///
   /// For example, 'class' will return tok::objc_class if ObjC is enabled.
   tok::ObjCKeywordKind getObjCKeywordID() const {
-    if (ObjCOrBuiltinID < tok::NUM_OBJC_KEYWORDS)
+    static_assert(FirstObjCKeywordID == 1,
+                  "hard-coding this assumption to simplify code");
+    if (ObjCOrBuiltinID <= LastObjCKeywordID)
       return tok::ObjCKeywordKind(ObjCOrBuiltinID);
     else
       return tok::objc_not_keyword;
@@ -301,15 +318,29 @@
   ///
   /// 0 is not-built-in. 1+ are specific builtin functions.
   unsigned getBuiltinID() const {
-    if (ObjCOrBuiltinID >= tok::NUM_OBJC_KEYWORDS)
-      return ObjCOrBuiltinID - tok::NUM_OBJC_KEYWORDS;
+    if (ObjCOrBuiltinID >= FirstBuiltinID)
+      return 1 + (ObjCOrBuiltinID - FirstBuiltinID);
     else
       return 0;
   }
   void setBuiltinID(unsigned ID) {
-    ObjCOrBuiltinID = ID + tok::NUM_OBJC_KEYWORDS;
-    assert(ObjCOrBuiltinID - unsigned(tok::NUM_OBJC_KEYWORDS) == ID
-           && "ID too large for field!");
+    ObjCOrBuiltinID = FirstBuiltinID + (ID - 1);
+    assert(getBuiltinID() == ID && "ID too large for field!");
+  }
+  void clearBuiltinID() { ObjCOrBuiltinID = 0; }
+
+  tok::InterestingIdentifierKind getInterestingIdentifierID() const {
+    if (ObjCOrBuiltinID >= FirstInterestingIdentifierID &&
+        ObjCOrBuiltinID <= LastInterestingIdentifierID)
+      return tok::InterestingIdentifierKind(
+          1 + (ObjCOrBuiltinID - FirstInterestingIdentifierID));
+    else
+      return tok::not_interesting;
+  }
+  void setInterestingIdentifierID(unsigned ID) {
+    assert(ID != FirstBuiltinID);
+    ObjCOrBuiltinID = FirstInterestingIdentifierID + (ID - 1);
+    assert(getInterestingIdentifierID() == ID && "ID too large for field!");
   }
 
   unsigned getObjCOrBuiltinID() const { return ObjCOrBuiltinID; }
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11558,6 +11558,10 @@
   "too %select{many|few}0 type arguments for class %1 (have %2, expected %3)">;
 }
 
+def err_type_available_only_in_default_eval_method : Error<
+  "cannot use type '%0' within '#pragma clang fp eval_method'; type is set "
+  "according to the default eval method for the translation unit">;
+
 def err_objc_type_arg_not_id_compatible : Error<
   "type argument %0 is neither an Objective-C object nor a block type">;
 
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -4193,3 +4193,10 @@
   let Subjects = SubjectList<[Record]>;
   let Documentation = [ReadOnlyPlacementDocs];
 }
+
+
+def AvailableOnlyInDefaultEvalMethod : InheritableAttr {
+  let Spellings = [Clang<"available_only_in_default_eval_method">];
+  let Subjects = SubjectList<[TypedefName], ErrorDiag>;
+  let Documentation = [Undocumented];
+}
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -4594,6 +4594,13 @@
     a = b[i] * c[i] + e;
   }
 
+Note: ``math.h`` defines the typedefs ``float_t`` and ``double_t`` based on the active
+evaluation method at the point where the header is included, not where the
+typedefs are used.  Because of this, it is unwise to combine these typedefs with
+``#pragma clang fp eval_method``.  To catch obvious bugs, Clang will emit an
+error for any references to these typedefs within the scope of this pragma;
+however, this is not a fool-proof protection, and programmers must take care.
+
 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