[PATCH] D25018: Always print doubles with the C locale

Nicolai Hähnle via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 28 06:12:12 PDT 2016


nhaehnle created this revision.
nhaehnle added reviewers: chandlerc, chapuni.
nhaehnle added a subscriber: llvm-commits.

This fixes a problem where AsmWriter asserts or produces invalid textual IR
when the locale is set such that ',' is used for the decimal point.

The reliance on C++ streams is perhaps annoying, but I see no other way
short of importing a whole double-to-string routine. Having the user change
the locale certainly isn't an option because this occurs in a context where
LLVM is embedded in a larger application.

https://reviews.llvm.org/D25018

Files:
  lib/Support/raw_ostream.cpp

Index: lib/Support/raw_ostream.cpp
===================================================================
--- lib/Support/raw_ostream.cpp
+++ lib/Support/raw_ostream.cpp
@@ -28,6 +28,9 @@
 #include <cerrno>
 #include <cstdio>
 #include <iterator>
+#include <iomanip>
+#include <sstream>
+#include <string>
 #include <system_error>
 #include <sys/stat.h>
 
@@ -230,8 +233,6 @@
 
 raw_ostream &raw_ostream::operator<<(double N) {
 #ifdef _WIN32
-  // On MSVCRT and compatible, output of %e is incompatible to Posix
-  // by default. Number of exponent digits should be at least 2. "%+03d"
   // FIXME: Implement our formatter to here or Support/Format.h!
 #if defined(__MINGW32__)
   // FIXME: It should be generic to C++11.
@@ -244,29 +245,29 @@
   if (fpcl == _FPCLASS_NZ)
     return *this << "-0.000000e+00";
 #endif
-
-  char buf[16];
-  unsigned len;
-  len = format("%e", N).snprint(buf, sizeof(buf));
-  if (len <= sizeof(buf) - 2) {
-    if (len >= 5 && buf[len - 5] == 'e' && buf[len - 3] == '0') {
-      int cs = buf[len - 4];
-      if (cs == '+' || cs == '-') {
-        int c1 = buf[len - 2];
-        int c0 = buf[len - 1];
-        if (isdigit(static_cast<unsigned char>(c1)) &&
-            isdigit(static_cast<unsigned char>(c0))) {
-          // Trim leading '0': "...e+012" -> "...e+12\0"
-          buf[len - 3] = c1;
-          buf[len - 2] = c0;
-          buf[--len] = 0;
-        }
+#endif
+  std::ostringstream os;
+  os.imbue(std::locale("C"));
+  os << std::scientific << N;
+  std::string result = os.str();
+#ifdef _WIN32
+  // On MSVCRT and compatible, output of %e is incompatible to Posix
+  // by default. Number of exponent digits should be at least 2. "%+03d"
+  if (result.size() >= 5 && result[result.size() - 5]  == 'e' &&
+    result[result.size() - 3] == '0') {
+    int cs = result[result.size() - 4];
+    if (cs == '+' || cs == '-') {
+      int c1 = result[result.size() - 2];
+      int c0 = result[result.size() - 1];
+      if (isdigit(static_cast<unsigned char>(c1)) &&
+          isdigit(static_cast<unsigned char>(c0))) {
+        // Trim leading '0': "...e+012" -> "...e+12\0"
+        result.erase(result.end() - 3);
       }
     }
-    return this->operator<<(buf);
   }
 #endif
-  return this->operator<<(format("%e", N));
+  return this->operator<<(result);
 }
 
 void raw_ostream::flush_nonempty() {


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D25018.72814.patch
Type: text/x-patch
Size: 2354 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160928/bdd18de6/attachment.bin>


More information about the llvm-commits mailing list