OSDN Git Service

[ADT] Add a workaround for GCC miscompiling the trivially copyable Optional
authorBenjamin Kramer <benny.kra@googlemail.com>
Thu, 18 Jan 2018 15:47:59 +0000 (15:47 +0000)
committerBenjamin Kramer <benny.kra@googlemail.com>
Thu, 18 Jan 2018 15:47:59 +0000 (15:47 +0000)
I've seen random crashes with GCC 4.8, GCC 6.3 and GCC 7.3, triggered by
my Optional change. All of them affect a different set of targets. This
change fixes the instance of the problem I'm seeing on my local machine,
let's hope it's good enough for the other instances too.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@322859 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ADT/Optional.h

index 54dc574..2c2d2c6 100644 (file)
@@ -23,6 +23,7 @@
 #include <algorithm>
 #include <cassert>
 #include <new>
+#include <cstring>
 #include <utility>
 
 namespace llvm {
@@ -117,10 +118,16 @@ template <typename T> struct OptionalStorage<T, true> {
 
   OptionalStorage() = default;
 
-  OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); }
+  OptionalStorage(const T &y) : hasVal(true) {
+    // We use memmove here because we know that T is trivially copyable and GCC
+    // up to 7 miscompiles placement new.
+    std::memmove(storage.buffer, &y, sizeof(y));
+  }
   OptionalStorage &operator=(const T &y) {
-    new (storage.buffer) T(y);
     hasVal = true;
+    // We use memmove here because we know that T is trivially copyable and GCC
+    // up to 7 miscompiles placement new.
+    std::memmove(storage.buffer, &y, sizeof(y));
     return *this;
   }