1+ #include < cstdint>
2+
3+ std::int16_t s16;
4+ std::uint16_t u16 ;
5+ std::int32_t s32;
6+ std::uint32_t u32 ;
7+ std::int64_t s64;
8+ std::uint64_t u64 ;
9+
10+ struct MemberFunctionPointerTest {
11+ void mf15 (std::int32_t l1) {}
12+ void mf15 (std::uint32_t l1) {}
13+ void mf16 (std::int32_t l1) {}
14+ };
15+
16+ void test_pointer_to_member_functions () {
17+ MemberFunctionPointerTest l1;
18+ MemberFunctionPointerTest *l6 = &l1;
19+
20+ // mf15 is overload independent when used as a member function pointer
21+ void (MemberFunctionPointerTest::*l2)(std::int32_t ) =
22+ &MemberFunctionPointerTest::mf15;
23+ (l1.*l2)(s16); // COMPLIANT - widening of id-expression
24+ (l1.*l2)(s32); // COMPLIANT - type match
25+ (l1.*l2)(s64); // NON_COMPLIANT - narrowing
26+ (l1.*l2)(u16 ); // NON_COMPLIANT - wrong sign
27+ (l1.*l2)(u32 ); // NON_COMPLIANT - wrong sign
28+ (l1.*l2)(u64 ); // NON_COMPLIANT - wrong sign and narrowing
29+
30+ (l6->*l2)(s16); // COMPLIANT - is widening of id-expression
31+ (l6->*l2)(s32); // COMPLIANT - type match
32+ (l6->*l2)(s64); // NON_COMPLIANT - narrowing
33+ (l6->*l2)(u16 ); // NON_COMPLIANT - wrong sign
34+ (l6->*l2)(u32 ); // NON_COMPLIANT - wrong sign
35+ (l6->*l2)(u64 ); // NON_COMPLIANT - wrong sign and narrowing
36+
37+ // mf16 is overload independent when used as a member function pointer
38+ void (MemberFunctionPointerTest::*l3)(std::int32_t ) =
39+ &MemberFunctionPointerTest::mf16;
40+ (l1.*l3)(s16); // COMPLIANT - widening of id-expression
41+ (l1.*l3)(s32); // COMPLIANT - type match
42+ (l1.*l3)(s64); // NON_COMPLIANT - narrowing
43+ (l1.*l3)(u16 ); // NON_COMPLIANT - wrong sign
44+ (l1.*l3)(u32 ); // NON_COMPLIANT - wrong sign
45+ (l1.*l3)(u64 ); // NON_COMPLIANT - wrong sign and narrowing
46+
47+ (l6->*l3)(s16); // COMPLIANT - widening of id-expression
48+ (l6->*l3)(s32); // COMPLIANT - type match
49+ (l6->*l3)(s64); // NON_COMPLIANT - narrowing
50+ (l6->*l3)(u16 ); // NON_COMPLIANT - wrong sign
51+ (l6->*l3)(u32 ); // NON_COMPLIANT - wrong sign
52+ (l6->*l3)(u64 ); // NON_COMPLIANT - wrong sign and narrowing
53+
54+ // Direct calls for comparison
55+
56+ // mf15 is not overload-independent, so it should only be compliant
57+ // where an exact type of an overload is used
58+ l1.mf15 (s16); // NON_COMPLIANT - widening not allowed
59+ l1.mf15 (s32); // COMPLIANT - exact type match
60+ l1.mf15 (u16 ); // NON_COMPLIANT - widening not allowed
61+ l1.mf15 (u32 ); // COMPLIANT - exact type match
62+
63+ // A qualified call to mf16 is overload-independent
64+ l1.mf16 (s16); // COMPLIANT - widening of id-expression
65+ l1.mf16 (s32); // COMPLIANT - exact type match
66+ l1.mf16 (u16 ); // NON_COMPLIANT
67+ l1.mf16 (u32 ); // NON_COMPLIANT
68+ }
69+
70+ // Test static member function pointers - should be overload-independent
71+ struct StaticMemberFunctionPointerTest {
72+ static void mf19 (std::int32_t l1) {}
73+ static void mf19 (std::uint32_t l1) {}
74+ static void mf20 (std::int32_t l1) {}
75+ };
76+
77+ void test_static_member_function_pointers () {
78+ // Static member function pointers - overload-independent
79+ void (*l1)(std::int32_t ) = &StaticMemberFunctionPointerTest::mf19;
80+ l1 (s16); // COMPLIANT - widening of id-expression
81+ l1 (s32); // COMPLIANT - type match
82+ l1 (s64); // NON_COMPLIANT - narrowing
83+ l1 (u16 ); // NON_COMPLIANT - wrong sign
84+ l1 (u32 ); // NON_COMPLIANT - wrong sign
85+ l1 (u64 ); // NON_COMPLIANT - wrong sign and narrowing
86+
87+ void (*l2)(std::int32_t ) = &StaticMemberFunctionPointerTest::mf20;
88+ l2 (s16); // COMPLIANT - widening of id-expression
89+ l2 (s32); // COMPLIANT - type match
90+ l2 (s64); // NON_COMPLIANT - narrowing
91+ l2 (u16 ); // NON_COMPLIANT - wrong sign
92+ l2 (u32 ); // NON_COMPLIANT - wrong sign
93+ l2 (u64 ); // NON_COMPLIANT - wrong sign and narrowing
94+
95+ // Direct calls for comparison - not overload-independent
96+ StaticMemberFunctionPointerTest::mf19 (
97+ s16); // NON_COMPLIANT - widening not allowed
98+ StaticMemberFunctionPointerTest::mf19 (s32); // COMPLIANT - exact type match
99+ StaticMemberFunctionPointerTest::mf19 (
100+ u16 ); // NON_COMPLIANT - widening not allowed
101+ StaticMemberFunctionPointerTest::mf19 (u32 ); // COMPLIANT - exact type match
102+
103+ StaticMemberFunctionPointerTest::mf20 (
104+ s16); // COMPLIANT - widening of id-expression
105+ StaticMemberFunctionPointerTest::mf20 (s32); // COMPLIANT - exact type match
106+ StaticMemberFunctionPointerTest::mf20 (u16 ); // NON_COMPLIANT
107+ StaticMemberFunctionPointerTest::mf20 (u32 ); // NON_COMPLIANT
108+ }
109+
110+ // Test member data pointers - not function calls, but test assignment to them
111+ struct MemberDataPointerTest {
112+ std::int64_t m1;
113+ std::int64_t m2 : 10 ;
114+ };
115+
116+ void test_member_data_pointers () {
117+ MemberDataPointerTest l1;
118+
119+ // Member data pointer assignments - follow normal assignment rules
120+ std::int64_t MemberDataPointerTest::*l2 = &MemberDataPointerTest::m1;
121+
122+ l1.*l2 = s16; // COMPLIANT - widening conversion allowed
123+ l1.*l2 = s32; // COMPLIANT - widening conversion allowed
124+ l1.*l2 = s64; // COMPLIANT
125+ l1.*l2 = u16 ; // NON_COMPLIANT - signedness violation
126+ l1.*l2 = u32 ; // NON_COMPLIANT - different signedness/size
127+ l1.*l2 = u64 ; // NON_COMPLIANT - different signedness
128+ }
0 commit comments