Use C++11 alignment primitives

Removes the compiler-specific base #define ALIGNOF and replace uses with alignof.

Replaces some uses of ALIGNAS with alignas. These are not all replaced,
and a note is added to the definition about the problems with alignas.
This came from https://codereview.chromium.org/2670873002/

Remove base::AlignedMemory and replace with alignas(type) char[size].

std::aligned_storage has some limitations. The style guide is updated to note these and mark it disallowed. It is also updated for alignas and alignof.

CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_trusty_blink_rel

Review-Url: https://codereview.chromium.org/2932053002
Cr-Commit-Position: refs/heads/master@{#479169}
diff --git a/base/memory/aligned_memory.h b/base/memory/aligned_memory.h
index d8290115..e302f45 100644
--- a/base/memory/aligned_memory.h
+++ b/base/memory/aligned_memory.h
@@ -2,24 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// AlignedMemory is a POD type that gives you a portable way to specify static
-// or local stack data of a given alignment and size. For example, if you need
-// static storage for a class, but you want manual control over when the object
-// is constructed and destructed (you don't want static initialization and
-// destruction), use AlignedMemory:
-//
-//   static AlignedMemory<sizeof(MyClass), ALIGNOF(MyClass)> my_class;
-//
-//   // ... at runtime:
-//   new(my_class.void_data()) MyClass();
-//
-//   // ... use it:
-//   MyClass* mc = my_class.data_as<MyClass>();
-//
-//   // ... later, to destruct my_class:
-//   my_class.data_as<MyClass>()->MyClass::~MyClass();
-//
-// Alternatively, a runtime sized aligned allocation can be created:
+#include <type_traits>
+
+// A runtime sized aligned allocation can be created:
 //
 //   float* my_array = static_cast<float*>(AlignedAlloc(size, alignment));
 //
@@ -48,52 +33,7 @@
 
 namespace base {
 
-// AlignedMemory is specialized for all supported alignments.
-// Make sure we get a compiler error if someone uses an unsupported alignment.
-template <size_t Size, size_t ByteAlignment>
-struct AlignedMemory {};
-
-#define BASE_DECL_ALIGNED_MEMORY(byte_alignment)                              \
-  template <size_t Size>                                                      \
-  class AlignedMemory<Size, byte_alignment> {                                 \
-   public:                                                                    \
-    ALIGNAS(byte_alignment) uint8_t data_[Size];                              \
-    void* void_data() { return static_cast<void*>(data_); }                   \
-    const void* void_data() const { return static_cast<const void*>(data_); } \
-    template <typename Type>                                                  \
-    Type* data_as() {                                                         \
-      return static_cast<Type*>(void_data());                                 \
-    }                                                                         \
-    template <typename Type>                                                  \
-    const Type* data_as() const {                                             \
-      return static_cast<const Type*>(void_data());                           \
-    }                                                                         \
-                                                                              \
-   private:                                                                   \
-    void* operator new(size_t);                                               \
-    void operator delete(void*);                                              \
-  }
-
-// Specialization for all alignments is required because MSVC (as of VS 2008)
-// does not understand ALIGNAS(ALIGNOF(Type)) or ALIGNAS(template_param).
-// Greater than 4096 alignment is not supported by some compilers, so 4096 is
-// the maximum specified here.
-BASE_DECL_ALIGNED_MEMORY(1);
-BASE_DECL_ALIGNED_MEMORY(2);
-BASE_DECL_ALIGNED_MEMORY(4);
-BASE_DECL_ALIGNED_MEMORY(8);
-BASE_DECL_ALIGNED_MEMORY(16);
-BASE_DECL_ALIGNED_MEMORY(32);
-BASE_DECL_ALIGNED_MEMORY(64);
-BASE_DECL_ALIGNED_MEMORY(128);
-BASE_DECL_ALIGNED_MEMORY(256);
-BASE_DECL_ALIGNED_MEMORY(512);
-BASE_DECL_ALIGNED_MEMORY(1024);
-BASE_DECL_ALIGNED_MEMORY(2048);
-BASE_DECL_ALIGNED_MEMORY(4096);
-
-#undef BASE_DECL_ALIGNED_MEMORY
-
+// This can be replaced with std::aligned_malloc when we have C++17.
 BASE_EXPORT void* AlignedAlloc(size_t size, size_t alignment);
 
 inline void AlignedFree(void* ptr) {
diff --git a/base/memory/aligned_memory_unittest.cc b/base/memory/aligned_memory_unittest.cc
index 892c50e..e354f38 100644
--- a/base/memory/aligned_memory_unittest.cc
+++ b/base/memory/aligned_memory_unittest.cc
@@ -12,84 +12,35 @@
 #define EXPECT_ALIGNED(ptr, align) \
     EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
 
-namespace {
-
-using base::AlignedMemory;
-
-TEST(AlignedMemoryTest, StaticAlignment) {
-  static AlignedMemory<8, 8> raw8;
-  static AlignedMemory<8, 16> raw16;
-  static AlignedMemory<8, 256> raw256;
-  static AlignedMemory<8, 4096> raw4096;
-
-  EXPECT_EQ(8u, ALIGNOF(raw8));
-  EXPECT_EQ(16u, ALIGNOF(raw16));
-  EXPECT_EQ(256u, ALIGNOF(raw256));
-  EXPECT_EQ(4096u, ALIGNOF(raw4096));
-
-  EXPECT_ALIGNED(raw8.void_data(), 8);
-  EXPECT_ALIGNED(raw16.void_data(), 16);
-  EXPECT_ALIGNED(raw256.void_data(), 256);
-  EXPECT_ALIGNED(raw4096.void_data(), 4096);
-}
-
-TEST(AlignedMemoryTest, StackAlignment) {
-  AlignedMemory<8, 8> raw8;
-  AlignedMemory<8, 16> raw16;
-  AlignedMemory<8, 128> raw128;
-
-  EXPECT_EQ(8u, ALIGNOF(raw8));
-  EXPECT_EQ(16u, ALIGNOF(raw16));
-  EXPECT_EQ(128u, ALIGNOF(raw128));
-
-  EXPECT_ALIGNED(raw8.void_data(), 8);
-  EXPECT_ALIGNED(raw16.void_data(), 16);
-  EXPECT_ALIGNED(raw128.void_data(), 128);
-
-  // NaCl x86-64 compiler emits non-validating instructions for >128
-  // bytes alignment.
-  // http://www.chromium.org/nativeclient/design-documents/nacl-sfi-model-on-x86-64-systems
-  // TODO(hamaji): Ideally, NaCl compiler for x86-64 should workaround
-  // this limitation and this #if should be removed.
-  // https://code.google.com/p/nativeclient/issues/detail?id=3463
-#if !(defined(OS_NACL) && defined(ARCH_CPU_X86_64))
-  AlignedMemory<8, 256> raw256;
-  EXPECT_EQ(256u, ALIGNOF(raw256));
-  EXPECT_ALIGNED(raw256.void_data(), 256);
-
-  AlignedMemory<8, 4096> raw4096;
-  EXPECT_EQ(4096u, ALIGNOF(raw4096));
-  EXPECT_ALIGNED(raw4096.void_data(), 4096);
-#endif  // !(defined(OS_NACL) && defined(ARCH_CPU_X86_64))
-}
+namespace base {
 
 TEST(AlignedMemoryTest, DynamicAllocation) {
-  void* p = base::AlignedAlloc(8, 8);
+  void* p = AlignedAlloc(8, 8);
   EXPECT_TRUE(p);
   EXPECT_ALIGNED(p, 8);
-  base::AlignedFree(p);
+  AlignedFree(p);
 
-  p = base::AlignedAlloc(8, 16);
+  p = AlignedAlloc(8, 16);
   EXPECT_TRUE(p);
   EXPECT_ALIGNED(p, 16);
-  base::AlignedFree(p);
+  AlignedFree(p);
 
-  p = base::AlignedAlloc(8, 256);
+  p = AlignedAlloc(8, 256);
   EXPECT_TRUE(p);
   EXPECT_ALIGNED(p, 256);
-  base::AlignedFree(p);
+  AlignedFree(p);
 
-  p = base::AlignedAlloc(8, 4096);
+  p = AlignedAlloc(8, 4096);
   EXPECT_TRUE(p);
   EXPECT_ALIGNED(p, 4096);
-  base::AlignedFree(p);
+  AlignedFree(p);
 }
 
 TEST(AlignedMemoryTest, ScopedDynamicAllocation) {
-  std::unique_ptr<float, base::AlignedFreeDeleter> p(
-      static_cast<float*>(base::AlignedAlloc(8, 8)));
+  std::unique_ptr<float, AlignedFreeDeleter> p(
+      static_cast<float*>(AlignedAlloc(8, 8)));
   EXPECT_TRUE(p.get());
   EXPECT_ALIGNED(p.get(), 8);
 }
 
-}  // namespace
+}  // namespace base
diff --git a/base/memory/manual_constructor.h b/base/memory/manual_constructor.h
index f401f62d..e968d04 100644
--- a/base/memory/manual_constructor.h
+++ b/base/memory/manual_constructor.h
@@ -34,17 +34,15 @@
   // Support users creating arrays of ManualConstructor<>s.  This ensures that
   // the array itself has the correct alignment.
   static void* operator new[](size_t size) {
-    return AlignedAlloc(size, ALIGNOF(Type));
+    return AlignedAlloc(size, alignof(Type));
   }
   static void operator delete[](void* mem) {
     AlignedFree(mem);
   }
 
-  inline Type* get() {
-    return space_.template data_as<Type>();
-  }
+  inline Type* get() { return reinterpret_cast<Type*>(space_); }
   inline const Type* get() const  {
-    return space_.template data_as<Type>();
+    return reinterpret_cast<const Type*>(space_);
   }
 
   inline Type* operator->() { return get(); }
@@ -55,7 +53,7 @@
 
   template <typename... Ts>
   inline void Init(Ts&&... params) {
-    new(space_.void_data()) Type(std::forward<Ts>(params)...);
+    new (space_) Type(std::forward<Ts>(params)...);
   }
 
   inline void InitFromMove(ManualConstructor<Type>&& o) {
@@ -67,7 +65,7 @@
   }
 
  private:
-  AlignedMemory<sizeof(Type), ALIGNOF(Type)> space_;
+  alignas(Type) char space_[sizeof(Type)];
 };
 
 }  // namespace base
diff --git a/base/memory/singleton.h b/base/memory/singleton.h
index 5c58d5fe..d604910 100644
--- a/base/memory/singleton.h
+++ b/base/memory/singleton.h
@@ -24,7 +24,6 @@
 #include "base/base_export.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/aligned_memory.h"
 #include "base/threading/thread_restrictions.h"
 
 namespace base {
@@ -115,7 +114,7 @@
     if (subtle::NoBarrier_AtomicExchange(&dead_, 1))
       return NULL;
 
-    return new(buffer_.void_data()) Type();
+    return new (buffer_) Type();
   }
 
   static void Delete(Type* p) {
@@ -130,14 +129,13 @@
   static void Resurrect() { subtle::NoBarrier_Store(&dead_, 0); }
 
  private:
-  static AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
+  alignas(Type) static char buffer_[sizeof(Type)];
   // Signal the object was already deleted, so it is not revived.
   static subtle::Atomic32 dead_;
 };
 
 template <typename Type>
-AlignedMemory<sizeof(Type), ALIGNOF(Type)>
-    StaticMemorySingletonTraits<Type>::buffer_;
+alignas(Type) char StaticMemorySingletonTraits<Type>::buffer_[sizeof(Type)];
 template <typename Type>
 subtle::Atomic32 StaticMemorySingletonTraits<Type>::dead_ = 0;
 
diff --git a/base/memory/singleton_unittest.cc b/base/memory/singleton_unittest.cc
index a15145c..e129215 100644
--- a/base/memory/singleton_unittest.cc
+++ b/base/memory/singleton_unittest.cc
@@ -16,6 +16,14 @@
 
 typedef void (*CallbackFunc)();
 
+template <size_t alignment>
+class AlignedData {
+ public:
+  AlignedData() {}
+  ~AlignedData() {}
+  alignas(alignment) char data_[alignment];
+};
+
 class IntSingleton {
  public:
   static IntSingleton* GetInstance() {
@@ -269,19 +277,17 @@
     EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
 
 TEST_F(SingletonTest, Alignment) {
-  using base::AlignedMemory;
-
   // Create some static singletons with increasing sizes and alignment
   // requirements. By ordering this way, the linker will need to do some work to
   // ensure proper alignment of the static data.
   AlignedTestSingleton<int32_t>* align4 =
       AlignedTestSingleton<int32_t>::GetInstance();
-  AlignedTestSingleton<AlignedMemory<32, 32> >* align32 =
-      AlignedTestSingleton<AlignedMemory<32, 32> >::GetInstance();
-  AlignedTestSingleton<AlignedMemory<128, 128> >* align128 =
-      AlignedTestSingleton<AlignedMemory<128, 128> >::GetInstance();
-  AlignedTestSingleton<AlignedMemory<4096, 4096> >* align4096 =
-      AlignedTestSingleton<AlignedMemory<4096, 4096> >::GetInstance();
+  AlignedTestSingleton<AlignedData<32>>* align32 =
+      AlignedTestSingleton<AlignedData<32>>::GetInstance();
+  AlignedTestSingleton<AlignedData<128>>* align128 =
+      AlignedTestSingleton<AlignedData<128>>::GetInstance();
+  AlignedTestSingleton<AlignedData<4096>>* align4096 =
+      AlignedTestSingleton<AlignedData<4096>>::GetInstance();
 
   EXPECT_ALIGNED(align4, 4);
   EXPECT_ALIGNED(align32, 32);