From 4b48854949f8bf9afb871c293a9022331a0b77c7 Mon Sep 17 00:00:00 2001
From: Abseil Team <absl-team@google.com>
Date: Wed, 16 Nov 2022 11:05:21 -0800
Subject: Update Condition to allocate 24 bytes for MSVC platform pointers to
 methods.

PiperOrigin-RevId: 488986942
Change-Id: I2babb7ea30d60c544f55ca9ed02d9aed23051a12
---
 absl/synchronization/mutex_method_pointer_test.cc | 138 ++++++++++++++++++++++
 1 file changed, 138 insertions(+)
 create mode 100644 absl/synchronization/mutex_method_pointer_test.cc

(limited to 'absl/synchronization/mutex_method_pointer_test.cc')

diff --git a/absl/synchronization/mutex_method_pointer_test.cc b/absl/synchronization/mutex_method_pointer_test.cc
new file mode 100644
index 00000000..1ec801a0
--- /dev/null
+++ b/absl/synchronization/mutex_method_pointer_test.cc
@@ -0,0 +1,138 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/synchronization/mutex.h"
+
+#include <cstdlib>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+
+namespace {
+
+class IncompleteClass;
+
+#ifdef _MSC_VER
+// These tests verify expectations about sizes of MSVC pointers to methods.
+// Pointers to methods are distinguished by whether their class hierachies
+// contain single inheritance, multiple inheritance, or virtual inheritence.
+
+// Declare classes of the various MSVC inheritance types.
+class __single_inheritance SingleInheritance{};
+class __multiple_inheritance MultipleInheritance;
+class __virtual_inheritance VirtualInheritance;
+
+TEST(MutexMethodPointerTest, MicrosoftMethodPointerSize) {
+  void (SingleInheritance::*single_inheritance_method_pointer)();
+  void (MultipleInheritance::*multiple_inheritance_method_pointer)();
+  void (VirtualInheritance::*virtual_inheritance_method_pointer)();
+
+#if defined(_M_IX86) || defined(_M_ARM)
+  static_assert(sizeof(single_inheritance_method_pointer) == 4,
+                "Unexpected sizeof(single_inheritance_method_pointer).");
+  static_assert(sizeof(multiple_inheritance_method_pointer) == 8,
+                "Unexpected sizeof(multiple_inheritance_method_pointer).");
+  static_assert(sizeof(virtual_inheritance_method_pointer) == 12,
+                "Unexpected sizeof(virtual_inheritance_method_pointer).");
+#elif defined(_M_X64) || defined(__aarch64__)
+  static_assert(sizeof(single_inheritance_method_pointer) == 8,
+                "Unexpected sizeof(single_inheritance_method_pointer).");
+  static_assert(sizeof(multiple_inheritance_method_pointer) == 16,
+                "Unexpected sizeof(multiple_inheritance_method_pointer).");
+  static_assert(sizeof(virtual_inheritance_method_pointer) == 16,
+                "Unexpected sizeof(virtual_inheritance_method_pointer).");
+#endif
+  void (IncompleteClass::*incomplete_class_method_pointer)();
+  static_assert(sizeof(incomplete_class_method_pointer) >=
+                    sizeof(virtual_inheritance_method_pointer),
+                "Failed invariant: sizeof(incomplete_class_method_pointer) >= "
+                "sizeof(virtual_inheritance_method_pointer)!");
+}
+
+class Callback {
+  bool x = true;
+
+ public:
+  Callback() {}
+  bool method() {
+    x = !x;
+    return x;
+  }
+};
+
+class M2 {
+  bool x = true;
+
+ public:
+  M2() {}
+  bool method2() {
+    x = !x;
+    return x;
+  }
+};
+
+class MultipleInheritance : public Callback, public M2 {};
+
+TEST(MutexMethodPointerTest, ConditionWithMultipleInheritanceMethod) {
+  // This test ensures that Condition can deal with method pointers from classes
+  // with multiple inheritance.
+  MultipleInheritance object = MultipleInheritance();
+  absl::Condition condition(&object, &MultipleInheritance::method);
+  EXPECT_FALSE(condition.Eval());
+  EXPECT_TRUE(condition.Eval());
+}
+
+class __virtual_inheritance VirtualInheritance : virtual public Callback {
+  bool x = false;
+
+ public:
+  VirtualInheritance() {}
+  bool method() {
+    x = !x;
+    return x;
+  }
+};
+
+TEST(MutexMethodPointerTest, ConditionWithVirtualInheritanceMethod) {
+  // This test ensures that Condition can deal with method pointers from classes
+  // with virtual inheritance.
+  VirtualInheritance object = VirtualInheritance();
+  absl::Condition condition(&object, &VirtualInheritance::method);
+  EXPECT_TRUE(condition.Eval());
+  EXPECT_FALSE(condition.Eval());
+}
+#endif  // #ifdef _MSC_VER
+
+TEST(MutexMethodPointerTest, ConditionWithIncompleteClassMethod) {
+  using IncompleteClassMethodPointer = void (IncompleteClass::*)();
+
+  union CallbackSlot {
+    void (*anonymous_function_pointer)();
+    IncompleteClassMethodPointer incomplete_class_method_pointer;
+  };
+
+  static_assert(sizeof(CallbackSlot) >= sizeof(IncompleteClassMethodPointer),
+                "The callback slot is not big enough for method pointers.");
+  static_assert(
+      sizeof(CallbackSlot) == sizeof(IncompleteClassMethodPointer),
+      "The callback slot is not big enough for anonymous function pointers.");
+
+#if defined(_MSC_VER)
+  static_assert(sizeof(IncompleteClassMethodPointer) <= 24,
+                "The pointer to a method of an incomplete class is too big.");
+#endif
+}
+
+}  // namespace
-- 
cgit v1.2.3