1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/synchronization/mutex.h"
16
17 #include <cstdlib>
18 #include <string>
19
20 #include "gtest/gtest.h"
21 #include "absl/base/config.h"
22
23 namespace {
24
25 class IncompleteClass;
26
27 #ifdef _MSC_VER
28 // These tests verify expectations about sizes of MSVC pointers to methods.
29 // Pointers to methods are distinguished by whether their class hierarchies
30 // contain single inheritance, multiple inheritance, or virtual inheritance.
31
32 // Declare classes of the various MSVC inheritance types.
33 class __single_inheritance SingleInheritance{};
34 class __multiple_inheritance MultipleInheritance;
35 class __virtual_inheritance VirtualInheritance;
36
TEST(MutexMethodPointerTest,MicrosoftMethodPointerSize)37 TEST(MutexMethodPointerTest, MicrosoftMethodPointerSize) {
38 void (SingleInheritance::*single_inheritance_method_pointer)();
39 void (MultipleInheritance::*multiple_inheritance_method_pointer)();
40 void (VirtualInheritance::*virtual_inheritance_method_pointer)();
41
42 #if defined(_M_IX86) || defined(_M_ARM)
43 static_assert(sizeof(single_inheritance_method_pointer) == 4,
44 "Unexpected sizeof(single_inheritance_method_pointer).");
45 static_assert(sizeof(multiple_inheritance_method_pointer) == 8,
46 "Unexpected sizeof(multiple_inheritance_method_pointer).");
47 static_assert(sizeof(virtual_inheritance_method_pointer) == 12,
48 "Unexpected sizeof(virtual_inheritance_method_pointer).");
49 #elif defined(_M_X64) || defined(__aarch64__)
50 static_assert(sizeof(single_inheritance_method_pointer) == 8,
51 "Unexpected sizeof(single_inheritance_method_pointer).");
52 static_assert(sizeof(multiple_inheritance_method_pointer) == 16,
53 "Unexpected sizeof(multiple_inheritance_method_pointer).");
54 static_assert(sizeof(virtual_inheritance_method_pointer) == 16,
55 "Unexpected sizeof(virtual_inheritance_method_pointer).");
56 #endif
57 void (IncompleteClass::*incomplete_class_method_pointer)();
58 static_assert(sizeof(incomplete_class_method_pointer) >=
59 sizeof(virtual_inheritance_method_pointer),
60 "Failed invariant: sizeof(incomplete_class_method_pointer) >= "
61 "sizeof(virtual_inheritance_method_pointer)!");
62 }
63
64 class Callback {
65 bool x = true;
66
67 public:
Callback()68 Callback() {}
method()69 bool method() {
70 x = !x;
71 return x;
72 }
73 };
74
75 class M2 {
76 bool x = true;
77
78 public:
M2()79 M2() {}
method2()80 bool method2() {
81 x = !x;
82 return x;
83 }
84 };
85
86 class MultipleInheritance : public Callback, public M2 {};
87
TEST(MutexMethodPointerTest,ConditionWithMultipleInheritanceMethod)88 TEST(MutexMethodPointerTest, ConditionWithMultipleInheritanceMethod) {
89 // This test ensures that Condition can deal with method pointers from classes
90 // with multiple inheritance.
91 MultipleInheritance object = MultipleInheritance();
92 absl::Condition condition(&object, &MultipleInheritance::method);
93 EXPECT_FALSE(condition.Eval());
94 EXPECT_TRUE(condition.Eval());
95 }
96
97 class __virtual_inheritance VirtualInheritance : virtual public Callback {
98 bool x = false;
99
100 public:
VirtualInheritance()101 VirtualInheritance() {}
method()102 bool method() {
103 x = !x;
104 return x;
105 }
106 };
107
TEST(MutexMethodPointerTest,ConditionWithVirtualInheritanceMethod)108 TEST(MutexMethodPointerTest, ConditionWithVirtualInheritanceMethod) {
109 // This test ensures that Condition can deal with method pointers from classes
110 // with virtual inheritance.
111 VirtualInheritance object = VirtualInheritance();
112 absl::Condition condition(&object, &VirtualInheritance::method);
113 EXPECT_TRUE(condition.Eval());
114 EXPECT_FALSE(condition.Eval());
115 }
116 #endif // #ifdef _MSC_VER
117
TEST(MutexMethodPointerTest,ConditionWithIncompleteClassMethod)118 TEST(MutexMethodPointerTest, ConditionWithIncompleteClassMethod) {
119 using IncompleteClassMethodPointer = void (IncompleteClass::*)();
120
121 union CallbackSlot {
122 void (*anonymous_function_pointer)();
123 IncompleteClassMethodPointer incomplete_class_method_pointer;
124 };
125
126 static_assert(sizeof(CallbackSlot) >= sizeof(IncompleteClassMethodPointer),
127 "The callback slot is not big enough for method pointers.");
128 static_assert(
129 sizeof(CallbackSlot) == sizeof(IncompleteClassMethodPointer),
130 "The callback slot is not big enough for anonymous function pointers.");
131
132 #if defined(_MSC_VER)
133 static_assert(sizeof(IncompleteClassMethodPointer) <= 24,
134 "The pointer to a method of an incomplete class is too big.");
135 #endif
136 }
137
138 } // namespace
139