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