1 // PERMUTE_ARGS: -g
2 // EXTRA_CPP_SOURCES: cppb.cpp
3 // EXTRA_FILES: extra-files/cppb.h
4 // CXXFLAGS(linux freebsd osx netbsd dragonflybsd): -std=c++11
5 // druntime isn't linked, this prevents missing symbols '_d_arraybounds_slicep':
6 // REQUIRED_ARGS: -checkaction=C
7 // Filter a spurious warning on Semaphore:
8 // TRANSFORM_OUTPUT: remove_lines("warning: relocation refers to discarded section")
9
10 // N.B MSVC doesn't have a C++11 switch, but it defaults to the latest fully-supported standard
11
12 import core.stdc.stdio;
13 import core.stdc.stdarg;
14 import core.stdc.config;
15 import core.stdc.stdint;
16
17 extern (C++)
18 int foob(int i, int j, int k);
19
20 class C
21 {
bar(int i,int j,int k)22 extern (C++) int bar(int i, int j, int k)
23 {
24 printf("this = %p\n", this);
25 printf("i = %d\n", i);
26 printf("j = %d\n", j);
27 printf("k = %d\n", k);
28 return 1;
29 }
30 }
31
32
33 extern (C++)
foo(int i,int j,int k)34 int foo(int i, int j, int k)
35 {
36 printf("i = %d\n", i);
37 printf("j = %d\n", j);
38 printf("k = %d\n", k);
39 assert(i == 1);
40 assert(j == 2);
41 assert(k == 3);
42 return 1;
43 }
44
test1()45 void test1()
46 {
47 foo(1, 2, 3);
48
49 auto i = foob(1, 2, 3);
50 assert(i == 7);
51
52 C c = new C();
53 c.bar(4, 5, 6);
54 }
55
56 /****************************************/
57
58 extern (C++) interface D
59 {
60 int bar(int i, int j, int k);
61 }
62
63 extern (C++) D getD();
64
test2()65 void test2()
66 {
67 D d = getD();
68 int i = d.bar(9,10,11);
69 assert(i == 8);
70 }
71
72 /****************************************/
73
74 extern (C++) int callE(E);
75
76 extern (C++) interface E
77 {
78 int bar(int i, int j, int k);
79 }
80
81 class F : E
82 {
bar(int i,int j,int k)83 extern (C++) int bar(int i, int j, int k)
84 {
85 printf("F.bar: i = %d\n", i);
86 printf("F.bar: j = %d\n", j);
87 printf("F.bar: k = %d\n", k);
88 assert(i == 11);
89 assert(j == 12);
90 assert(k == 13);
91 return 8;
92 }
93 }
94
test3()95 void test3()
96 {
97 F f = new F();
98 int i = callE(f);
99 assert(i == 8);
100 }
101
102 /****************************************/
103
104 extern (C++) void foo4(char* p);
105
test4()106 void test4()
107 {
108 foo4(null);
109 }
110
111 /****************************************/
112
113 extern(C++)
114 {
115 struct foo5 { int i; int j; void* p; }
116
117 interface bar5{
118 foo5 getFoo(int i);
119 }
120
121 bar5 newBar();
122 }
123
test5()124 void test5()
125 {
126 bar5 b = newBar();
127 foo5 f = b.getFoo(4);
128 printf("f.p = %p, b = %p\n", f.p, cast(void*)b);
129 assert(f.p == cast(void*)b);
130 }
131
132
133 /****************************************/
134
135 extern(C++)
136 {
137 struct S6
138 {
139 int i;
140 double d;
141 }
142
143 union S6_2
144 {
145 int i;
146 double d;
147 }
148
149 enum S6_3
150 {
151 A, B
152 }
153
154 S6 foo6();
155 S6_2 foo6_2();
156 S6_3 foo6_3();
157 }
158
159 extern (C) int foosize6();
160
test6()161 void test6()
162 {
163 S6 f = foo6();
164 printf("%d %zd\n", foosize6(), S6.sizeof);
165 assert(foosize6() == S6.sizeof);
166 version (X86)
167 {
168 assert(f.i == 42);
169 printf("f.d = %g\n", f.d);
170 assert(f.d == 2.5);
171 assert(foo6_2().i == 42);
172 assert(foo6_3() == S6_3.A);
173 }
174 }
175
176 /****************************************/
177
178 extern (C) int foo7();
179
180 struct S
181 {
182 int i;
183 long l;
184 }
185
test7()186 void test7()
187 {
188 printf("%d %zd\n", foo7(), S.sizeof);
189 assert(foo7() == S.sizeof);
190 }
191
192 /****************************************/
193
194 extern (C++) void foo8(const(char)*);
195
test8()196 void test8()
197 {
198 char c;
199 foo8(&c);
200 }
201
202 /****************************************/
203 // https://issues.dlang.org/show_bug.cgi?id=4059
204
205 struct elem9 { }
206
207 extern(C++) void foobar9(elem9*, elem9*);
208
test9()209 void test9()
210 {
211 elem9 *a;
212 foobar9(a, a);
213 }
214
215 /****************************************/
216
217
218 struct A11802;
219 struct B11802;
220
221 extern(C++) class C11802
222 {
223 int x;
fun(A11802 *)224 void fun(A11802*) { x += 2; }
fun(B11802 *)225 void fun(B11802*) { x *= 2; }
226 }
227
228 extern(C++) class D11802 : C11802
229 {
fun(A11802 *)230 override void fun(A11802*) { x += 3; }
fun(B11802 *)231 override void fun(B11802*) { x *= 3; }
232 }
233
234 extern(C++) void test11802x(D11802);
235
test11802()236 void test11802()
237 {
238 auto x = new D11802();
239 x.x = 0;
240 test11802x(x);
241 assert(x.x == 9);
242 }
243
244
245 /****************************************/
246
247 struct S13956
248 {
249 }
250
251 extern(C++) void func13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6);
252
check13956(S13956 arg0,int arg1,int arg2,int arg3,int arg4,int arg5,int arg6)253 extern(C++) void check13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6)
254 {
255 assert(arg0 == S13956());
256 assert(arg1 == 1);
257 assert(arg2 == 2);
258 assert(arg3 == 3);
259 assert(arg4 == 4);
260 assert(arg5 == 5);
261 assert(arg6 == 6);
262 }
263
test13956()264 void test13956()
265 {
266 func13956(S13956(), 1, 2, 3, 4, 5, 6);
267 }
268
269 /****************************************/
270 // https://issues.dlang.org/show_bug.cgi?id=5148
271
272 extern (C++)
273 {
274 void foo10(const(char)*, const(char)*);
275 void foo10(const int, const int);
276 void foo10(const char, const char);
277 void foo10(bool, bool);
278
279 struct MyStructType { }
280 void foo10(const MyStructType s, const MyStructType t);
281
282 enum MyEnumType { onemember }
283 void foo10(const MyEnumType s, const MyEnumType t);
284 }
285
test10()286 void test10()
287 {
288 char* p;
289 foo10(p, p);
290 foo10(1,2);
291 foo10('c','d');
292 MyStructType s;
293 foo10(s,s);
294 MyEnumType e;
295 foo10(e,e);
296 }
297
298 /****************************************/
299
300 extern (C++, N11.M) { void bar11(); }
301
302 extern (C++, A11.B) { extern (C++, C) { void bar(); }}
303
test11()304 void test11()
305 {
306 bar11();
307 A11.B.C.bar();
308 }
309 /****************************************/
310
311 struct Struct10071
312 {
313 void *p;
314 c_long_double r;
315 }
316
317 extern(C++) size_t offset10071();
test10071()318 void test10071()
319 {
320 assert(offset10071() == Struct10071.r.offsetof);
321 }
322
323 /****************************************/
324
325 char[100] valistbuffer;
326
myvprintfx(const (char)* format,va_list va)327 extern(C++) void myvprintfx(const(char)* format, va_list va)
328 {
329 vsprintf(valistbuffer.ptr, format, va);
330 }
331 extern(C++) void myvprintf(const(char)*, va_list);
myprintf(const (char)* format,...)332 extern(C++) void myprintf(const(char)* format, ...)
333 {
334 va_list ap;
335 va_start(ap, format);
336 myvprintf(format, ap);
337 va_end(ap);
338 }
339
testvalist()340 void testvalist()
341 {
342 myprintf("hello %d", 999);
343 assert(valistbuffer[0..9] == "hello 999");
344 }
345
346 /****************************************/
347 // https://issues.dlang.org/show_bug.cgi?id=12825
348
349 extern(C++) class C12825
350 {
351 uint a = 0x12345678;
352 }
353
test12825()354 void test12825()
355 {
356 auto c = new C12825();
357 }
358
359 /****************************************/
360
361 struct S13955a
362 {
363 float a;
364 double b;
365 }
366
367 struct S13955b
368 {
369 double a;
370 float b;
371 }
372
373 struct S13955c
374 {
375 float a;
376 float b;
377 }
378
379 struct S13955d
380 {
381 double a;
382 double b;
383 }
384
check13955(S13955a a,S13955b b,S13955c c,S13955d d)385 extern(C++) void check13955(S13955a a, S13955b b, S13955c c, S13955d d)
386 {
387 assert(a.a == 2);
388 assert(a.b == 4);
389 assert(b.a == 8);
390 assert(b.b == 16);
391 assert(c.a == 32);
392 assert(c.b == 64);
393 assert(d.a == 128);
394 assert(d.b == 256);
395 }
396
397 extern(C++) void func13955(S13955a a, S13955b b, S13955c c, S13955d d);
398
test13955()399 void test13955()
400 {
401 func13955(S13955a(2, 4), S13955b(8, 16), S13955c(32, 64), S13955d(128, 256));
402 }
403
404 /****************************************/
405
406 extern(C++) class C13161
407 {
408 void dummyfunc();
409 long val_5;
410 uint val_9;
411 }
412
413 extern(C++) class Test : C13161
414 {
415 uint val_0;
416 long val_1;
417 }
418
419 extern(C++) size_t getoffset13161();
420
421 extern(C++) class C13161a
422 {
423 void dummyfunc();
424 c_long_double val_5;
425 uint val_9;
426 }
427
428 extern(C++) class Testa : C13161a
429 {
430 bool val_0;
431 }
432
433 extern(C++) size_t getoffset13161a();
434
test13161()435 void test13161()
436 {
437 assert(getoffset13161() == Test.val_0.offsetof);
438 assert(getoffset13161a() == Testa.val_0.offsetof);
439 }
440
441 /****************************************/
442
version(linux)443 version (linux)
444 {
445 extern(C++, __gnu_cxx)
446 {
447 struct new_allocator(T)
448 {
449 alias size_type = size_t;
450 static if (is(T : char))
451 void deallocate(T*, size_type) { }
452 else
453 void deallocate(T*, size_type);
454 }
455 }
456 }
457
458 extern (C++, std)
459 {
allocator(T)460 extern (C++, class) struct allocator(T)
461 {
462 version (linux)
463 {
464 alias size_type = size_t;
465 void deallocate(T* p, size_type sz)
466 { (cast(__gnu_cxx.new_allocator!T*)&this).deallocate(p, sz); }
467 }
468 }
469
470 class vector(T, A = allocator!T)
471 {
472 final void push_back(ref const T);
473 }
474
char_traits(T)475 struct char_traits(T)
476 {
477 }
478
479 // https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
version(none)480 version (none)
481 {
482 extern (C++, __cxx11)
483 {
484 struct basic_string(T, C = char_traits!T, A = allocator!T)
485 {
486 }
487 }
488 }
489 else
490 {
491 extern (C++, class) struct basic_string(T, C = char_traits!T, A = allocator!T)
492 {
493 }
494 }
495
496 struct basic_istream(T, C = char_traits!T)
497 {
498 }
499
500 struct basic_ostream(T, C = char_traits!T)
501 {
502 }
503
504 struct basic_iostream(T, C = char_traits!T)
505 {
506 }
507
508 class exception { }
509
510 // https://issues.dlang.org/show_bug.cgi?id=14956
511 extern(C++, N14956)
512 {
513 struct S14956 { }
514 }
515 }
516
517 extern (C++)
518 {
519 version (linux)
520 {
521 void foo14(std.vector!(int) p);
522 void foo14a(std.basic_string!(char) *p);
523 void foo14b(std.basic_string!(int) *p);
524 void foo14c(std.basic_istream!(char) *p);
525 void foo14d(std.basic_ostream!(char) *p);
526 void foo14e(std.basic_iostream!(char) *p);
527
528 void foo14f(std.char_traits!char* x, std.basic_string!char* p, std.basic_string!char* q);
529 }
530 }
531
532 void test14()
533 {
534 version (linux)
535 {
536 std.vector!int p;
537 foo14(p);
538
539 foo14a(null);
540 foo14b(null);
541 foo14c(null);
542 foo14d(null);
543 foo14e(null);
544 foo14f(null, null, null);
545 }
546 }
547
548 version (linux)
549 {
550 void test14a(std.allocator!int * pa)
551 {
552 pa.deallocate(null, 0);
553 }
554
555 void gun(std.vector!int pa)
556 {
557 int x = 42;
558 pa.push_back(x);
559 }
560 }
561
562 void test13289()
563 {
564 assert(f13289_cpp_wchar_t('a') == 'A');
565 assert(f13289_cpp_wchar_t('B') == 'B');
566 assert(f13289_d_wchar('c') == 'C');
567 assert(f13289_d_wchar('D') == 'D');
568 assert(f13289_d_dchar('e') == 'E');
569 assert(f13289_d_dchar('F') == 'F');
570 assert(f13289_cpp_test());
571 }
572
573 version(Posix)
574 {
575 enum __c_wchar_t : dchar;
576 }
577 else version(Windows)
578 {
579 enum __c_wchar_t : wchar;
580 }
581 alias wchar_t = __c_wchar_t;
582 extern(C++)
583 {
584 bool f13289_cpp_test();
585
586
587 wchar_t f13289_cpp_wchar_t(wchar_t);
588
589
590 wchar f13289_d_wchar(wchar ch)
591 {
592 if (ch <= 'z' && ch >= 'a')
593 {
594 return cast(wchar)(ch - ('a' - 'A'));
595 }
596 else
597 {
598 return ch;
599 }
600 }
601 dchar f13289_d_dchar(dchar ch)
602 {
603 if (ch <= 'z' && ch >= 'a')
604 {
605 return ch - ('a' - 'A');
606 }
607 else
608 {
609 return ch;
610 }
611 }
612 wchar_t f13289_d_wchar_t(wchar_t ch)
613 {
614 if (ch <= 'z' && ch >= 'a')
615 {
616 return cast(wchar_t)(ch - ('a' - 'A'));
617 }
618 else
619 {
620 return ch;
621 }
622 }
623 }
624
625 /****************************************/
626
627 version (CRuntime_Microsoft)
628 {
629 enum __c_long_double : double;
630 alias __c_long_double myld;
631 }
632 else
633 alias c_long_double myld;
634
635 extern (C++) myld testld(myld);
636 extern (C++) myld testldld(myld, myld);
637
638
639 void test15()
640 {
641 myld ld = 5.0;
642 ld = testld(ld);
643 assert(ld == 6.0);
644
645 myld ld2 = 5.0;
646 ld2 = testldld(ld2, ld2);
647 assert(ld2 == 6.0);
648 }
649
650 /****************************************/
651
652 version( Windows )
653 {
654 alias int x_long;
655 alias uint x_ulong;
656 }
657 else
658 {
659 static if( (void*).sizeof > int.sizeof )
660 {
661 alias long x_long;
662 alias ulong x_ulong;
663 }
664 else
665 {
666 alias int x_long;
667 alias uint x_ulong;
668 }
669 }
670
671 enum __c_long : x_long;
672 enum __c_ulong : x_ulong;
673 alias __c_long mylong;
674 alias __c_ulong myulong;
675
676 extern (C++) mylong testl(mylong);
677 extern (C++) myulong testul(myulong);
678
679
680 void test16()
681 {
682 {
683 mylong ld = 5;
684 ld = testl(ld);
685 printf("ld = %lld, mylong.sizeof = %lld\n", cast(long)ld, cast(long)mylong.sizeof);
686 assert(ld == 5 + mylong.sizeof);
687 }
688 {
689 myulong ld = 5;
690 ld = testul(ld);
691 assert(ld == 5 + myulong.sizeof);
692 }
693
694 static if (__c_long.sizeof == long.sizeof)
695 {
696 static assert(__c_long.max == long.max);
697 static assert(__c_long.min == long.min);
698 static assert(__c_long.init == long.init);
699
700 static assert(__c_ulong.max == ulong.max);
701 static assert(__c_ulong.min == ulong.min);
702 static assert(__c_ulong.init == ulong.init);
703
704 __c_long cl = 0;
705 cl = cl + 1;
706 long l = cl;
707 cl = l;
708
709 __c_ulong cul = 0;
710 cul = cul + 1;
711 ulong ul = cul;
712 cul = ul;
713 }
714 else static if (__c_long.sizeof == int.sizeof)
715 {
716 static assert(__c_long.max == int.max);
717 static assert(__c_long.min == int.min);
718 static assert(__c_long.init == int.init);
719
720 static assert(__c_ulong.max == uint.max);
721 static assert(__c_ulong.min == uint.min);
722 static assert(__c_ulong.init == uint.init);
723
724 __c_long cl = 0;
725 cl = cl + 1;
726 int i = cl;
727 cl = i;
728
729 __c_ulong cul = 0;
730 cul = cul + 1;
731 uint u = cul;
732 cul = u;
733 }
734 else
735 static assert(0);
736 }
737
738 /****************************************/
739
740 struct S13707
741 {
742 void* a;
743 void* b;
744 this(void* a, void* b)
745 {
746 this.a = a;
747 this.b = b;
748 }
749 }
750
751 extern(C++) S13707 func13707();
752
753 void test13707()
754 {
755 auto p = func13707();
756 assert(p.a == null);
757 assert(p.b == null);
758 }
759
760 /****************************************/
761
762 struct S13932(int x)
763 {
764 int member;
765 }
766
767 extern(C++) void func13932(S13932!(-1) s);
768
769 /****************************************/
770
771 extern(C++, N13337.M13337)
772 {
773 struct S13337{}
774 void foo13337(S13337 s);
775 }
776
777 /****************************************/
778 // https://issues.dlang.org/show_bug.cgi?id=14195
779
780 struct Delegate1(T) {}
781 struct Delegate2(T1, T2) {}
782
783 template Signature(T)
784 {
785 alias Signature = typeof(*(T.init));
786 }
787
788 extern(C++)
789 {
790 alias del1_t = Delegate1!(Signature!(void function()));
791 alias del2_t = Delegate2!(Signature!(int function(float, double)), Signature!(int function(float, double)));
792 void test14195a(del1_t);
793 void test14195b(del2_t);
794 }
795
796 void test14195()
797 {
798 test14195a(del1_t());
799 test14195b(del2_t());
800 }
801
802
803 /****************************************/
804 // https://issues.dlang.org/show_bug.cgi?id=14200
805
806 template Tuple14200(T...)
807 {
808 alias Tuple14200 = T;
809 }
810
811 extern(C++) void test14200a(Tuple14200!(int));
812 extern(C++) void test14200b(float, Tuple14200!(int, double));
813
814 void test14200()
815 {
816 test14200a(1);
817 test14200b(1.0f, 1, 1.0);
818 }
819
820 /****************************************/
821 // https://issues.dlang.org/show_bug.cgi?id=14956
822
823 extern(C++) void test14956(S14956 s);
824
825 /****************************************/
826 // check order of overloads in vtable
827
828 extern (C++) class Statement {}
829 extern (C++) class ErrorStatement {}
830 extern (C++) class PeelStatement {}
831 extern (C++) class ExpStatement {}
832 extern (C++) class DtorExpStatement {}
833
834 extern (C++) class Visitor
835 {
836 public:
837 int visit(Statement) { return 1; }
838 int visit(ErrorStatement) { return 2; }
839 int visit(PeelStatement) { return 3; }
840 }
841
842 extern (C++) class Visitor2 : Visitor
843 {
844 int visit2(ExpStatement) { return 4; }
845 int visit2(DtorExpStatement) { return 5; }
846 }
847
848 extern(C++) bool testVtableCpp(Visitor2 sv);
849 extern(C++) Visitor2 getVisitor2();
850
851 bool testVtableD(Visitor2 sv)
852 {
853 Statement s1;
854 ErrorStatement s2;
855 PeelStatement s3;
856 ExpStatement s4;
857 DtorExpStatement s5;
858
859 if (sv.visit(s1) != 1) return false;
860 if (sv.visit(s2) != 2) return false;
861 if (sv.visit(s3) != 3) return false;
862 if (sv.visit2(s4) != 4) return false;
863 if (sv.visit2(s5) != 5) return false;
864 return true;
865 }
866
867 void testVtable()
868 {
869 Visitor2 dinst = new Visitor2;
870 if (!testVtableCpp(dinst))
871 assert(0);
872
873 Visitor2 cppinst = getVisitor2();
874 if (!testVtableD(cppinst))
875 assert(0);
876 }
877
878 /****************************************/
879 /* problems detected by fuzzer */
880 extern(C++) void fuzz1_cppvararg(int64_t arg10, int64_t arg11, bool arg12);
881 extern(C++) void fuzz1_dvararg(int64_t arg10, int64_t arg11, bool arg12)
882 {
883 fuzz1_checkValues(arg10, arg11, arg12);
884 }
885
886 extern(C++) void fuzz1_checkValues(int64_t arg10, int64_t arg11, bool arg12)
887 {
888 assert(arg10 == 103);
889 assert(arg11 == 104);
890 assert(arg12 == false);
891 }
892
893 void fuzz1()
894 {
895 long arg10 = 103;
896 long arg11 = 104;
897 bool arg12 = false;
898 fuzz1_dvararg(arg10, arg11, arg12);
899 fuzz1_cppvararg(arg10, arg11, arg12);
900 }
901
902 ////////
903 extern(C++) void fuzz2_cppvararg(uint64_t arg10, uint64_t arg11, bool arg12);
904 extern(C++) void fuzz2_dvararg(uint64_t arg10, uint64_t arg11, bool arg12)
905 {
906 fuzz2_checkValues(arg10, arg11, arg12);
907 }
908
909 extern(C++) void fuzz2_checkValues(uint64_t arg10, uint64_t arg11, bool arg12)
910 {
911 assert(arg10 == 103);
912 assert(arg11 == 104);
913 assert(arg12 == false);
914 }
915
916 void fuzz2()
917 {
918 ulong arg10 = 103;
919 ulong arg11 = 104;
920 bool arg12 = false;
921 fuzz2_dvararg(arg10, arg11, arg12);
922 fuzz2_cppvararg(arg10, arg11, arg12);
923 }
924
925 ////////
926 version(CppRuntime_DigitalMars)
927 enum UNICODE = false;
928 else version(CppRuntime_Microsoft)
929 enum UNICODE = false; //VS2013 doesn't support them
930 else
931 enum UNICODE = true;
932
933 static if (UNICODE)
934 {
935 extern(C++) void fuzz3_cppvararg(wchar arg10, dchar arg11, bool arg12);
936 extern(C++) void fuzz3_dvararg(wchar arg10, dchar arg11, bool arg12)
937 {
938 fuzz2_checkValues(arg10, arg11, arg12);
939 }
940
941 extern(C++) void fuzz3_checkValues(wchar arg10, dchar arg11, bool arg12)
942 {
943 assert(arg10 == 103);
944 assert(arg11 == 104);
945 assert(arg12 == false);
946 }
947
948 void fuzz3()
949 {
950 wchar arg10 = 103;
951 dchar arg11 = 104;
952 bool arg12 = false;
953 fuzz3_dvararg(arg10, arg11, arg12);
954 fuzz3_cppvararg(arg10, arg11, arg12);
955 }
956 }
957
958 void fuzz()
959 {
960 fuzz1();
961 fuzz2();
962 static if (UNICODE) fuzz3();
963 }
964
965 /****************************************/
966
967 extern (C++)
968 {
969 void throwit();
970 }
971
972 void testeh()
973 {
974 printf("testeh()\n");
975 version (linux)
976 {
977 version (X86_64)
978 {
979 bool caught;
980 try
981 {
982 throwit();
983 }
984 catch (std.exception e)
985 {
986 caught = true;
987 }
988 assert(caught);
989 }
990 }
991 }
992
993 /****************************************/
994
995 version (linux)
996 {
997 version (X86_64)
998 {
999 bool raii_works = false;
1000 struct RAIITest
1001 {
1002 ~this()
1003 {
1004 raii_works = true;
1005 }
1006 }
1007
1008 void dFunction()
1009 {
1010 RAIITest rt;
1011 throwit();
1012 }
1013
1014 void testeh2()
1015 {
1016 printf("testeh2()\n");
1017 try
1018 {
1019 dFunction();
1020 }
1021 catch(std.exception e)
1022 {
1023 assert(raii_works);
1024 }
1025 }
1026 }
1027 else
1028 void testeh2() { }
1029 }
1030 else
1031 void testeh2() { }
1032
1033 /****************************************/
1034
1035 extern (C++) { void throwle(); void throwpe(); }
1036
1037 void testeh3()
1038 {
1039 printf("testeh3()\n");
1040 version (linux)
1041 {
1042 version (X86_64)
1043 {
1044 bool caught = false;
1045 try
1046 {
1047 throwle();
1048 }
1049 catch (std.exception e) //polymorphism test.
1050 {
1051 caught = true;
1052 }
1053 assert(caught);
1054 }
1055 }
1056 }
1057
1058 /****************************************/
1059 // https://issues.dlang.org/show_bug.cgi?id=15576
1060
1061 extern (C++, ns15576)
1062 {
1063 extern __gshared int global15576;
1064
1065 extern (C++, ns)
1066 {
1067 extern __gshared int n_global15576;
1068 }
1069 }
1070
1071 void test15576()
1072 {
1073 global15576 = n_global15576 = 123;
1074 }
1075
1076 /****************************************/
1077 // https://issues.dlang.org/show_bug.cgi?id=15579
1078
1079 extern (C++)
1080 {
1081 class Base
1082 {
1083 //~this() {}
1084 void based() { }
1085 ubyte x = 4;
1086 }
1087
1088 interface Interface
1089 {
1090 int MethodCPP();
1091 int MethodD();
1092 }
1093
1094 class Derived : Base, Interface
1095 {
1096 short y = 5;
1097 int MethodCPP();
1098 int MethodD() {
1099 printf("Derived.MethodD(): this = %p, x = %d, y = %d\n", this, x, y);
1100 Derived p = this;
1101 //p = cast(Derived)(cast(void*)p - 16);
1102 assert(p.x == 4 || p.x == 7);
1103 assert(p.y == 5 || p.y == 8);
1104 return 3;
1105 }
1106 int Method() { return 6; }
1107 }
1108
1109 Derived cppfoo(Derived);
1110 Interface cppfooi(Interface);
1111 }
1112
1113 void test15579()
1114 {
1115 Derived d = new Derived();
1116 printf("d = %p\n", d);
1117 assert(d.x == 4);
1118 assert(d.y == 5);
1119 assert((cast(Interface)d).MethodCPP() == 30);
1120 assert((cast(Interface)d).MethodD() == 3);
1121 assert(d.MethodCPP() == 30);
1122 assert(d.MethodD() == 3);
1123 assert(d.Method() == 6);
1124
1125 d = cppfoo(d);
1126 assert(d.x == 7);
1127 assert(d.y == 8);
1128
1129 printf("d2 = %p\n", d);
1130
1131 /* Casting to an interface involves thunks in the vtbl[].
1132 * g++ puts the thunks for MethodD in the same COMDAT as MethodD.
1133 * But D doesn't, so when the linker "picks one" of the D generated MethodD
1134 * or the g++ generated MethodD, it may wind up with a messed up thunk,
1135 * resulting in a seg fault. The solution is to not expect objects of the same
1136 * type to be constructed on both sides of the D/C++ divide if the same member
1137 * function (in this case, MethodD) is also defined on both sides.
1138 */
1139 version (Windows)
1140 {
1141 assert((cast(Interface)d).MethodD() == 3);
1142 }
1143 assert((cast(Interface)d).MethodCPP() == 30);
1144
1145 assert(d.Method() == 6);
1146
1147 printf("d = %p, i = %p\n", d, cast(Interface)d);
1148 version (Windows)
1149 {
1150 Interface i = cppfooi(d);
1151 printf("i2: %p\n", i);
1152 assert(i.MethodD() == 3);
1153 assert(i.MethodCPP() == 30);
1154 }
1155 printf("test15579() done\n");
1156 }
1157
1158 /****************************************/
1159 // https://issues.dlang.org/show_bug.cgi?id=15610
1160
1161 extern(C++) class Base2
1162 {
1163 int i;
1164 void baser() { }
1165 }
1166
1167 extern(C++) interface Interface2 { abstract void f(); }
1168
1169 extern(C++) class Derived2 : Base2, Interface2
1170 {
1171 final
1172 override void f();
1173 }
1174
1175
1176 void test15610()
1177 {
1178 auto c = new Derived2();
1179 printf("test15610(): c = %p\n", c);
1180 c.i = 3;
1181 c.f();
1182 }
1183
1184 /******************************************/
1185 // https://issues.dlang.org/show_bug.cgi?id=15455
1186
1187 struct X6
1188 {
1189 ushort a;
1190 ushort b;
1191 ubyte c;
1192 ubyte d;
1193 }
1194
1195 static assert(X6.sizeof == 6);
1196
1197 struct X8
1198 {
1199 ushort a;
1200 X6 b;
1201 }
1202
1203 static assert(X8.sizeof == 8);
1204
1205 void test15455a(X8 s)
1206 {
1207 assert(s.a == 1);
1208 assert(s.b.a == 2);
1209 assert(s.b.b == 3);
1210 assert(s.b.c == 4);
1211 assert(s.b.d == 5);
1212 }
1213
1214 extern (C++) void test15455b(X8 s);
1215
1216 void test15455()
1217 {
1218 X8 s;
1219
1220 s.a = 1;
1221 s.b.a = 2;
1222 s.b.b = 3;
1223 s.b.c = 4;
1224 s.b.d = 5;
1225 test15455a(s);
1226 test15455b(s);
1227 }
1228
1229 /****************************************/
1230 // https://issues.dlang.org/show_bug.cgi?id=15372
1231
1232 extern(C++) int foo15372(T)(int v);
1233
1234 void test15372()
1235 {
1236 version(Windows){}
1237 else
1238 assert(foo15372!int(1) == 1);
1239 }
1240
1241 /****************************************/
1242 // https://issues.dlang.org/show_bug.cgi?id=15802
1243
1244 extern(C++) {
1245 template Foo15802(T) {
1246 static int boo(T v);
1247 }
1248 }
1249
1250 void test15802()
1251 {
1252 version(Windows){}
1253 else
1254 assert(Foo15802!(int).boo(1) == 1);
1255 }
1256
1257 /****************************************/
1258 // https://issues.dlang.org/show_bug.cgi?id=16536
1259 // mangling mismatch on OSX
1260
1261 version(OSX) extern(C++) uint64_t pass16536(uint64_t);
1262
1263 void test16536()
1264 {
1265 version(OSX) assert(pass16536(123) == 123);
1266 }
1267
1268 /****************************************/
1269 // https://issues.dlang.org/show_bug.cgi?id=15589
1270 // extern(C++) virtual destructors are not put in vtbl[]
1271
1272 extern(C++)
1273 {
1274 class A15589
1275 {
1276 extern(D) static int[] dtorSeq;
1277 struct S
1278 {
1279 this(int x) { this.x = x; }
1280 ~this() { dtorSeq ~= x; }
1281 int x;
1282 }
1283 int foo() { return 100; } // shift dtor to slot 1
1284 ~this() { dtorSeq ~= 10; }
1285 S s1 = S(1);
1286 S s2 = S(2);
1287 }
1288 class B15589 : A15589
1289 {
1290 int bar() { return 200;} // add an additional function AFTER the dtor at slot 2
1291 ~this() { dtorSeq ~= 20; }
1292 S s3 = S(3);
1293 }
1294
1295 void test15589b(A15589 p);
1296 }
1297
1298 void test15589()
1299 {
1300 A15589 c = new B15589;
1301 assert(A15589.dtorSeq == null);
1302 assert(c.foo() == 100);
1303 assert((cast(B15589)c).bar() == 200);
1304 c.__xdtor(); // virtual dtor call
1305 assert(A15589.dtorSeq[] == [ 20, 3, 10, 2, 1 ]); // destroyed full hierarchy!
1306
1307 A15589.dtorSeq = null;
1308 test15589b(c);
1309 assert(A15589.dtorSeq[] == [ 20, 3, 10, 2, 1 ]); // destroyed full hierarchy!
1310 }
1311
1312 extern(C++)
1313 {
1314 class Cpp15589Base
1315 {
1316 public:
1317 final ~this();
1318
1319 void nonVirtual();
1320 int a;
1321 }
1322
1323 class Cpp15589Derived : Cpp15589Base
1324 {
1325 public:
1326 this();
1327 final ~this();
1328 int b;
1329 }
1330
1331 class Cpp15589BaseVirtual
1332 {
1333 public:
1334 void beforeDtor();
1335
1336 this();
1337 ~this();
1338
1339 void afterDtor();
1340 int c = 1;
1341 }
1342
1343 class Cpp15589DerivedVirtual : Cpp15589BaseVirtual
1344 {
1345 public:
1346 this();
1347 ~this();
1348
1349 override void afterDtor();
1350
1351 int d;
1352 }
1353
1354 class Cpp15589IntroducingVirtual : Cpp15589Base
1355 {
1356 public:
1357 this();
1358 void beforeIntroducedVirtual();
1359 ~this();
1360 void afterIntroducedVirtual(int);
1361
1362 int e;
1363 }
1364
1365 struct Cpp15589Struct
1366 {
1367 ~this();
1368 int s;
1369 }
1370
1371 void trace15589(int ch)
1372 {
1373 traceBuf[traceBufPos++] = cast(char) ch;
1374 }
1375 }
1376
1377 __gshared char[32] traceBuf;
1378 __gshared size_t traceBufPos;
1379
1380 // workaround for https://issues.dlang.org/show_bug.cgi?id=18986
1381 version(OSX)
1382 enum cppCtorReturnsThis = false;
1383 else version(FreeBSD)
1384 enum cppCtorReturnsThis = false;
1385 else
1386 enum cppCtorReturnsThis = true;
1387
1388 mixin template scopeAllocCpp(C)
1389 {
1390 static if (cppCtorReturnsThis)
1391 scope C ptr = new C;
1392 else
1393 {
1394 ubyte[__traits(classInstanceSize, C)] data;
1395 C ptr = (){ auto p = cast(C) data.ptr; p.__ctor(); return p; }();
1396 }
1397 }
1398
1399 void test15589b()
1400 {
1401 traceBufPos = 0;
1402 {
1403 Cpp15589Struct struc = Cpp15589Struct();
1404 mixin scopeAllocCpp!Cpp15589Derived derived;
1405 mixin scopeAllocCpp!Cpp15589DerivedVirtual derivedVirtual;
1406 mixin scopeAllocCpp!Cpp15589IntroducingVirtual introducingVirtual;
1407
1408 // `scope` instances are destroyed automatically
1409 static if (!cppCtorReturnsThis)
1410 {
1411 introducingVirtual.ptr.destroy();
1412 derivedVirtual.ptr.destroy();
1413 derived.ptr.destroy();
1414 }
1415 }
1416 printf("traceBuf15589 %.*s\n", cast(int)traceBufPos, traceBuf.ptr);
1417 assert(traceBuf[0..traceBufPos] == "IbVvBbs");
1418 }
1419
1420 /****************************************/
1421
1422 // https://issues.dlang.org/show_bug.cgi?id=18928
1423 // Win64: extern(C++) bad codegen, wrong calling convention
1424
1425 extern(C++) struct Small18928
1426 {
1427 int x;
1428 }
1429
1430 extern(C++) class CC18928
1431 {
1432 Small18928 getVirtual(); // { return S(3); }
1433 final Small18928 getFinal(); // { return S(4); }
1434 static Small18928 getStatic(); // { return S(5); }
1435 }
1436
1437 extern(C++) CC18928 newCC18928();
1438
1439 void test18928()
1440 {
1441 auto cc = newCC18928();
1442 Small18928 v = cc.getVirtual();
1443 assert(v.x == 3);
1444 Small18928 f = cc.getFinal();
1445 assert(f.x == 4);
1446 Small18928 s = cc.getStatic();
1447 assert(s.x == 5);
1448 }
1449
1450 /****************************************/
1451 // https://issues.dlang.org/show_bug.cgi?id=18953
1452 // Win32: extern(C++) struct destructor not called correctly through runtime
1453
1454 extern(C++)
1455 struct S18953
1456 {
1457 char x;
1458 ~this() nothrow @nogc { traceBuf[traceBufPos++] = x; }
1459 }
1460
1461 void test18953()
1462 {
1463 traceBufPos = 0;
1464 S18953[] arr = new S18953[3];
1465 arr[1].x = '1';
1466 arr[2].x = '2';
1467 arr.length = 1;
1468 assumeSafeAppend(arr); // destroys arr[1] and arr[2]
1469 printf("traceBuf18953 %.*s\n", cast(int)traceBufPos, traceBuf.ptr);
1470 assert(traceBuf[0..traceBufPos] == "21");
1471 }
1472
1473 /****************************************/
1474
1475 // https://issues.dlang.org/show_bug.cgi?id=18966
1476
1477 extern(C++):
1478 class Base18966
1479 {
1480 this() @safe nothrow;
1481 ~this() @safe;
1482 void vf();
1483 int x;
1484 }
1485
1486 class Derived18966 : Base18966
1487 {
1488 override void vf() { x = 200; }
1489 }
1490
1491 class Explicit18966 : Base18966
1492 {
1493 this() @safe { super(); }
1494 override void vf() { x = 250; }
1495 }
1496
1497 class Implicit18966 : Base18966
1498 {
1499 this() nothrow {}
1500 override void vf() { x = 300; }
1501 }
1502
1503 // test vptr in full ctor chain of mixed D/C++ class hierarchies
1504
1505 // TODO: Make this a D class and let C++ derive from it. This works on Windows,
1506 // but results in linker errors on Posix due to extra base ctor (`C2`
1507 // mangling) being called by the B ctor.
1508 class A18966 // in C++
1509 {
1510 char[8] calledOverloads = 0;
1511 int i;
1512 this();
1513 void foo();
1514 }
1515
1516 class B18966 : A18966 // in C++
1517 {
1518 this();
1519 override void foo();
1520 }
1521
1522 class C18966 : B18966
1523 {
1524 this() { foo(); }
1525 override void foo() { calledOverloads[i++] = 'C'; }
1526 }
1527
1528 class D18966 : C18966
1529 {
1530 this() { foo(); }
1531 override void foo() { calledOverloads[i++] = 'D'; }
1532 }
1533
1534 void test18966()
1535 {
1536 Derived18966 d = new Derived18966;
1537 assert(d.x == 10);
1538 d.vf();
1539 assert(d.x == 200);
1540
1541 Explicit18966 e = new Explicit18966;
1542 assert(e.x == 10);
1543 e.vf();
1544 assert(e.x == 250);
1545
1546 Implicit18966 i = new Implicit18966;
1547 assert(i.x == 10);
1548 i.vf();
1549 assert(i.x == 300);
1550
1551 // TODO: Allocating + constructing a C++ class with the D GC is not
1552 // supported on Posix. The returned pointer (probably from C++ ctor)
1553 // seems to be an offset and not the actual object address.
1554 version (Windows)
1555 {
1556 auto a = new A18966;
1557 assert(a.calledOverloads[0..2] == "A\0");
1558
1559 auto b = new B18966;
1560 assert(b.calledOverloads[0..3] == "AB\0");
1561 }
1562
1563 auto c = new C18966;
1564 assert(c.calledOverloads[0..4] == "ABC\0");
1565
1566 auto d2 = new D18966;
1567 // note: the vptr semantics in ctors of extern(C++) classes may be revised (to "ABCD")
1568 assert(d2.calledOverloads[0..5] == "ABDD\0");
1569 }
1570
1571 /****************************************/
1572
1573 // https://issues.dlang.org/show_bug.cgi?id=19134
1574
1575 class Base19134
1576 {
1577 int a = 123;
1578 this() { a += 42; }
1579 int foo() const { return a; }
1580 }
1581
1582 class Derived19134 : Base19134
1583 {
1584 int b = 666;
1585 this()
1586 {
1587 a *= 2;
1588 b -= 6;
1589 }
1590 override int foo() const { return b; }
1591 }
1592
1593 void test19134()
1594 {
1595 static const d = new Derived19134;
1596 assert(d.a == (123 + 42) * 2);
1597 assert(d.b == 666 - 6);
1598 assert(d.foo() == 660);
1599 }
1600
1601 // https://issues.dlang.org/show_bug.cgi?id=18955
1602 alias std_string = std.basic_string!(char);
1603
1604 extern(C++) void callback18955(ref const(std_string) str)
1605 {
1606 }
1607 extern(C++) void test18955();
1608
1609 /****************************************/
1610
1611 void main()
1612 {
1613 test1();
1614 test2();
1615 test3();
1616 test4();
1617 test13956();
1618 test5();
1619 test6();
1620 test10071();
1621 test7();
1622 test8();
1623 test11802();
1624 test9();
1625 test10();
1626 test13955();
1627 test11();
1628 testvalist();
1629 test12825();
1630 test13161();
1631 test14();
1632 test13289();
1633 test15();
1634 test16();
1635 func13707();
1636 func13932(S13932!(-1)(0));
1637 foo13337(S13337());
1638 test14195();
1639 test14200();
1640 test14956(S14956());
1641 testVtable();
1642 fuzz();
1643 testeh();
1644 testeh2();
1645 testeh3();
1646 test15576();
1647 test15579();
1648 test15610();
1649 test15455();
1650 test15372();
1651 test15802();
1652 test16536();
1653 test15589();
1654 test15589b();
1655 test18928();
1656 test18953();
1657 test18966();
1658 test19134();
1659 test18955();
1660
1661 printf("Success\n");
1662 }
1663