zahiraam updated this revision to Diff 532734.
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,10 +320,11 @@
// 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,16 @@
Table.get(Name).setObjCKeywordID(ObjCID);
}
+static void AddInterestingIdentifier(StringRef Name,
+ tok::InterestingIdentifierKind BTID,
+ IdentifierTable &Table) {
+ // Don't add 'not_interesting' identifier.
+ if (BTID != tok::not_interesting) {
+ 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 +305,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,30 @@
///
/// 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!");
+ assert(ID != 0);
+ 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 != tok::not_interesting);
+ 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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits