| // REQUIRED_ARGS: -preview=in |
| // PERMUTE_ARGS: -g |
| // EXTRA_CPP_SOURCES: cppb.cpp |
| // EXTRA_FILES: extra-files/cppb.h |
| // CXXFLAGS(linux freebsd osx netbsd dragonflybsd): -std=c++11 |
| // druntime isn't linked, this prevents missing symbols '_d_arraybounds_slicep': |
| // REQUIRED_ARGS: -checkaction=C |
| // Filter a spurious warning on Semaphore: |
| // TRANSFORM_OUTPUT: remove_lines("warning: relocation refers to discarded section") |
| |
| // N.B MSVC doesn't have a C++11 switch, but it defaults to the latest fully-supported standard |
| |
| // Broken for unknown reasons since the OMF => MsCOFF switch |
| // DISABLED: win32omf |
| |
| import core.stdc.stdio; |
| import core.stdc.stdarg; |
| import core.stdc.config; |
| import core.stdc.stdint; |
| |
| extern (C++) |
| int foob(int i, int j, int k); |
| |
| class C |
| { |
| extern (C++) int bar(int i, int j, int k) |
| { |
| printf("this = %p\n", this); |
| printf("i = %d\n", i); |
| printf("j = %d\n", j); |
| printf("k = %d\n", k); |
| return 1; |
| } |
| } |
| |
| |
| extern (C++) |
| int foo(int i, int j, int k) |
| { |
| printf("i = %d\n", i); |
| printf("j = %d\n", j); |
| printf("k = %d\n", k); |
| assert(i == 1); |
| assert(j == 2); |
| assert(k == 3); |
| return 1; |
| } |
| |
| void test1() |
| { |
| foo(1, 2, 3); |
| |
| auto i = foob(1, 2, 3); |
| assert(i == 7); |
| |
| C c = new C(); |
| c.bar(4, 5, 6); |
| } |
| |
| /****************************************/ |
| |
| extern (C++) interface D |
| { |
| int bar(int i, int j, int k); |
| } |
| |
| extern (C++) D getD(); |
| |
| void test2() |
| { |
| D d = getD(); |
| int i = d.bar(9,10,11); |
| assert(i == 8); |
| } |
| |
| /****************************************/ |
| |
| extern (C++) int callE(E); |
| |
| extern (C++) interface E |
| { |
| int bar(int i, int j, int k); |
| } |
| |
| class F : E |
| { |
| extern (C++) int bar(int i, int j, int k) |
| { |
| printf("F.bar: i = %d\n", i); |
| printf("F.bar: j = %d\n", j); |
| printf("F.bar: k = %d\n", k); |
| assert(i == 11); |
| assert(j == 12); |
| assert(k == 13); |
| return 8; |
| } |
| } |
| |
| void test3() |
| { |
| F f = new F(); |
| int i = callE(f); |
| assert(i == 8); |
| } |
| |
| /****************************************/ |
| |
| extern (C++) void foo4(char* p); |
| |
| void test4() |
| { |
| foo4(null); |
| } |
| |
| /****************************************/ |
| |
| extern(C++) |
| { |
| struct foo5 { int i; int j; void* p; } |
| |
| interface bar5{ |
| foo5 getFoo(int i); |
| } |
| |
| bar5 newBar(); |
| } |
| |
| void test5() |
| { |
| bar5 b = newBar(); |
| foo5 f = b.getFoo(4); |
| printf("f.p = %p, b = %p\n", f.p, cast(void*)b); |
| assert(f.p == cast(void*)b); |
| } |
| |
| |
| /****************************************/ |
| |
| extern(C++) |
| { |
| struct S6 |
| { |
| int i; |
| double d; |
| } |
| |
| union S6_2 |
| { |
| int i; |
| double d; |
| } |
| |
| enum S6_3 |
| { |
| A, B |
| } |
| |
| S6 foo6(); |
| S6_2 foo6_2(); |
| S6_3 foo6_3(); |
| } |
| |
| extern (C) int foosize6(); |
| |
| void test6() |
| { |
| S6 f = foo6(); |
| printf("%d %zd\n", foosize6(), S6.sizeof); |
| assert(foosize6() == S6.sizeof); |
| version (X86) |
| { |
| assert(f.i == 42); |
| printf("f.d = %g\n", f.d); |
| assert(f.d == 2.5); |
| assert(foo6_2().i == 42); |
| assert(foo6_3() == S6_3.A); |
| } |
| } |
| |
| /****************************************/ |
| |
| extern (C) int foo7(); |
| |
| struct S |
| { |
| int i; |
| long l; |
| } |
| |
| void test7() |
| { |
| printf("%d %zd\n", foo7(), S.sizeof); |
| assert(foo7() == S.sizeof); |
| } |
| |
| /****************************************/ |
| |
| extern (C++) void foo8(const(char)*); |
| |
| void test8() |
| { |
| char c; |
| foo8(&c); |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=4059 |
| |
| struct elem9 { } |
| |
| extern(C++) void foobar9(elem9*, elem9*); |
| |
| void test9() |
| { |
| elem9 *a; |
| foobar9(a, a); |
| } |
| |
| /****************************************/ |
| |
| |
| struct A11802; |
| struct B11802; |
| |
| extern(C++) class C11802 |
| { |
| int x; |
| void fun(A11802*) { x += 2; } |
| void fun(B11802*) { x *= 2; } |
| } |
| |
| extern(C++) class D11802 : C11802 |
| { |
| override void fun(A11802*) { x += 3; } |
| override void fun(B11802*) { x *= 3; } |
| } |
| |
| extern(C++) void test11802x(D11802); |
| |
| void test11802() |
| { |
| auto x = new D11802(); |
| x.x = 0; |
| test11802x(x); |
| assert(x.x == 9); |
| } |
| |
| |
| /****************************************/ |
| |
| struct S13956 |
| { |
| } |
| |
| extern(C++) void func13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); |
| |
| extern(C++) void check13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) |
| { |
| assert(arg0 == S13956()); |
| assert(arg1 == 1); |
| assert(arg2 == 2); |
| assert(arg3 == 3); |
| assert(arg4 == 4); |
| assert(arg5 == 5); |
| assert(arg6 == 6); |
| } |
| |
| void test13956() |
| { |
| func13956(S13956(), 1, 2, 3, 4, 5, 6); |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=5148 |
| |
| extern (C++) |
| { |
| void foo10(const(char)*, const(char)*); |
| void foo10(const int, const int); |
| void foo10(const char, const char); |
| void foo10(bool, bool); |
| |
| struct MyStructType { } |
| void foo10(const MyStructType s, const MyStructType t); |
| |
| enum MyEnumType { onemember } |
| void foo10(const MyEnumType s, const MyEnumType t); |
| } |
| |
| void test10() |
| { |
| char* p; |
| foo10(p, p); |
| foo10(1,2); |
| foo10('c','d'); |
| MyStructType s; |
| foo10(s,s); |
| MyEnumType e; |
| foo10(e,e); |
| } |
| |
| /****************************************/ |
| |
| extern (C++, N11.M) { void bar11(); } |
| |
| extern (C++, A11.B) { extern (C++, C) { void bar(); }} |
| |
| void test11() |
| { |
| bar11(); |
| A11.B.C.bar(); |
| } |
| /****************************************/ |
| |
| struct Struct10071 |
| { |
| void *p; |
| c_long_double r; |
| } |
| |
| extern(C++) size_t offset10071(); |
| void test10071() |
| { |
| assert(offset10071() == Struct10071.r.offsetof); |
| } |
| |
| /****************************************/ |
| |
| char[100] valistbuffer; |
| |
| extern(C++) void myvprintfx(const(char)* format, va_list va) |
| { |
| vsprintf(valistbuffer.ptr, format, va); |
| } |
| extern(C++) void myvprintf(const(char)*, va_list); |
| extern(C++) void myprintf(const(char)* format, ...) |
| { |
| va_list ap; |
| va_start(ap, format); |
| myvprintf(format, ap); |
| va_end(ap); |
| } |
| |
| void testvalist() |
| { |
| myprintf("hello %d", 999); |
| assert(valistbuffer[0..9] == "hello 999"); |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=12825 |
| |
| extern(C++) class C12825 |
| { |
| uint a = 0x12345678; |
| } |
| |
| void test12825() |
| { |
| auto c = new C12825(); |
| } |
| |
| /****************************************/ |
| |
| struct S13955a |
| { |
| float a; |
| double b; |
| } |
| |
| struct S13955b |
| { |
| double a; |
| float b; |
| } |
| |
| struct S13955c |
| { |
| float a; |
| float b; |
| } |
| |
| struct S13955d |
| { |
| double a; |
| double b; |
| } |
| |
| extern(C++) void check13955(S13955a a, S13955b b, S13955c c, S13955d d) |
| { |
| assert(a.a == 2); |
| assert(a.b == 4); |
| assert(b.a == 8); |
| assert(b.b == 16); |
| assert(c.a == 32); |
| assert(c.b == 64); |
| assert(d.a == 128); |
| assert(d.b == 256); |
| } |
| |
| extern(C++) void func13955(S13955a a, S13955b b, S13955c c, S13955d d); |
| |
| void test13955() |
| { |
| func13955(S13955a(2, 4), S13955b(8, 16), S13955c(32, 64), S13955d(128, 256)); |
| } |
| |
| /****************************************/ |
| |
| extern(C++) class C13161 |
| { |
| void dummyfunc(); |
| long val_5; |
| uint val_9; |
| } |
| |
| extern(C++) class Test : C13161 |
| { |
| uint val_0; |
| long val_1; |
| } |
| |
| extern(C++) size_t getoffset13161(); |
| |
| extern(C++) class C13161a |
| { |
| void dummyfunc(); |
| c_long_double val_5; |
| uint val_9; |
| } |
| |
| extern(C++) class Testa : C13161a |
| { |
| bool val_0; |
| } |
| |
| extern(C++) size_t getoffset13161a(); |
| |
| void test13161() |
| { |
| assert(getoffset13161() == Test.val_0.offsetof); |
| assert(getoffset13161a() == Testa.val_0.offsetof); |
| } |
| |
| /****************************************/ |
| |
| version (linux) |
| { |
| static if (__traits(getTargetInfo, "cppStd") < 201703) |
| { |
| // See note on std::allocator below. |
| extern(C++, __gnu_cxx) |
| { |
| struct new_allocator(T) |
| { |
| alias size_type = size_t; |
| static if (is(T : char)) |
| void deallocate(T*, size_type) { } |
| else |
| void deallocate(T*, size_type); |
| } |
| } |
| } |
| } |
| |
| extern (C++, std) |
| { |
| version (linux) |
| { |
| static if (__traits(getTargetInfo, "cppStd") >= 201703) |
| { |
| // std::allocator no longer derives from __gnu_cxx::new_allocator, |
| // it derives from std::__new_allocator instead. |
| struct __new_allocator(T) |
| { |
| alias size_type = size_t; |
| static if (is(T : char)) |
| void deallocate(T*, size_type) { } |
| else |
| void deallocate(T*, size_type); |
| } |
| } |
| } |
| |
| extern (C++, class) struct allocator(T) |
| { |
| version (linux) |
| { |
| alias size_type = size_t; |
| void deallocate(T* p, size_type sz) |
| { |
| static if (__traits(getTargetInfo, "cppStd") >= 201703) |
| (cast(std.__new_allocator!T*)&this).deallocate(p, sz); |
| else |
| (cast(__gnu_cxx.new_allocator!T*)&this).deallocate(p, sz); |
| } |
| } |
| } |
| |
| class vector(T, A = allocator!T) |
| { |
| final void push_back(ref const T); |
| } |
| |
| struct char_traits(T) |
| { |
| } |
| |
| version (CppRuntime_Gcc) |
| { |
| // https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html |
| static if (__traits(getTargetInfo, "cppStd") >= 201103) |
| { |
| extern (C++, __cxx11) |
| { |
| struct basic_string(T, C = char_traits!T, A = allocator!T) |
| { |
| } |
| } |
| } |
| else |
| { |
| extern (C++, class) struct basic_string(T, C = char_traits!T, A = allocator!T) |
| { |
| } |
| } |
| } |
| else |
| { |
| extern (C++, class) struct basic_string(T, C = char_traits!T, A = allocator!T) |
| { |
| } |
| } |
| |
| struct basic_istream(T, C = char_traits!T) |
| { |
| } |
| |
| struct basic_ostream(T, C = char_traits!T) |
| { |
| } |
| |
| struct basic_iostream(T, C = char_traits!T) |
| { |
| } |
| |
| class exception { } |
| |
| // https://issues.dlang.org/show_bug.cgi?id=14956 |
| extern(C++, N14956) |
| { |
| struct S14956 { } |
| } |
| } |
| |
| extern (C++) |
| { |
| version (linux) |
| { |
| void foo14(std.vector!(int) p); |
| void foo14a(std.basic_string!(char) *p); |
| void foo14b(std.basic_string!(int) *p); |
| void foo14c(std.basic_istream!(char) *p); |
| void foo14d(std.basic_ostream!(char) *p); |
| void foo14e(std.basic_iostream!(char) *p); |
| |
| void foo14f(std.char_traits!char* x, std.basic_string!char* p, std.basic_string!char* q); |
| } |
| } |
| |
| void test14() |
| { |
| version (linux) |
| { |
| std.vector!int p; |
| foo14(p); |
| |
| foo14a(null); |
| foo14b(null); |
| foo14c(null); |
| foo14d(null); |
| foo14e(null); |
| foo14f(null, null, null); |
| } |
| } |
| |
| version (linux) |
| { |
| void test14a(std.allocator!int * pa) |
| { |
| pa.deallocate(null, 0); |
| } |
| |
| void gun(std.vector!int pa) |
| { |
| int x = 42; |
| pa.push_back(x); |
| } |
| } |
| |
| void test13289() |
| { |
| assert(f13289_cpp_wchar_t('a') == 'A'); |
| assert(f13289_cpp_wchar_t('B') == 'B'); |
| assert(f13289_d_wchar('c') == 'C'); |
| assert(f13289_d_wchar('D') == 'D'); |
| assert(f13289_d_dchar('e') == 'E'); |
| assert(f13289_d_dchar('F') == 'F'); |
| assert(f13289_cpp_test()); |
| } |
| |
| version(Posix) |
| { |
| enum __c_wchar_t : dchar; |
| } |
| else version(Windows) |
| { |
| enum __c_wchar_t : wchar; |
| } |
| alias wchar_t = __c_wchar_t; |
| extern(C++) |
| { |
| bool f13289_cpp_test(); |
| |
| |
| wchar_t f13289_cpp_wchar_t(wchar_t); |
| |
| |
| wchar f13289_d_wchar(wchar ch) |
| { |
| if (ch <= 'z' && ch >= 'a') |
| { |
| return cast(wchar)(ch - ('a' - 'A')); |
| } |
| else |
| { |
| return ch; |
| } |
| } |
| dchar f13289_d_dchar(dchar ch) |
| { |
| if (ch <= 'z' && ch >= 'a') |
| { |
| return ch - ('a' - 'A'); |
| } |
| else |
| { |
| return ch; |
| } |
| } |
| wchar_t f13289_d_wchar_t(wchar_t ch) |
| { |
| if (ch <= 'z' && ch >= 'a') |
| { |
| return cast(wchar_t)(ch - ('a' - 'A')); |
| } |
| else |
| { |
| return ch; |
| } |
| } |
| } |
| |
| /****************************************/ |
| |
| version (CRuntime_Microsoft) |
| { |
| enum __c_long_double : double; |
| alias __c_long_double myld; |
| } |
| else |
| alias c_long_double myld; |
| |
| extern (C++) myld testld(myld); |
| extern (C++) myld testldld(myld, myld); |
| |
| |
| void test15() |
| { |
| myld ld = 5.0; |
| ld = testld(ld); |
| assert(ld == 6.0); |
| |
| myld ld2 = 5.0; |
| ld2 = testldld(ld2, ld2); |
| assert(ld2 == 6.0); |
| } |
| |
| /****************************************/ |
| |
| version( Windows ) |
| { |
| alias int x_long; |
| alias uint x_ulong; |
| } |
| else |
| { |
| static if( (void*).sizeof > int.sizeof ) |
| { |
| alias long x_long; |
| alias ulong x_ulong; |
| } |
| else |
| { |
| alias int x_long; |
| alias uint x_ulong; |
| } |
| } |
| |
| enum __c_long : x_long; |
| enum __c_ulong : x_ulong; |
| alias __c_long mylong; |
| alias __c_ulong myulong; |
| |
| extern (C++) mylong testl(mylong); |
| extern (C++) myulong testul(myulong); |
| |
| |
| void test16() |
| { |
| { |
| mylong ld = 5; |
| ld = testl(ld); |
| printf("ld = %lld, mylong.sizeof = %lld\n", cast(long)ld, cast(long)mylong.sizeof); |
| assert(ld == 5 + mylong.sizeof); |
| } |
| { |
| myulong ld = 5; |
| ld = testul(ld); |
| assert(ld == 5 + myulong.sizeof); |
| } |
| |
| static if (__c_long.sizeof == long.sizeof) |
| { |
| static assert(__c_long.max == long.max); |
| static assert(__c_long.min == long.min); |
| static assert(__c_long.init == long.init); |
| |
| static assert(__c_ulong.max == ulong.max); |
| static assert(__c_ulong.min == ulong.min); |
| static assert(__c_ulong.init == ulong.init); |
| |
| __c_long cl = 0; |
| cl = cl + 1; |
| long l = cl; |
| cl = l; |
| |
| __c_ulong cul = 0; |
| cul = cul + 1; |
| ulong ul = cul; |
| cul = ul; |
| } |
| else static if (__c_long.sizeof == int.sizeof) |
| { |
| static assert(__c_long.max == int.max); |
| static assert(__c_long.min == int.min); |
| static assert(__c_long.init == int.init); |
| |
| static assert(__c_ulong.max == uint.max); |
| static assert(__c_ulong.min == uint.min); |
| static assert(__c_ulong.init == uint.init); |
| |
| __c_long cl = 0; |
| cl = cl + 1; |
| int i = cl; |
| cl = i; |
| |
| __c_ulong cul = 0; |
| cul = cul + 1; |
| uint u = cul; |
| cul = u; |
| } |
| else |
| static assert(0); |
| } |
| |
| /****************************************/ |
| |
| struct S13707 |
| { |
| void* a; |
| void* b; |
| this(void* a, void* b) |
| { |
| this.a = a; |
| this.b = b; |
| } |
| } |
| |
| extern(C++) S13707 func13707(); |
| |
| void test13707() |
| { |
| auto p = func13707(); |
| assert(p.a == null); |
| assert(p.b == null); |
| } |
| |
| /****************************************/ |
| |
| struct S13932(int x) |
| { |
| int member; |
| } |
| |
| extern(C++) void func13932(S13932!(-1) s); |
| |
| /****************************************/ |
| |
| extern(C++, N13337.M13337) |
| { |
| struct S13337{} |
| void foo13337(S13337 s); |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=14195 |
| |
| struct Delegate1(T) {} |
| struct Delegate2(T1, T2) {} |
| |
| template Signature(T) |
| { |
| alias Signature = typeof(*(T.init)); |
| } |
| |
| extern(C++) |
| { |
| alias del1_t = Delegate1!(Signature!(void function())); |
| alias del2_t = Delegate2!(Signature!(int function(float, double)), Signature!(int function(float, double))); |
| void test14195a(del1_t); |
| void test14195b(del2_t); |
| } |
| |
| void test14195() |
| { |
| test14195a(del1_t()); |
| test14195b(del2_t()); |
| } |
| |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=14200 |
| |
| template Tuple14200(T...) |
| { |
| alias Tuple14200 = T; |
| } |
| |
| extern(C++) void test14200a(Tuple14200!(int)); |
| extern(C++) void test14200b(float, Tuple14200!(int, double)); |
| |
| void test14200() |
| { |
| test14200a(1); |
| test14200b(1.0f, 1, 1.0); |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=14956 |
| |
| extern(C++) void test14956(S14956 s); |
| |
| /****************************************/ |
| // check order of overloads in vtable |
| |
| extern (C++) class Statement {} |
| extern (C++) class ErrorStatement {} |
| extern (C++) class PeelStatement {} |
| extern (C++) class ExpStatement {} |
| extern (C++) class DtorExpStatement {} |
| |
| extern (C++) class Visitor |
| { |
| public: |
| int visit(Statement) { return 1; } |
| int visit(ErrorStatement) { return 2; } |
| int visit(PeelStatement) { return 3; } |
| } |
| |
| extern (C++) class Visitor2 : Visitor |
| { |
| int visit2(ExpStatement) { return 4; } |
| int visit2(DtorExpStatement) { return 5; } |
| } |
| |
| extern(C++) bool testVtableCpp(Visitor2 sv); |
| extern(C++) Visitor2 getVisitor2(); |
| |
| bool testVtableD(Visitor2 sv) |
| { |
| Statement s1; |
| ErrorStatement s2; |
| PeelStatement s3; |
| ExpStatement s4; |
| DtorExpStatement s5; |
| |
| if (sv.visit(s1) != 1) return false; |
| if (sv.visit(s2) != 2) return false; |
| if (sv.visit(s3) != 3) return false; |
| if (sv.visit2(s4) != 4) return false; |
| if (sv.visit2(s5) != 5) return false; |
| return true; |
| } |
| |
| void testVtable() |
| { |
| Visitor2 dinst = new Visitor2; |
| if (!testVtableCpp(dinst)) |
| assert(0); |
| |
| Visitor2 cppinst = getVisitor2(); |
| if (!testVtableD(cppinst)) |
| assert(0); |
| } |
| |
| /****************************************/ |
| /* problems detected by fuzzer */ |
| extern(C++) void fuzz1_cppvararg(int64_t arg10, int64_t arg11, bool arg12); |
| extern(C++) void fuzz1_dvararg(int64_t arg10, int64_t arg11, bool arg12) |
| { |
| fuzz1_checkValues(arg10, arg11, arg12); |
| } |
| |
| extern(C++) void fuzz1_checkValues(int64_t arg10, int64_t arg11, bool arg12) |
| { |
| assert(arg10 == 103); |
| assert(arg11 == 104); |
| assert(arg12 == false); |
| } |
| |
| void fuzz1() |
| { |
| long arg10 = 103; |
| long arg11 = 104; |
| bool arg12 = false; |
| fuzz1_dvararg(arg10, arg11, arg12); |
| fuzz1_cppvararg(arg10, arg11, arg12); |
| } |
| |
| //////// |
| extern(C++) void fuzz2_cppvararg(uint64_t arg10, uint64_t arg11, bool arg12); |
| extern(C++) void fuzz2_dvararg(uint64_t arg10, uint64_t arg11, bool arg12) |
| { |
| fuzz2_checkValues(arg10, arg11, arg12); |
| } |
| |
| extern(C++) void fuzz2_checkValues(uint64_t arg10, uint64_t arg11, bool arg12) |
| { |
| assert(arg10 == 103); |
| assert(arg11 == 104); |
| assert(arg12 == false); |
| } |
| |
| void fuzz2() |
| { |
| ulong arg10 = 103; |
| ulong arg11 = 104; |
| bool arg12 = false; |
| fuzz2_dvararg(arg10, arg11, arg12); |
| fuzz2_cppvararg(arg10, arg11, arg12); |
| } |
| |
| //////// |
| version(CppRuntime_DigitalMars) |
| enum UNICODE = false; |
| else version(CppRuntime_Microsoft) |
| enum UNICODE = false; //VS2013 doesn't support them |
| else |
| enum UNICODE = true; |
| |
| static if (UNICODE) |
| { |
| extern(C++) void fuzz3_cppvararg(wchar arg10, dchar arg11, bool arg12); |
| extern(C++) void fuzz3_dvararg(wchar arg10, dchar arg11, bool arg12) |
| { |
| fuzz2_checkValues(arg10, arg11, arg12); |
| } |
| |
| extern(C++) void fuzz3_checkValues(wchar arg10, dchar arg11, bool arg12) |
| { |
| assert(arg10 == 103); |
| assert(arg11 == 104); |
| assert(arg12 == false); |
| } |
| |
| void fuzz3() |
| { |
| wchar arg10 = 103; |
| dchar arg11 = 104; |
| bool arg12 = false; |
| fuzz3_dvararg(arg10, arg11, arg12); |
| fuzz3_cppvararg(arg10, arg11, arg12); |
| } |
| } |
| |
| void fuzz() |
| { |
| fuzz1(); |
| fuzz2(); |
| static if (UNICODE) fuzz3(); |
| } |
| |
| /****************************************/ |
| |
| extern (C++) |
| { |
| void throwit(); |
| } |
| |
| void testeh() |
| { |
| printf("testeh()\n"); |
| version (linux) |
| { |
| version (X86_64) |
| { |
| bool caught; |
| try |
| { |
| throwit(); |
| } |
| catch (std.exception e) |
| { |
| caught = true; |
| } |
| assert(caught); |
| } |
| } |
| } |
| |
| /****************************************/ |
| |
| version (linux) |
| { |
| version (X86_64) |
| { |
| bool raii_works = false; |
| struct RAIITest |
| { |
| ~this() |
| { |
| raii_works = true; |
| } |
| } |
| |
| void dFunction() |
| { |
| RAIITest rt; |
| throwit(); |
| } |
| |
| void testeh2() |
| { |
| printf("testeh2()\n"); |
| try |
| { |
| dFunction(); |
| } |
| catch(std.exception e) |
| { |
| assert(raii_works); |
| } |
| } |
| } |
| else |
| void testeh2() { } |
| } |
| else |
| void testeh2() { } |
| |
| /****************************************/ |
| |
| extern (C++) { void throwle(); void throwpe(); } |
| |
| void testeh3() |
| { |
| printf("testeh3()\n"); |
| version (linux) |
| { |
| version (X86_64) |
| { |
| bool caught = false; |
| try |
| { |
| throwle(); |
| } |
| catch (std.exception e) //polymorphism test. |
| { |
| caught = true; |
| } |
| assert(caught); |
| } |
| } |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=15576 |
| |
| extern (C++, ns15576) |
| { |
| extern __gshared int global15576; |
| |
| extern (C++, ns) |
| { |
| extern __gshared int n_global15576; |
| } |
| } |
| |
| void test15576() |
| { |
| global15576 = n_global15576 = 123; |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=15579 |
| |
| extern (C++) |
| { |
| class Base |
| { |
| //~this() {} |
| void based() { } |
| ubyte x = 4; |
| } |
| |
| interface Interface |
| { |
| int MethodCPP(); |
| int MethodD(); |
| } |
| |
| class Derived : Base, Interface |
| { |
| short y = 5; |
| int MethodCPP(); |
| int MethodD() { |
| printf("Derived.MethodD(): this = %p, x = %d, y = %d\n", this, x, y); |
| Derived p = this; |
| //p = cast(Derived)(cast(void*)p - 16); |
| assert(p.x == 4 || p.x == 7); |
| assert(p.y == 5 || p.y == 8); |
| return 3; |
| } |
| int Method() { return 6; } |
| } |
| |
| Derived cppfoo(Derived); |
| Interface cppfooi(Interface); |
| } |
| |
| void test15579() |
| { |
| Derived d = new Derived(); |
| printf("d = %p\n", d); |
| assert(d.x == 4); |
| assert(d.y == 5); |
| assert((cast(Interface)d).MethodCPP() == 30); |
| assert((cast(Interface)d).MethodD() == 3); |
| assert(d.MethodCPP() == 30); |
| assert(d.MethodD() == 3); |
| assert(d.Method() == 6); |
| |
| d = cppfoo(d); |
| assert(d.x == 7); |
| assert(d.y == 8); |
| |
| printf("d2 = %p\n", d); |
| |
| /* Casting to an interface involves thunks in the vtbl[]. |
| * g++ puts the thunks for MethodD in the same COMDAT as MethodD. |
| * But D doesn't, so when the linker "picks one" of the D generated MethodD |
| * or the g++ generated MethodD, it may wind up with a messed up thunk, |
| * resulting in a seg fault. The solution is to not expect objects of the same |
| * type to be constructed on both sides of the D/C++ divide if the same member |
| * function (in this case, MethodD) is also defined on both sides. |
| */ |
| version (Windows) |
| { |
| assert((cast(Interface)d).MethodD() == 3); |
| } |
| assert((cast(Interface)d).MethodCPP() == 30); |
| |
| assert(d.Method() == 6); |
| |
| printf("d = %p, i = %p\n", d, cast(Interface)d); |
| version (Windows) |
| { |
| Interface i = cppfooi(d); |
| printf("i2: %p\n", i); |
| assert(i.MethodD() == 3); |
| assert(i.MethodCPP() == 30); |
| } |
| printf("test15579() done\n"); |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=15610 |
| |
| extern(C++) class Base2 |
| { |
| int i; |
| void baser() { } |
| } |
| |
| extern(C++) interface Interface2 { abstract void f(); } |
| |
| extern(C++) class Derived2 : Base2, Interface2 |
| { |
| final |
| override void f(); |
| } |
| |
| |
| void test15610() |
| { |
| auto c = new Derived2(); |
| printf("test15610(): c = %p\n", c); |
| c.i = 3; |
| c.f(); |
| } |
| |
| /******************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=15455 |
| |
| struct X6 |
| { |
| ushort a; |
| ushort b; |
| ubyte c; |
| ubyte d; |
| } |
| |
| static assert(X6.sizeof == 6); |
| |
| struct X8 |
| { |
| ushort a; |
| X6 b; |
| } |
| |
| static assert(X8.sizeof == 8); |
| |
| void test15455a(X8 s) |
| { |
| assert(s.a == 1); |
| assert(s.b.a == 2); |
| assert(s.b.b == 3); |
| assert(s.b.c == 4); |
| assert(s.b.d == 5); |
| } |
| |
| extern (C++) void test15455b(X8 s); |
| |
| void test15455() |
| { |
| X8 s; |
| |
| s.a = 1; |
| s.b.a = 2; |
| s.b.b = 3; |
| s.b.c = 4; |
| s.b.d = 5; |
| test15455a(s); |
| test15455b(s); |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=15372 |
| |
| extern(C++) int foo15372(T)(int v); |
| |
| void test15372() |
| { |
| version(Windows){} |
| else |
| assert(foo15372!int(1) == 1); |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=15802 |
| |
| extern(C++) { |
| template Foo15802(T) { |
| static int boo(T v); |
| } |
| } |
| |
| void test15802() |
| { |
| version(Windows){} |
| else |
| assert(Foo15802!(int).boo(1) == 1); |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=16536 |
| // mangling mismatch on OSX |
| |
| version(OSX) extern(C++) uint64_t pass16536(uint64_t); |
| |
| void test16536() |
| { |
| version(OSX) assert(pass16536(123) == 123); |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=15589 |
| // extern(C++) virtual destructors are not put in vtbl[] |
| |
| extern(C++) |
| { |
| class A15589 |
| { |
| extern(D) static int[] dtorSeq; |
| struct S |
| { |
| this(int x) { this.x = x; } |
| ~this() { dtorSeq ~= x; } |
| int x; |
| } |
| int foo() { return 100; } // shift dtor to slot 1 |
| ~this() { dtorSeq ~= 10; } |
| S s1 = S(1); |
| S s2 = S(2); |
| } |
| class B15589 : A15589 |
| { |
| int bar() { return 200;} // add an additional function AFTER the dtor at slot 2 |
| ~this() { dtorSeq ~= 20; } |
| S s3 = S(3); |
| } |
| |
| void test15589b(A15589 p); |
| } |
| |
| void test15589() |
| { |
| A15589 c = new B15589; |
| assert(A15589.dtorSeq == null); |
| assert(c.foo() == 100); |
| assert((cast(B15589)c).bar() == 200); |
| c.__xdtor(); // virtual dtor call |
| assert(A15589.dtorSeq[] == [ 20, 3, 10, 2, 1 ]); // destroyed full hierarchy! |
| |
| A15589.dtorSeq = null; |
| test15589b(c); |
| assert(A15589.dtorSeq[] == [ 20, 3, 10, 2, 1 ]); // destroyed full hierarchy! |
| } |
| |
| extern(C++) |
| { |
| class Cpp15589Base |
| { |
| public: |
| final ~this(); |
| |
| void nonVirtual(); |
| int a; |
| } |
| |
| class Cpp15589Derived : Cpp15589Base |
| { |
| public: |
| this(); |
| final ~this(); |
| int b; |
| } |
| |
| class Cpp15589BaseVirtual |
| { |
| public: |
| void beforeDtor(); |
| |
| this(); |
| ~this(); |
| |
| void afterDtor(); |
| int c = 1; |
| } |
| |
| class Cpp15589DerivedVirtual : Cpp15589BaseVirtual |
| { |
| public: |
| this(); |
| ~this(); |
| |
| override void afterDtor(); |
| |
| int d; |
| } |
| |
| class Cpp15589IntroducingVirtual : Cpp15589Base |
| { |
| public: |
| this(); |
| void beforeIntroducedVirtual(); |
| ~this(); |
| void afterIntroducedVirtual(int); |
| |
| int e; |
| } |
| |
| struct Cpp15589Struct |
| { |
| ~this(); |
| int s; |
| } |
| |
| void trace15589(int ch) |
| { |
| traceBuf[traceBufPos++] = cast(char) ch; |
| } |
| } |
| |
| __gshared char[32] traceBuf; |
| __gshared size_t traceBufPos; |
| |
| // workaround for https://issues.dlang.org/show_bug.cgi?id=18986 |
| version(OSX) |
| enum cppCtorReturnsThis = false; |
| else version(FreeBSD) |
| enum cppCtorReturnsThis = false; |
| else |
| enum cppCtorReturnsThis = true; |
| |
| mixin template scopeAllocCpp(C) |
| { |
| static if (cppCtorReturnsThis) |
| scope C ptr = new C; |
| else |
| { |
| ubyte[__traits(classInstanceSize, C)] data; |
| C ptr = (){ auto p = cast(C) data.ptr; p.__ctor(); return p; }(); |
| } |
| } |
| |
| void test15589b() |
| { |
| traceBufPos = 0; |
| { |
| Cpp15589Struct struc = Cpp15589Struct(); |
| mixin scopeAllocCpp!Cpp15589Derived derived; |
| mixin scopeAllocCpp!Cpp15589DerivedVirtual derivedVirtual; |
| mixin scopeAllocCpp!Cpp15589IntroducingVirtual introducingVirtual; |
| |
| // `scope` instances are destroyed automatically |
| static if (!cppCtorReturnsThis) |
| { |
| introducingVirtual.ptr.destroy(); |
| derivedVirtual.ptr.destroy(); |
| derived.ptr.destroy(); |
| } |
| } |
| printf("traceBuf15589 %.*s\n", cast(int)traceBufPos, traceBuf.ptr); |
| assert(traceBuf[0..traceBufPos] == "IbVvBbs"); |
| } |
| |
| /****************************************/ |
| |
| // https://issues.dlang.org/show_bug.cgi?id=18928 |
| // Win64: extern(C++) bad codegen, wrong calling convention |
| |
| extern(C++) struct Small18928 |
| { |
| int x; |
| } |
| |
| extern(C++) class CC18928 |
| { |
| Small18928 getVirtual(); // { return S(3); } |
| final Small18928 getFinal(); // { return S(4); } |
| static Small18928 getStatic(); // { return S(5); } |
| } |
| |
| extern(C++) CC18928 newCC18928(); |
| |
| void test18928() |
| { |
| auto cc = newCC18928(); |
| Small18928 v = cc.getVirtual(); |
| assert(v.x == 3); |
| Small18928 f = cc.getFinal(); |
| assert(f.x == 4); |
| Small18928 s = cc.getStatic(); |
| assert(s.x == 5); |
| } |
| |
| /****************************************/ |
| // https://issues.dlang.org/show_bug.cgi?id=18953 |
| // Win32: extern(C++) struct destructor not called correctly through runtime |
| |
| extern(C++) |
| struct S18953 |
| { |
| char x; |
| ~this() nothrow @nogc { traceBuf[traceBufPos++] = x; } |
| } |
| |
| void test18953() |
| { |
| traceBufPos = 0; |
| S18953[] arr = new S18953[3]; |
| arr[1].x = '1'; |
| arr[2].x = '2'; |
| arr.length = 1; |
| assumeSafeAppend(arr); // destroys arr[1] and arr[2] |
| printf("traceBuf18953 %.*s\n", cast(int)traceBufPos, traceBuf.ptr); |
| assert(traceBuf[0..traceBufPos] == "21"); |
| } |
| |
| /****************************************/ |
| |
| // https://issues.dlang.org/show_bug.cgi?id=18966 |
| |
| extern(C++): |
| class Base18966 |
| { |
| this() @safe nothrow; |
| ~this() @safe; |
| void vf(); |
| int x; |
| } |
| |
| class Derived18966 : Base18966 |
| { |
| override void vf() { x = 200; } |
| } |
| |
| class Explicit18966 : Base18966 |
| { |
| this() @safe { super(); } |
| override void vf() { x = 250; } |
| } |
| |
| class Implicit18966 : Base18966 |
| { |
| this() nothrow {} |
| override void vf() { x = 300; } |
| } |
| |
| // test vptr in full ctor chain of mixed D/C++ class hierarchies |
| |
| // TODO: Make this a D class and let C++ derive from it. This works on Windows, |
| // but results in linker errors on Posix due to extra base ctor (`C2` |
| // mangling) being called by the B ctor. |
| class A18966 // in C++ |
| { |
| char[8] calledOverloads = 0; |
| int i; |
| this(); |
| void foo(); |
| } |
| |
| class B18966 : A18966 // in C++ |
| { |
| this(); |
| override void foo(); |
| } |
| |
| class C18966 : B18966 |
| { |
| this() { foo(); } |
| override void foo() { calledOverloads[i++] = 'C'; } |
| } |
| |
| class D18966 : C18966 |
| { |
| this() { foo(); } |
| override void foo() { calledOverloads[i++] = 'D'; } |
| } |
| |
| void test18966() |
| { |
| Derived18966 d = new Derived18966; |
| assert(d.x == 10); |
| d.vf(); |
| assert(d.x == 200); |
| |
| Explicit18966 e = new Explicit18966; |
| assert(e.x == 10); |
| e.vf(); |
| assert(e.x == 250); |
| |
| Implicit18966 i = new Implicit18966; |
| assert(i.x == 10); |
| i.vf(); |
| assert(i.x == 300); |
| |
| // TODO: Allocating + constructing a C++ class with the D GC is not |
| // supported on Posix. The returned pointer (probably from C++ ctor) |
| // seems to be an offset and not the actual object address. |
| version (Windows) |
| { |
| auto a = new A18966; |
| assert(a.calledOverloads[0..2] == "A\0"); |
| |
| auto b = new B18966; |
| assert(b.calledOverloads[0..3] == "AB\0"); |
| } |
| |
| auto c = new C18966; |
| assert(c.calledOverloads[0..4] == "ABC\0"); |
| |
| auto d2 = new D18966; |
| // note: the vptr semantics in ctors of extern(C++) classes may be revised (to "ABCD") |
| assert(d2.calledOverloads[0..5] == "ABDD\0"); |
| } |
| |
| /****************************************/ |
| |
| // https://issues.dlang.org/show_bug.cgi?id=19134 |
| |
| class Base19134 |
| { |
| int a = 123; |
| this() { a += 42; } |
| int foo() const { return a; } |
| } |
| |
| class Derived19134 : Base19134 |
| { |
| int b = 666; |
| this() |
| { |
| a *= 2; |
| b -= 6; |
| } |
| override int foo() const { return b; } |
| } |
| |
| void test19134() |
| { |
| static const d = new Derived19134; |
| assert(d.a == (123 + 42) * 2); |
| assert(d.b == 666 - 6); |
| assert(d.foo() == 660); |
| } |
| |
| // https://issues.dlang.org/show_bug.cgi?id=18955 |
| version (linux) |
| alias std_string = std.basic_string!(char); |
| else |
| { |
| import core.stdcpp.string : core_basic_string = basic_string; |
| alias std_string = core_basic_string!(char); |
| } |
| |
| extern(C++) void callback18955(ref const(std_string) str) |
| { |
| } |
| extern(C++) void test18955(); |
| |
| /****************************************/ |
| |
| extern(C++) void testPreviewIn(); |
| |
| extern(C++) void previewInFunction(in int a, in std_string b, ref const(std_string) c) |
| { |
| assert(a == 42); |
| assert(&b is &c); |
| } |
| |
| /****************************************/ |
| |
| void main() |
| { |
| test1(); |
| test2(); |
| test3(); |
| test4(); |
| test13956(); |
| test5(); |
| test6(); |
| test10071(); |
| test7(); |
| test8(); |
| test11802(); |
| test9(); |
| test10(); |
| test13955(); |
| test11(); |
| testvalist(); |
| test12825(); |
| test13161(); |
| test14(); |
| test13289(); |
| test15(); |
| test16(); |
| func13707(); |
| func13932(S13932!(-1)(0)); |
| foo13337(S13337()); |
| test14195(); |
| test14200(); |
| test14956(S14956()); |
| testVtable(); |
| fuzz(); |
| testeh(); |
| testeh2(); |
| testeh3(); |
| test15576(); |
| test15579(); |
| test15610(); |
| test15455(); |
| test15372(); |
| test15802(); |
| test16536(); |
| test15589(); |
| test15589b(); |
| test18928(); |
| test18953(); |
| test18966(); |
| test19134(); |
| test18955(); |
| testPreviewIn(); |
| |
| printf("Success\n"); |
| } |