Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/symb-mangling.bas
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
162 changes: 162 additions & 0 deletions tests/cpp/bop-cpp.cpp
Original file line number Diff line number Diff line change
@@ -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, ^ ) }
124 changes: 124 additions & 0 deletions tests/cpp/bop-fbc.bas
Original file line number Diff line number Diff line change
@@ -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 )
10 changes: 10 additions & 0 deletions tests/cpp/bop.bmk
Original file line number Diff line number Diff line change
@@ -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 $@ $^
Loading