From 0220433a5829b848422810c88d01c2203bc66eae Mon Sep 17 00:00:00 2001 From: coderJeff Date: Sat, 29 Jun 2019 12:41:31 -0400 Subject: [PATCH 1/4] fbc-tests: rename tests/cpp/*-mangle.* to tests/cpp/mangle-*.* --- tests/cpp/{cpp-mangle.cpp => mangle-cpp.cpp} | 0 tests/cpp/{fbc-mangle.bas => mangle-fbc.bas} | 0 tests/cpp/mangle.bmk | 6 +++--- 3 files changed, 3 insertions(+), 3 deletions(-) rename tests/cpp/{cpp-mangle.cpp => mangle-cpp.cpp} (100%) rename tests/cpp/{fbc-mangle.bas => mangle-fbc.bas} (100%) diff --git a/tests/cpp/cpp-mangle.cpp b/tests/cpp/mangle-cpp.cpp similarity index 100% rename from tests/cpp/cpp-mangle.cpp rename to tests/cpp/mangle-cpp.cpp diff --git a/tests/cpp/fbc-mangle.bas b/tests/cpp/mangle-fbc.bas similarity index 100% rename from tests/cpp/fbc-mangle.bas rename to tests/cpp/mangle-fbc.bas diff --git a/tests/cpp/mangle.bmk b/tests/cpp/mangle.bmk index ca5ba1940b..6b728b429e 100644 --- a/tests/cpp/mangle.bmk +++ b/tests/cpp/mangle.bmk @@ -1,10 +1,10 @@ # TEST_MODE : MULTI_MODULE_OK -MAIN := fbc-mangle.bas +MAIN := mangle-fbc.bas SRCS := -EXTRA_OBJS := cpp-mangle.o +EXTRA_OBJS := mangle-cpp.o -$(SRCDIR)cpp-mangle.o : $(SRCDIR)cpp-mangle.cpp +$(SRCDIR)mangle-cpp.o : $(SRCDIR)mangle-cpp.cpp # Pass $(CFLAGS) to get -m32 or -m64 as required $(CXX) -c $(CFLAGS) -o $@ $^ From c92048fdb46a3fca836c761a8194e1dec84dfaa0 Mon Sep 17 00:00:00 2001 From: coderJeff Date: Sat, 13 Jul 2019 08:46:52 -0400 Subject: [PATCH 2/4] fbc: global overloaded operator procs need "_Z" mangling prefix --- changelog.txt | 1 + src/compiler/symb-mangling.bas | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 55a1ba52d4..00ecc8f5a6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -53,6 +53,7 @@ Version 1.07.0 - fbc uses '-march=armv8-a' instead of invalid option '-march=aarch64' when passing options to gcc/LLVM (czsgaba) - rtlib: sys/io.h incorrectly included on systems that do not provide it. It is used only for x86, x86_64 and is unnecessary for all other linux targets (armhf ,arm64, mips ....) - SELECT CASE AS CONST checks for ranges that would produce unreasonably large jump tables (greater than 8192 entries) +- sf.net #907: global overloaded operator procs need "_Z" mangling prefix Version 1.06.0 diff --git a/src/compiler/symb-mangling.bas b/src/compiler/symb-mangling.bas index 5b834a9844..8ed77502c6 100644 --- a/src/compiler/symb-mangling.bas +++ b/src/compiler/symb-mangling.bas @@ -1195,7 +1195,8 @@ private sub hMangleProc( byval sym as FBSYMBOL ptr ) end if '' C++ prefix - if( docpp ) then + '' global overloaded operators need the prefix + if( docpp or symbIsOperator( sym ) ) then mangled += "_Z" end if From 48d50664e67652c1ca6eb9bbabb5ec5dd674b162 Mon Sep 17 00:00:00 2001 From: coderJeff Date: Sun, 7 Jul 2019 11:15:55 -0400 Subject: [PATCH 3/4] fbc: add tests for c++ mangling/call conventions for procedures - test fbc default, cdecl, and stdcall calling conventions - test in extern "c" and extern "c++" blocks --- tests/cpp/call-cpp.cpp | 345 +++++++++++++++++++++++++++++++++++++++++ tests/cpp/call-fbc.bas | 157 +++++++++++++++++++ tests/cpp/call.bmk | 10 ++ 3 files changed, 512 insertions(+) create mode 100644 tests/cpp/call-cpp.cpp create mode 100644 tests/cpp/call-fbc.bas create mode 100644 tests/cpp/call.bmk diff --git a/tests/cpp/call-cpp.cpp b/tests/cpp/call-cpp.cpp new file mode 100644 index 0000000000..f49c87b1d6 --- /dev/null +++ b/tests/cpp/call-cpp.cpp @@ -0,0 +1,345 @@ +// implementation for call-fbc.bas + +// each operation records call information +// in static variables, and we use getters +// to retrieve it back to fbc side + +#define NULL 0 +static const void * ptr1 = NULL; +static const void * ptr2 = NULL; +static const void * ptr3 = NULL; +static char msg1[100]; // check message + +void setMsg( const char* msg ) { + char *s = msg1; + while( *msg ) + *s++ = *msg++; + *s = *msg; +} + +void resetChecks() { + ptr1 = NULL; + ptr2 = NULL; + ptr3 = NULL; + setMsg( "" ); +} + +const void* getPtr1() { + return ptr1; +} + +const void* getPtr2() { + return ptr2; +} + +const void* getPtr3() { + return ptr3; +} + +char* getMsg1() { + return msg1; +} + +class UDT +{ + public: + int value; +}; + +extern "C" { +void sub1_c_default( UDT const& a ); +void sub1_c_cdecl( UDT const& a ) __attribute__((cdecl)); +void sub1_c_stdcall( UDT const& a ) __attribute__((stdcall)); +UDT func1_c_default( UDT const& a ); +UDT func1_c_cdecl( UDT const& a ) __attribute__((cdecl)); +UDT func1_c_stdcall( UDT const& a ) __attribute__((stdcall)); + +void sub2_c_default( UDT const& a, UDT const& b ); +void sub2_c_cdecl( UDT const& a, UDT const& b ) __attribute__((cdecl)); +void sub2_c_stdcall( UDT const& a, UDT const& b ) __attribute__((stdcall)); +UDT func2_c_default( UDT const& a, UDT const& b ); +UDT func2_c_cdecl( UDT const& a, UDT const& b ) __attribute__((cdecl)); +UDT func2_c_stdcall( UDT const& a, UDT const& b ) __attribute__((stdcall)); + +void sub3_c_default( UDT const& a, UDT const& b, UDT const& c ); +void sub3_c_cdecl( UDT const& a, UDT const& b, UDT const& c ) __attribute__((cdecl)); +void sub3_c_stdcall( UDT const& a, UDT const& b, UDT const& c ) __attribute__((stdcall)); +UDT func3_c_default( UDT const& a, UDT const& b, UDT const& c ); +UDT func3_c_cdecl( UDT const& a, UDT const& b, UDT const& c ) __attribute__((cdecl)); +UDT func3_c_stdcall( UDT const& a, UDT const& b, UDT const& c ) __attribute__((stdcall)); +} + +void sub1_cpp_default( UDT const& a ); +void sub1_cpp_cdecl( UDT const& a ) __attribute__((cdecl)); +void sub1_cpp_stdcall( UDT const& a ) __attribute__((stdcall)); +UDT func1_cpp_default( UDT const& a ); +UDT func1_cpp_cdecl( UDT const& a ) __attribute__((cdecl)); +UDT func1_cpp_stdcall( UDT const& a ) __attribute__((stdcall)); + +void sub2_cpp_default( UDT const& a, UDT const& b ); +void sub2_cpp_cdecl( UDT const& a, UDT const& b ) __attribute__((cdecl)); +void sub2_cpp_stdcall( UDT const& a, UDT const& b ) __attribute__((stdcall)); +UDT func2_cpp_default( UDT const& a, UDT const& b ); +UDT func2_cpp_cdecl( UDT const& a, UDT const& b ) __attribute__((cdecl)); +UDT func2_cpp_stdcall( UDT const& a, UDT const& b ) __attribute__((stdcall)); + +void sub3_cpp_default( UDT const& a, UDT const& b, UDT const& c ); +void sub3_cpp_cdecl( UDT const& a, UDT const& b, UDT const& c ) __attribute__((cdecl)); +void sub3_cpp_stdcall( UDT const& a, UDT const& b, UDT const& c ) __attribute__((stdcall)); +UDT func3_cpp_default( UDT const& a, UDT const& b, UDT const& c ); +UDT func3_cpp_cdecl( UDT const& a, UDT const& b, UDT const& c ) __attribute__((cdecl)); +UDT func3_cpp_stdcall( UDT const& a, UDT const& b, UDT const& c ) __attribute__((stdcall)); + +extern "C" { +void sub1_c_default( UDT const& a ) { + ptr1 = &a; + setMsg( "sub1_c_default" ); +} + +void sub1_c_cdecl( UDT const& a ) { + ptr1 = &a; + setMsg( "sub1_c_cdecl" ); +} + +void sub1_c_stdcall( UDT const& a ) { + ptr1 = &a; + setMsg( "sub1_c_stdcall" ); +} + +UDT func1_c_default( UDT const& a ) { + UDT ret = {0}; + ptr1 = &a; + setMsg( "func1_c_default" ); + return ret; +} + +UDT func1_c_cdecl( UDT const& a ) { + UDT ret = {0}; + ptr1 = &a; + setMsg( "func1_c_cdecl" ); + return ret; +} + +UDT func1_c_stdcall( UDT const& a ) { + UDT ret = {0}; + ptr1 = &a; + setMsg( "func1_c_stdcall" ); + return ret; +} + +void sub2_c_default( UDT const& a, UDT const& b ) { + ptr1 = &a; + ptr2 = &b; + setMsg( "sub2_c_default" ); +} + +void sub2_c_cdecl( UDT const& a, UDT const& b ) { + ptr1 = &a; + ptr2 = &b; + setMsg( "sub2_c_cdecl" ); +} + +void sub2_c_stdcall( UDT const& a, UDT const& b ) { + ptr1 = &a; + ptr2 = &b; + setMsg( "sub2_c_stdcall" ); +} + +UDT func2_c_default( UDT const& a, UDT const& b ) { + UDT ret = {0}; + ptr1 = &a; + ptr2 = &b; + setMsg( "func2_c_default" ); + return ret; +} + +UDT func2_c_cdecl( UDT const& a, UDT const& b ) { + UDT ret = {0}; + ptr1 = &a; + ptr2 = &b; + setMsg( "func2_c_cdecl" ); + return ret; +} + +UDT func2_c_stdcall( UDT const& a, UDT const& b ) { + UDT ret = {0}; + ptr1 = &a; + ptr2 = &b; + setMsg( "func2_c_stdcall" ); + return ret; +} + +void sub3_c_default( UDT const& a, UDT const& b, UDT const& c ) { + ptr1 = &a; + ptr2 = &b; + ptr3 = &c; + setMsg( "sub3_c_default" ); +} + +void sub3_c_cdecl( UDT const& a, UDT const& b, UDT const& c ) { + ptr1 = &a; + ptr2 = &b; + ptr3 = &c; + setMsg( "sub3_c_cdecl" ); +} + +void sub3_c_stdcall( UDT const& a, UDT const& b, UDT const& c ) { + ptr1 = &a; + ptr2 = &b; + ptr3 = &c; + setMsg( "sub3_c_stdcall" ); +} + +UDT func3_c_default( UDT const& a, UDT const& b, UDT const& c ) { + UDT ret = {0}; + ptr1 = &a; + ptr2 = &b; + ptr3 = &c; + setMsg( "func3_c_default" ); + return ret; +} + +UDT func3_c_cdecl( UDT const& a, UDT const& b, UDT const& c ) { + UDT ret = {0}; + ptr1 = &a; + ptr2 = &b; + ptr3 = &c; + setMsg( "func3_c_cdecl" ); + return ret; +} + +UDT func3_c_stdcall( UDT const& a, UDT const& b, UDT const& c ) { + UDT ret = {0}; + ptr1 = &a; + ptr2 = &b; + ptr3 = &c; + setMsg( "func3_c_stdcall" ); + return ret; +} +} // extern "C" + +void sub1_cpp_default( UDT const& a ) { + ptr1 = &a; + setMsg( "sub1_cpp_default" ); +} + +void sub1_cpp_cdecl( UDT const& a ) { + ptr1 = &a; + setMsg( "sub1_cpp_cdecl" ); +} + +void sub1_cpp_stdcall( UDT const& a ) { + ptr1 = &a; + setMsg( "sub1_cpp_stdcall" ); +} + +UDT func1_cpp_default( UDT const& a ) { + UDT ret = {0}; + ptr1 = &a; + setMsg( "func1_cpp_default" ); + return ret; +} + +UDT func1_cpp_cdecl( UDT const& a ) { + UDT ret = {0}; + ptr1 = &a; + setMsg( "func1_cpp_cdecl" ); + return ret; +} + +UDT func1_cpp_stdcall( UDT const& a ) { + UDT ret = {0}; + ptr1 = &a; + setMsg( "func1_cpp_stdcall" ); + return ret; +} + +void sub2_cpp_default( UDT const& a, UDT const& b ) { + ptr1 = &a; + ptr2 = &b; + setMsg( "sub2_cpp_default" ); +} + +void sub2_cpp_cdecl( UDT const& a, UDT const& b ) { + ptr1 = &a; + ptr2 = &b; + setMsg( "sub2_cpp_cdecl" ); +} + +void sub2_cpp_stdcall( UDT const& a, UDT const& b ) { + ptr1 = &a; + ptr2 = &b; + setMsg( "sub2_cpp_stdcall" ); +} + +UDT func2_cpp_default( UDT const& a, UDT const& b ) { + UDT ret = {0}; + ptr1 = &a; + ptr2 = &b; + setMsg( "func2_cpp_default" ); + return ret; +} + +UDT func2_cpp_cdecl( UDT const& a, UDT const& b ) { + UDT ret = {0}; + ptr1 = &a; + ptr2 = &b; + setMsg( "func2_cpp_cdecl" ); + return ret; +} + +UDT func2_cpp_stdcall( UDT const& a, UDT const& b ) { + UDT ret = {0}; + ptr1 = &a; + ptr2 = &b; + setMsg( "func2_cpp_stdcall" ); + return ret; +} + +void sub3_cpp_default( UDT const& a, UDT const& b, UDT const& c ) { + ptr1 = &a; + ptr2 = &b; + ptr3 = &c; + setMsg( "sub3_cpp_default" ); +} + +void sub3_cpp_cdecl( UDT const& a, UDT const& b, UDT const& c ) { + ptr1 = &a; + ptr2 = &b; + ptr3 = &c; + setMsg( "sub3_cpp_cdecl" ); +} + +void sub3_cpp_stdcall( UDT const& a, UDT const& b, UDT const& c ) { + ptr1 = &a; + ptr2 = &b; + ptr3 = &c; + setMsg( "sub3_cpp_stdcall" ); +} + +UDT func3_cpp_default( UDT const& a, UDT const& b, UDT const& c ) { + UDT ret = {0}; + ptr1 = &a; + ptr2 = &b; + ptr3 = &c; + setMsg( "func3_cpp_default" ); + return ret; +} + +UDT func3_cpp_cdecl( UDT const& a, UDT const& b, UDT const& c ) { + UDT ret = {0}; + ptr1 = &a; + ptr2 = &b; + ptr3 = &c; + setMsg( "func3_cpp_cdecl" ); + return ret; +} + +UDT func3_cpp_stdcall( UDT const& a, UDT const& b, UDT const& c ) { + UDT ret = {0}; + ptr1 = &a; + ptr2 = &b; + ptr3 = &c; + setMsg( "func3_cpp_stdcall" ); + return ret; +} diff --git a/tests/cpp/call-fbc.bas b/tests/cpp/call-fbc.bas new file mode 100644 index 0000000000..bf6a8f5532 --- /dev/null +++ b/tests/cpp/call-fbc.bas @@ -0,0 +1,157 @@ +' TEST_MODE : MULTI_MODULE_TEST + +'' test mapping of mangling and calling convention +'' between fbc and c/c++ class procedures + +'' helper macro to track progress +#define DLOG( msg ) '' print #msg + +extern "c++" + '' getters to retrieve call information + '' from the c++ side + declare sub resetChecks() + declare function getPtr1() as any ptr + declare function getPtr2() as any ptr + declare function getPtr3() as any ptr + declare function getMsg1() as zstring ptr +end extern + +type UDT + value as long +end type + +extern "c" + declare sub sub1_c_default( byref a as const UDT ) + declare sub sub1_c_cdecl cdecl( byref a as const UDT ) + declare sub sub1_c_stdcall stdcall( byref a as const UDT ) + declare function func1_c_default( byref a as const UDT ) as UDT + declare function func1_c_cdecl cdecl( byref a as const UDT ) as UDT + declare function func1_c_stdcall stdcall( byref a as const UDT ) as UDT + + declare sub sub2_c_default( byref a as const UDT, byref b as const UDT ) + declare sub sub2_c_cdecl cdecl( byref a as const UDT, byref b as const UDT ) + declare sub sub2_c_stdcall stdcall( byref a as const UDT, byref b as const UDT ) + declare function func2_c_default( byref a as const UDT, byref b as const UDT ) as UDT + declare function func2_c_cdecl cdecl( byref a as const UDT, byref b as const UDT ) as UDT + declare function func2_c_stdcall stdcall( byref a as const UDT, byref b as const UDT ) as UDT + + declare sub sub3_c_default( byref a as const UDT, byref b as const UDT, byref c as const UDT ) + declare sub sub3_c_cdecl cdecl( byref a as const UDT, byref b as const UDT, byref c as const UDT ) + declare sub sub3_c_stdcall stdcall( byref a as const UDT, byref b as const UDT, byref c as const UDT ) + declare function func3_c_default( byref a as const UDT, byref b as const UDT, byref c as const UDT ) as UDT + declare function func3_c_cdecl cdecl( byref a as const UDT, byref b as const UDT, byref c as const UDT ) as UDT + declare function func3_c_stdcall stdcall( byref a as const UDT, byref b as const UDT, byref c as const UDT ) as UDT +end extern + +extern "c++" + declare sub sub1_cpp_default( byref a as const UDT ) + declare sub sub1_cpp_cdecl cdecl( byref a as const UDT ) + declare sub sub1_cpp_stdcall stdcall( byref a as const UDT ) + declare function func1_cpp_default( byref a as const UDT ) as UDT + declare function func1_cpp_cdecl cdecl( byref a as const UDT ) as UDT + declare function func1_cpp_stdcall stdcall( byref a as const UDT ) as UDT + + declare sub sub2_cpp_default( byref a as const UDT, byref b as const UDT ) + declare sub sub2_cpp_cdecl cdecl( byref a as const UDT, byref b as const UDT ) + declare sub sub2_cpp_stdcall stdcall( byref a as const UDT, byref b as const UDT ) + declare function func2_cpp_default( byref a as const UDT, byref b as const UDT ) as UDT + declare function func2_cpp_cdecl cdecl( byref a as const UDT, byref b as const UDT ) as UDT + declare function func2_cpp_stdcall stdcall( byref a as const UDT, byref b as const UDT ) as UDT + + declare sub sub3_cpp_default( byref a as const UDT, byref b as const UDT, byref c as const UDT ) + declare sub sub3_cpp_cdecl cdecl( byref a as const UDT, byref b as const UDT, byref c as const UDT ) + declare sub sub3_cpp_stdcall stdcall( byref a as const UDT, byref b as const UDT, byref c as const UDT ) + declare function func3_cpp_default( byref a as const UDT, byref b as const UDT, byref c as const UDT ) as UDT + declare function func3_cpp_cdecl cdecl( byref a as const UDT, byref b as const UDT, byref c as const UDT ) as UDT + declare function func3_cpp_stdcall stdcall( byref a as const UDT, byref b as const UDT, byref c as const UDT ) as UDT +end extern + +#macro chksub( count, n ) + DLOG( n ) + resetChecks() + scope + #if count = 1 + dim a as UDT + n( a ) + assert( @a = getPtr1() ) + #elseif count = 2 + dim a as UDT, b as UDT + n( a, b ) + assert( @a = getPtr1() ) + assert( @b = getPtr2() ) + #else + dim a as UDT, b as UDT, c as UDT + n( a, b, c ) + assert( @a = getPtr1() ) + assert( @b = getPtr2() ) + assert( @c = getPtr3() ) + #endif + assert( #n = *getMsg1() ) + end scope +#endmacro + +#macro chkfunc( count, n ) + DLOG( n ) + resetChecks() + scope + #if count = 1 + dim a as UDT, r as UDT + r = n( a ) + assert( @a = getPtr1() ) + #elseif count = 2 + dim a as UDT, b as UDT, r as UDT + r = n( a, b ) + assert( @a = getPtr1() ) + assert( @b = getPtr2() ) + #else + dim a as UDT, b as UDT, c as UDT, r as UDT + r = n( a, b, c ) + assert( @a = getPtr1() ) + assert( @b = getPtr2() ) + assert( @c = getPtr3() ) + #endif + assert( #n = *getMsg1() ) + end scope +#endmacro + +chksub( 1, sub1_c_default ) +chksub( 1, sub1_c_cdecl ) +chksub( 1, sub1_c_stdcall ) +chkfunc( 1, func1_c_default ) +chkfunc( 1, func1_c_cdecl ) +chkfunc( 1, func1_c_stdcall ) + +chksub( 1, sub1_cpp_default ) +chksub( 1, sub1_cpp_cdecl ) +chksub( 1, sub1_cpp_stdcall ) +chkfunc( 1, func1_cpp_default ) +chkfunc( 1, func1_cpp_cdecl ) +chkfunc( 1, func1_cpp_stdcall ) + +chksub( 2, sub2_c_default ) +chksub( 2, sub2_c_cdecl ) +chksub( 2, sub2_c_stdcall ) +chkfunc( 2, func2_c_default ) +chkfunc( 2, func2_c_cdecl ) +chkfunc( 2, func2_c_stdcall ) + +chksub( 2, sub2_cpp_default ) +chksub( 2, sub2_cpp_cdecl ) +chksub( 2, sub2_cpp_stdcall ) +chkfunc( 2, func2_cpp_default ) +chkfunc( 2, func2_cpp_cdecl ) +chkfunc( 2, func2_cpp_stdcall ) + +chksub( 3, sub3_c_default ) +chksub( 3, sub3_c_cdecl ) +chksub( 3, sub3_c_stdcall ) +chkfunc( 3, func3_c_default ) +chkfunc( 3, func3_c_cdecl ) +chkfunc( 3, func3_c_stdcall ) + +chksub( 3, sub3_cpp_default ) +chksub( 3, sub3_cpp_cdecl ) +chksub( 3, sub3_cpp_stdcall ) +chkfunc( 3, func3_cpp_default ) +chkfunc( 3, func3_cpp_cdecl ) +chkfunc( 3, func3_cpp_stdcall ) diff --git a/tests/cpp/call.bmk b/tests/cpp/call.bmk new file mode 100644 index 0000000000..07886fd107 --- /dev/null +++ b/tests/cpp/call.bmk @@ -0,0 +1,10 @@ +# TEST_MODE : MULTI_MODULE_OK + +MAIN := call-fbc.bas +SRCS := + +EXTRA_OBJS := call-cpp.o + +$(SRCDIR)call-cpp.o : $(SRCDIR)call-cpp.cpp + # Pass $(CFLAGS) to get -m32 or -m64 as required + $(CXX) -c $(CFLAGS) -o $@ $^ From 21d7f6f8ad30d71a2531b4336fe50863f64dbe02 Mon Sep 17 00:00:00 2001 From: coderJeff Date: Sun, 7 Jul 2019 11:16:20 -0400 Subject: [PATCH 4/4] fbc: add tests for c++ overloaded binary operator mangling and calling conventions --- tests/cpp/bop-cpp.cpp | 162 ++++++++++++++++++++++++++++++++++++++++++ tests/cpp/bop-fbc.bas | 124 ++++++++++++++++++++++++++++++++ tests/cpp/bop.bmk | 10 +++ 3 files changed, 296 insertions(+) create mode 100644 tests/cpp/bop-cpp.cpp create mode 100644 tests/cpp/bop-fbc.bas create mode 100644 tests/cpp/bop.bmk diff --git a/tests/cpp/bop-cpp.cpp b/tests/cpp/bop-cpp.cpp new file mode 100644 index 0000000000..64c2815de7 --- /dev/null +++ b/tests/cpp/bop-cpp.cpp @@ -0,0 +1,162 @@ +// implementation for bop-fbc.bas + +// each operation records call information +// in static variables, and we use getters +// to retrieve it back to fbc side + +#define NULL 0 +static const void * ptr1 = NULL; +static const void * ptr2 = NULL; +static char msg1[100]; // check message +static int val1 = 0; // current/lhs value +static int val2 = 0; // rhs value +static int val3 = 0; // result value + +void setMsg( const char* msg ) { + char *s = msg1; + while( *msg ) + *s++ = *msg++; + *s = *msg; +} + +void resetChecks() { + ptr1 = NULL; + ptr2 = NULL; + setMsg( "" ); +} + +const void* getPtr1() { + return ptr1; +} + +const void* getPtr2() { + return ptr2; +} + +char* getMsg1() { + return msg1; +} + +int getVal1() { + return val1; +} + +int getVal2() { + return val2; +} + +int getVal3() { + return val3; +} + +class UDT_DEFAULT +{ + public: + int value; +}; + +// by default fbc will be stdcall on windows and cdecl on linux +#ifdef __MINGW32__ +// warning !!! mingw specific +#define FBCALL __attribute__((stdcall)) +#else +#define FBCALL +#endif + +UDT_DEFAULT operator+( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) FBCALL; +UDT_DEFAULT operator-( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) FBCALL; +UDT_DEFAULT operator*( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) FBCALL; +UDT_DEFAULT operator/( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) FBCALL; +UDT_DEFAULT operator%( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) FBCALL; +UDT_DEFAULT operator<<( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) FBCALL; +UDT_DEFAULT operator>>( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) FBCALL; +UDT_DEFAULT operator&( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) FBCALL; +UDT_DEFAULT operator|( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) FBCALL; +UDT_DEFAULT operator^( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) FBCALL; + +class UDT_C_DEFAULT +{ + public: + int value; +}; + +extern "C" { +UDT_C_DEFAULT operator+( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ); +UDT_C_DEFAULT operator-( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ); +UDT_C_DEFAULT operator*( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ); +UDT_C_DEFAULT operator/( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ); +UDT_C_DEFAULT operator%( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ); +UDT_C_DEFAULT operator<<( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ); +UDT_C_DEFAULT operator>>( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ); +UDT_C_DEFAULT operator&( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ); +UDT_C_DEFAULT operator|( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ); +UDT_C_DEFAULT operator^( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ); +} + +class UDT_CPP_DEFAULT +{ + public: + int value; +}; + +UDT_CPP_DEFAULT operator+( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ); +UDT_CPP_DEFAULT operator-( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ); +UDT_CPP_DEFAULT operator*( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ); +UDT_CPP_DEFAULT operator/( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ); +UDT_CPP_DEFAULT operator%( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ); +UDT_CPP_DEFAULT operator<<( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ); +UDT_CPP_DEFAULT operator>>( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ); +UDT_CPP_DEFAULT operator&( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ); +UDT_CPP_DEFAULT operator|( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ); +UDT_CPP_DEFAULT operator^( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ); + +#define exec_bop( t, bop ) \ + t ret = {0}; \ + ptr1 = &lhs; \ + ptr2 = &rhs; \ + setMsg( #t " operator" #bop ); \ + val1 = lhs.value; \ + val2 = rhs.value; \ + val3 = lhs.value bop rhs.value; \ + ret.value = lhs.value bop rhs.value; \ + return ret; + +// default mangling (on fbc side), default calling convention + +UDT_DEFAULT operator+( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) { exec_bop( UDT_DEFAULT, + ) } +UDT_DEFAULT operator-( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) { exec_bop( UDT_DEFAULT, - ) } +UDT_DEFAULT operator*( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) { exec_bop( UDT_DEFAULT, * ) } +UDT_DEFAULT operator/( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) { exec_bop( UDT_DEFAULT, / ) } +UDT_DEFAULT operator%( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) { exec_bop( UDT_DEFAULT, % ) } +UDT_DEFAULT operator<<( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) { exec_bop( UDT_DEFAULT, << ) } +UDT_DEFAULT operator>>( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) { exec_bop( UDT_DEFAULT, >> ) } +UDT_DEFAULT operator&( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) { exec_bop( UDT_DEFAULT, & ) } +UDT_DEFAULT operator|( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) { exec_bop( UDT_DEFAULT, | ) } +UDT_DEFAULT operator^( UDT_DEFAULT const& lhs, UDT_DEFAULT const& rhs ) { exec_bop( UDT_DEFAULT, ^ ) } + +// C mangling (on fbc side), default calling convention +extern "C" { +UDT_C_DEFAULT operator+( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ){exec_bop( UDT_C_DEFAULT, + ) } +UDT_C_DEFAULT operator-( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ) { exec_bop( UDT_C_DEFAULT, - ) } +UDT_C_DEFAULT operator*( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ) { exec_bop( UDT_C_DEFAULT, * ) } +UDT_C_DEFAULT operator/( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ) { exec_bop( UDT_C_DEFAULT, / ) } +UDT_C_DEFAULT operator%( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ) { exec_bop( UDT_C_DEFAULT, % ) } +UDT_C_DEFAULT operator<<( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ) { exec_bop( UDT_C_DEFAULT, << ) } +UDT_C_DEFAULT operator>>( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ) { exec_bop( UDT_C_DEFAULT, >> ) } +UDT_C_DEFAULT operator&( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ) { exec_bop( UDT_C_DEFAULT, & ) } +UDT_C_DEFAULT operator|( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ) { exec_bop( UDT_C_DEFAULT, | ) } +UDT_C_DEFAULT operator^( UDT_C_DEFAULT const& lhs, UDT_C_DEFAULT const& rhs ) { exec_bop( UDT_C_DEFAULT, ^ ) } +} // extern "C" + +// c++ mangling (on fbc side), default calling convention + +UDT_CPP_DEFAULT operator+( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ) { exec_bop( UDT_CPP_DEFAULT, + ) } +UDT_CPP_DEFAULT operator-( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ) { exec_bop( UDT_CPP_DEFAULT, - ) } +UDT_CPP_DEFAULT operator*( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ) { exec_bop( UDT_CPP_DEFAULT, * ) } +UDT_CPP_DEFAULT operator/( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ) { exec_bop( UDT_CPP_DEFAULT, / ) } +UDT_CPP_DEFAULT operator%( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ) { exec_bop( UDT_CPP_DEFAULT, % ) } +UDT_CPP_DEFAULT operator<<( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ) { exec_bop( UDT_CPP_DEFAULT, << ) } +UDT_CPP_DEFAULT operator>>( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ) { exec_bop( UDT_CPP_DEFAULT, >> ) } +UDT_CPP_DEFAULT operator&( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ) { exec_bop( UDT_CPP_DEFAULT, & ) } +UDT_CPP_DEFAULT operator|( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ) { exec_bop( UDT_CPP_DEFAULT, | ) } +UDT_CPP_DEFAULT operator^( UDT_CPP_DEFAULT const& lhs, UDT_CPP_DEFAULT const& rhs ) { exec_bop( UDT_CPP_DEFAULT, ^ ) } diff --git a/tests/cpp/bop-fbc.bas b/tests/cpp/bop-fbc.bas new file mode 100644 index 0000000000..6d0b8e6b64 --- /dev/null +++ b/tests/cpp/bop-fbc.bas @@ -0,0 +1,124 @@ +' TEST_MODE : MULTI_MODULE_TEST + +'' test mapping of mangling and calling convention +'' of global overloaded operators +'' between c/c++ and fbc + +'' helper macro to track progress +#define DLOG( msg ) '' print #msg + +extern "c++" + '' getters to retrieve call information + '' from the c++ side + declare sub resetChecks() + declare function getPtr1() as any ptr + declare function getPtr2() as any ptr + declare function getMsg1() as zstring ptr + declare function getVal1() as long + declare function getVal2() as long + declare function getVal3() as long +end extern + +'' default mangling, default calling convention +type UDT_DEFAULT + value as long +end type + +'' fbc will mangle a @N suffix by default +declare operator +( byref lhs as const UDT_DEFAULT, byref rhs as const UDT_DEFAULT ) as UDT_DEFAULT +declare operator -( byref lhs as const UDT_DEFAULT, byref rhs as const UDT_DEFAULT ) as UDT_DEFAULT +declare operator *( byref lhs as const UDT_DEFAULT, byref rhs as const UDT_DEFAULT ) as UDT_DEFAULT +declare operator /( byref lhs as const UDT_DEFAULT, byref rhs as const UDT_DEFAULT ) as UDT_DEFAULT +declare operator mod( byref lhs as const UDT_DEFAULT, byref rhs as const UDT_DEFAULT ) as UDT_DEFAULT +declare operator shl( byref lhs as const UDT_DEFAULT, byref rhs as const UDT_DEFAULT ) as UDT_DEFAULT +declare operator shr( byref lhs as const UDT_DEFAULT, byref rhs as const UDT_DEFAULT ) as UDT_DEFAULT +declare operator and( byref lhs as const UDT_DEFAULT, byref rhs as const UDT_DEFAULT ) as UDT_DEFAULT +declare operator or ( byref lhs as const UDT_DEFAULT, byref rhs as const UDT_DEFAULT ) as UDT_DEFAULT +declare operator xor( byref lhs as const UDT_DEFAULT, byref rhs as const UDT_DEFAULT ) as UDT_DEFAULT + + +'' extern "c", default calling convention +type UDT_C_DEFAULT + value as long +end type + +extern "c" + declare operator +( byref lhs as const UDT_C_DEFAULT, byref rhs as const UDT_C_DEFAULT ) as UDT_C_DEFAULT + declare operator -( byref lhs as const UDT_C_DEFAULT, byref rhs as const UDT_C_DEFAULT ) as UDT_C_DEFAULT + declare operator *( byref lhs as const UDT_C_DEFAULT, byref rhs as const UDT_C_DEFAULT ) as UDT_C_DEFAULT + declare operator /( byref lhs as const UDT_C_DEFAULT, byref rhs as const UDT_C_DEFAULT ) as UDT_C_DEFAULT + declare operator mod( byref lhs as const UDT_C_DEFAULT, byref rhs as const UDT_C_DEFAULT ) as UDT_C_DEFAULT + declare operator shl( byref lhs as const UDT_C_DEFAULT, byref rhs as const UDT_C_DEFAULT ) as UDT_C_DEFAULT + declare operator shr( byref lhs as const UDT_C_DEFAULT, byref rhs as const UDT_C_DEFAULT ) as UDT_C_DEFAULT + declare operator and( byref lhs as const UDT_C_DEFAULT, byref rhs as const UDT_C_DEFAULT ) as UDT_C_DEFAULT + declare operator or ( byref lhs as const UDT_C_DEFAULT, byref rhs as const UDT_C_DEFAULT ) as UDT_C_DEFAULT + declare operator xor( byref lhs as const UDT_C_DEFAULT, byref rhs as const UDT_C_DEFAULT ) as UDT_C_DEFAULT +end extern + + +'' extern "c++", default calling convention +type UDT_CPP_DEFAULT + value as long +end type + +extern "c++" + declare operator +( byref lhs as const UDT_CPP_DEFAULT, byref rhs as const UDT_CPP_DEFAULT ) as UDT_CPP_DEFAULT + declare operator -( byref lhs as const UDT_CPP_DEFAULT, byref rhs as const UDT_CPP_DEFAULT ) as UDT_CPP_DEFAULT + declare operator *( byref lhs as const UDT_CPP_DEFAULT, byref rhs as const UDT_CPP_DEFAULT ) as UDT_CPP_DEFAULT + declare operator /( byref lhs as const UDT_CPP_DEFAULT, byref rhs as const UDT_CPP_DEFAULT ) as UDT_CPP_DEFAULT + declare operator mod( byref lhs as const UDT_CPP_DEFAULT, byref rhs as const UDT_CPP_DEFAULT ) as UDT_CPP_DEFAULT + declare operator shl( byref lhs as const UDT_CPP_DEFAULT, byref rhs as const UDT_CPP_DEFAULT ) as UDT_CPP_DEFAULT + declare operator shr( byref lhs as const UDT_CPP_DEFAULT, byref rhs as const UDT_CPP_DEFAULT ) as UDT_CPP_DEFAULT + declare operator and( byref lhs as const UDT_CPP_DEFAULT, byref rhs as const UDT_CPP_DEFAULT ) as UDT_CPP_DEFAULT + declare operator or ( byref lhs as const UDT_CPP_DEFAULT, byref rhs as const UDT_CPP_DEFAULT ) as UDT_CPP_DEFAULT + declare operator xor( byref lhs as const UDT_CPP_DEFAULT, byref rhs as const UDT_CPP_DEFAULT ) as UDT_CPP_DEFAULT +end extern + +#macro chkbop( op, t, m1, arg1, arg2, result ) + DLOG( n ) + resetChecks() + scope + dim a as t = ( arg1 ) + dim b as t = ( arg2 ) + dim r as t + r = a op b + assert( m1 = *getMsg1() ) + assert( @a = getPtr1() ) + assert( @b = getPtr2() ) + assert( r.value = result ) + assert( r.value = getVal3() ) + end scope +#endmacro + +chkbop( +, UDT_DEFAULT, "UDT_DEFAULT operator+", 5, 7, 12 ) +chkbop( -, UDT_DEFAULT, "UDT_DEFAULT operator-", 5, 7, -2 ) +chkbop( *, UDT_DEFAULT, "UDT_DEFAULT operator*", 5, 7, 35 ) +chkbop( /, UDT_DEFAULT, "UDT_DEFAULT operator/", 35, 7, 5 ) +chkbop( mod, UDT_DEFAULT, "UDT_DEFAULT operator%", 16, 5, 1 ) +chkbop( shl, UDT_DEFAULT, "UDT_DEFAULT operator<<", 16, 2, 64 ) +chkbop( shr, UDT_DEFAULT, "UDT_DEFAULT operator>>", 16, 2, 4 ) +chkbop( and, UDT_DEFAULT, "UDT_DEFAULT operator&", &b1100, &b1010, &b1000 ) +chkbop( or , UDT_DEFAULT, "UDT_DEFAULT operator|", &b1100, &b1010, &b1110 ) +chkbop( xor, UDT_DEFAULT, "UDT_DEFAULT operator^", &b1100, &b1010, &b0110 ) + +chkbop( +, UDT_C_DEFAULT, "UDT_C_DEFAULT operator+", 5, 7, 12 ) +chkbop( -, UDT_C_DEFAULT, "UDT_C_DEFAULT operator-", 5, 7, -2 ) +chkbop( *, UDT_C_DEFAULT, "UDT_C_DEFAULT operator*", 5, 7, 35 ) +chkbop( /, UDT_C_DEFAULT, "UDT_C_DEFAULT operator/", 35, 7, 5 ) +chkbop( mod, UDT_C_DEFAULT, "UDT_C_DEFAULT operator%", 16, 5, 1 ) +chkbop( shl, UDT_C_DEFAULT, "UDT_C_DEFAULT operator<<", 16, 2, 64 ) +chkbop( shr, UDT_C_DEFAULT, "UDT_C_DEFAULT operator>>", 16, 2, 4 ) +chkbop( and, UDT_C_DEFAULT, "UDT_C_DEFAULT operator&", &b1100, &b1010, &b1000 ) +chkbop( or , UDT_C_DEFAULT, "UDT_C_DEFAULT operator|", &b1100, &b1010, &b1110 ) +chkbop( xor, UDT_C_DEFAULT, "UDT_C_DEFAULT operator^", &b1100, &b1010, &b0110 ) + +chkbop( +, UDT_CPP_DEFAULT, "UDT_CPP_DEFAULT operator+", 5, 7, 12 ) +chkbop( -, UDT_CPP_DEFAULT, "UDT_CPP_DEFAULT operator-", 5, 7, -2 ) +chkbop( *, UDT_CPP_DEFAULT, "UDT_CPP_DEFAULT operator*", 5, 7, 35 ) +chkbop( /, UDT_CPP_DEFAULT, "UDT_CPP_DEFAULT operator/", 35, 7, 5 ) +chkbop( mod, UDT_CPP_DEFAULT, "UDT_CPP_DEFAULT operator%", 16, 5, 1 ) +chkbop( shl, UDT_CPP_DEFAULT, "UDT_CPP_DEFAULT operator<<", 16, 2, 64 ) +chkbop( shr, UDT_CPP_DEFAULT, "UDT_CPP_DEFAULT operator>>", 16, 2, 4 ) +chkbop( and, UDT_CPP_DEFAULT, "UDT_CPP_DEFAULT operator&", &b1100, &b1010, &b1000 ) +chkbop( or , UDT_CPP_DEFAULT, "UDT_CPP_DEFAULT operator|", &b1100, &b1010, &b1110 ) +chkbop( xor, UDT_CPP_DEFAULT, "UDT_CPP_DEFAULT operator^", &b1100, &b1010, &b0110 ) diff --git a/tests/cpp/bop.bmk b/tests/cpp/bop.bmk new file mode 100644 index 0000000000..475f785c76 --- /dev/null +++ b/tests/cpp/bop.bmk @@ -0,0 +1,10 @@ +# TEST_MODE : MULTI_MODULE_OK + +MAIN := bop-fbc.bas +SRCS := + +EXTRA_OBJS := bop-cpp.o + +$(SRCDIR)bop-cpp.o : $(SRCDIR)bop-cpp.cpp + # Pass $(CFLAGS) to get -m32 or -m64 as required + $(CXX) -c $(CFLAGS) -o $@ $^