Support constant-evaluation of __builtin_nans* as well as the correct constant
evaluation of __builtin_nan*.  Most of the work to make this work is in LLVM.

Fixes <rdar://problem/7696712> and part of PR 5255.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97383 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 1a44cd0..e036692 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1560,6 +1560,31 @@
   return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
 }
 
+static bool TryEvaluateBuiltinNaN(ASTContext &Context,
+                                  QualType ResultTy,
+                                  const Expr *Arg,
+                                  bool SNaN,
+                                  llvm::APFloat &Result) {
+  const StringLiteral *S = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts());
+  if (!S) return false;
+
+  const llvm::fltSemantics &Sem = Context.getFloatTypeSemantics(ResultTy);
+
+  llvm::APInt fill;
+
+  // Treat empty strings as if they were zero.
+  if (S->getString().empty())
+    fill = llvm::APInt(32, 0);
+  else if (S->getString().getAsInteger(0, fill))
+    return false;
+
+  if (SNaN)
+    Result = llvm::APFloat::getSNaN(Sem, false, &fill);
+  else
+    Result = llvm::APFloat::getQNaN(Sem, false, &fill);
+  return true;
+}
+
 bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
   switch (E->isBuiltinCall(Info.Ctx)) {
   default: return false;
@@ -1575,24 +1600,19 @@
     return true;
   }
 
+  case Builtin::BI__builtin_nans:
+  case Builtin::BI__builtin_nansf:
+  case Builtin::BI__builtin_nansl:
+    return TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
+                                 true, Result);
+
   case Builtin::BI__builtin_nan:
   case Builtin::BI__builtin_nanf:
   case Builtin::BI__builtin_nanl:
     // If this is __builtin_nan() turn this into a nan, otherwise we
     // can't constant fold it.
-    if (const StringLiteral *S =
-        dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenCasts())) {
-      if (!S->isWide()) {
-        const llvm::fltSemantics &Sem =
-          Info.Ctx.getFloatTypeSemantics(E->getType());
-        unsigned Type = 0;
-        if (!S->getString().empty() && S->getString().getAsInteger(0, Type))
-          return false;
-        Result = llvm::APFloat::getNaN(Sem, false, Type);
-        return true;
-      }
-    }
-    return false;
+    return TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
+                                 false, Result);
 
   case Builtin::BI__builtin_fabs:
   case Builtin::BI__builtin_fabsf: