|
1 | | -// PERMUTE_ARGS: |
| 1 | +/* |
| 2 | +REQUIRED_ARGS: -betterC |
| 3 | +*/ |
| 4 | +// Fix: https://github.com/dlang/dmd/issues/20924 (invariant not called on extern(C++) classes) |
2 | 5 |
|
3 | | -extern(C) int printf(const char*, ...); |
4 | | - |
5 | | -class Foo : Object |
| 6 | +extern(C++) class C |
6 | 7 | { |
7 | | - void test() { } |
8 | | - |
9 | | - invariant() |
10 | | - { |
11 | | - printf("in invariant %p\n", this); |
12 | | - } |
| 8 | + invariant { assert(0); } |
| 9 | + void f() {} |
13 | 10 | } |
14 | 11 |
|
15 | | -int testinvariant() |
| 12 | +extern(D) class D |
16 | 13 | { |
17 | | - printf("hello\n"); |
18 | | - Foo f = new Foo(); |
19 | | - printf("f = %p\n", f); |
20 | | - printf("f.sizeof = x%zx\n", Foo.sizeof); |
21 | | - printf("f.classinfo = %p\n", f.classinfo); |
22 | | - printf("f.classinfo._invariant = %p\n", f.classinfo.base); |
23 | | - f.test(); |
24 | | - printf("world\n"); |
25 | | - return 0; |
| 14 | + invariant { assert(0); } |
| 15 | + void f() {} |
26 | 16 | } |
27 | 17 |
|
28 | | -/***************************************************/ |
29 | | -// https://issues.dlang.org/show_bug.cgi?id=6453 |
30 | | - |
31 | | -void test6453() |
| 18 | +// This function runs tests on extern(C++) class |
| 19 | +void testCppClass() |
32 | 20 | { |
33 | | - static class C |
34 | | - { |
35 | | - static uint called; |
36 | | - invariant() { called += 1; } |
37 | | - invariant() { called += 4; } |
38 | | - invariant() { called += 16; } |
39 | | - |
40 | | - void publicMember() { assert(called == 21); } |
41 | | - } |
42 | | - |
43 | | - static struct S |
44 | | - { |
45 | | - static uint called; |
46 | | - invariant() { called += 1; } |
47 | | - invariant() { called += 4; } |
48 | | - invariant() { called += 16; } |
49 | | - |
50 | | - void publicMember() { assert(called == 21); } |
51 | | - } |
52 | | - |
53 | | - auto c = new C(); |
54 | | - C.called = 0; |
55 | | - c.publicMember(); |
56 | | - assert(C.called == 42); |
57 | | - |
58 | | - auto s = new S(); |
59 | | - S.called = 0; |
60 | | - s.publicMember(); |
61 | | - assert(S.called == 42); |
62 | | - |
63 | | - // Defined symbols in one invariant cannot be seen from others. |
64 | | - static struct S6453 |
65 | | - { |
66 | | - invariant() |
67 | | - { |
68 | | - struct S {} |
69 | | - int x; |
70 | | - static assert(!__traits(compiles, y)); |
71 | | - static assert(!__traits(compiles, z)); |
72 | | - } |
73 | | - invariant() |
74 | | - { |
75 | | - struct S {} |
76 | | - int y; |
77 | | - static assert(!__traits(compiles, x)); |
78 | | - static assert(!__traits(compiles, z)); |
79 | | - } |
80 | | - invariant() |
81 | | - { |
82 | | - struct S {} |
83 | | - int z; |
84 | | - static assert(!__traits(compiles, x)); |
85 | | - static assert(!__traits(compiles, y)); |
86 | | - } |
87 | | - } |
88 | | - |
89 | | - static struct S6453a |
90 | | - { |
91 | | - pure invariant() {} |
92 | | - nothrow invariant() {} |
93 | | - @safe invariant() {} |
94 | | - } |
95 | | - static struct S6453b |
96 | | - { |
97 | | - pure shared invariant() {} |
98 | | - nothrow shared invariant() {} |
99 | | - @safe shared invariant() {} |
100 | | - } |
101 | | - static class C6453c |
102 | | - { |
103 | | - pure synchronized invariant() {} |
104 | | - nothrow synchronized invariant() {} |
105 | | - @safe synchronized invariant() {} |
106 | | - } |
107 | | -} |
108 | | - |
109 | | -/***************************************************/ |
110 | | -// https://issues.dlang.org/show_bug.cgi?id=13113 |
111 | | - |
112 | | -struct S13113 |
113 | | -{ |
114 | | - static int count; |
115 | | - invariant() // impure, throwable, system, and gc-able |
116 | | - { |
117 | | - ++count; // impure |
118 | | - } |
119 | | - |
120 | | - this(int) pure nothrow @safe @nogc {} |
121 | | - // post invaiant is called directly but doesn't interfere with constructor attributes |
122 | | - |
123 | | - ~this() pure nothrow @safe @nogc {} |
124 | | - // pre invaiant is called directly but doesn't interfere with destructor attributes |
125 | | - |
126 | | - void foo() pure nothrow @safe @nogc {} |
127 | | - // pre & post invariant calls don't interfere with method attributes |
128 | | -} |
129 | | - |
130 | | -void test13113() |
131 | | -{ |
132 | | - assert(S13113.count == 0); |
133 | | - { |
134 | | - auto s = S13113(1); |
135 | | - assert(S13113.count == 1); |
136 | | - s.foo(); |
137 | | - assert(S13113.count == 3); |
138 | | - } |
139 | | - assert(S13113.count == 4); |
140 | | -} |
141 | | - |
142 | | -/***************************************************/ |
143 | | -// https://issues.dlang.org/show_bug.cgi?id=13147 |
144 | | - |
145 | | -version (D_InlineAsm_X86) |
146 | | - enum x86iasm = true; |
147 | | -else version (D_InlineAsm_X86_64) |
148 | | - enum x86iasm = true; |
149 | | -else |
150 | | - enum x86iasm = false; |
151 | | - |
152 | | -class C13147 |
153 | | -{ |
154 | | - extern (C++) C13147 test() |
| 21 | + import core.exception : AssertError; |
| 22 | + |
| 23 | + try |
155 | 24 | { |
156 | | - static if (x86iasm) |
157 | | - asm { naked; ret; } |
158 | | - return this; |
| 25 | + auto c = new C(); |
| 26 | + c.f(); // Should trigger invariant |
| 27 | + assert(false, "Failed: invariant in extern(C++) class not checked"); |
159 | 28 | } |
160 | | -} |
161 | | - |
162 | | -struct S13147 |
163 | | -{ |
164 | | - void test() |
| 29 | + catch (AssertError e) |
165 | 30 | { |
166 | | - static if (x86iasm) |
167 | | - asm { naked; ret; } |
| 31 | + // Expected behavior - invariant was checked |
| 32 | + return; |
168 | 33 | } |
| 34 | + assert(0, "Invariant in extern(C++) class was not checked"); |
169 | 35 | } |
170 | 36 |
|
171 | | -void test13147() |
172 | | -{ |
173 | | - auto c = new C13147(); |
174 | | - c.test(); |
175 | | - S13147 s; |
176 | | - s.test(); |
177 | | -} |
178 | | - |
179 | | -/***************************************************/ |
180 | | -// https://issues.dlang.org/show_bug.cgi?id=16384 |
181 | | - |
182 | | -struct S(T) |
183 | | -{ |
184 | | - T x = 5; |
185 | | - invariant { assert(x == 6); } |
186 | | - invariant { assert(x > 0); } |
187 | | - |
188 | | - void foo() {} |
189 | | -} |
190 | | - |
191 | | -void f(int i) pure { assert( i == 6); } |
192 | | - |
193 | | -struct S2(T) |
194 | | -{ |
195 | | - T x = 5; |
196 | | - invariant { f(x); } |
197 | | - invariant { assert(x > 0); } |
198 | | - |
199 | | - void foo() {} |
200 | | -} |
201 | | - |
202 | | -void test16384() |
| 37 | +// Runs tests on extern(D) class for comparison |
| 38 | +void testDClass() |
203 | 39 | { |
204 | | - string s; |
205 | | - S!int y; |
206 | | - try |
207 | | - { |
208 | | - y.foo(); |
209 | | - } |
210 | | - catch(Error) |
211 | | - { |
212 | | - s = "needs to be thrown"; |
213 | | - } |
214 | | - |
215 | | - assert(s == "needs to be thrown"); |
216 | | - |
217 | | - S2!int y2; |
218 | | - |
| 40 | + import core.exception : AssertError; |
| 41 | + |
219 | 42 | try |
220 | 43 | { |
221 | | - y2.foo(); |
| 44 | + auto d = new D(); |
| 45 | + d.f(); // Should trigger invariant |
| 46 | + assert(false, "Failed: invariant in extern(D) class not checked"); |
222 | 47 | } |
223 | | - catch(Error) |
| 48 | + catch (AssertError e) |
224 | 49 | { |
225 | | - s = "needs to be thrown2"; |
| 50 | + // Expected behavior - invariant was checked |
| 51 | + return; |
226 | 52 | } |
227 | | - |
228 | | - assert(s == "needs to be thrown2"); |
| 53 | + assert(0, "Invariant in extern(D) class was not checked"); |
229 | 54 | } |
230 | 55 |
|
231 | | - |
232 | | -/***************************************************/ |
233 | | - |
234 | 56 | void main() |
235 | 57 | { |
236 | | - testinvariant(); |
237 | | - test6453(); |
238 | | - test16384(); |
239 | | - test13113(); |
240 | | - test13147(); |
241 | | -} |
| 58 | + // Test both class types |
| 59 | + testDClass(); |
| 60 | + testCppClass(); |
| 61 | +} |
| 62 | + |
| 63 | + |
0 commit comments