Skip to content

Commit 9e7bb2d

Browse files
committed
Skip functions that pass arrays or structs by value
1 parent 67ef777 commit 9e7bb2d

File tree

10 files changed

+102
-5
lines changed

10 files changed

+102
-5
lines changed

bindgen/ir/Function.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "Function.h"
22
#include "../Utils.h"
3+
#include "Struct.h"
34

45
Parameter::Parameter(std::string name, std::shared_ptr<Type> type)
56
: TypeAndName(std::move(name), type) {}
@@ -71,3 +72,23 @@ Function::~Function() {
7172
delete parameter;
7273
}
7374
}
75+
76+
bool Function::isLegalScalaNativeFunction() const {
77+
/* structs and unions are used only through corresponding TypeDefs so it's
78+
* okay to cast only to TypeDef.
79+
* Return type and parameters types cannot be array types because array type
80+
* in this case is always represented as a pointer to element type */
81+
auto *typeDef = dynamic_cast<TypeDef *>(retType.get());
82+
if (typeDef &&
83+
(typeDef->isAliasFor<Struct>() || typeDef->isAliasFor<ArrayType>())) {
84+
return false;
85+
}
86+
for (const auto &parameter : parameters) {
87+
typeDef = dynamic_cast<TypeDef *>(parameter->getType().get());
88+
if (typeDef && (typeDef->isAliasFor<Struct>() ||
89+
typeDef->isAliasFor<ArrayType>())) {
90+
return false;
91+
}
92+
}
93+
return true;
94+
}

bindgen/ir/Function.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define SCALA_NATIVE_BINDGEN_FUNCTION_H
33

44
#include "TypeAndName.h"
5+
#include "TypeDef.h"
56
#include <llvm/Support/raw_ostream.h>
67
#include <string>
78
#include <vector>
@@ -27,6 +28,12 @@ class Function {
2728

2829
void setScalaName(std::string scalaName);
2930

31+
/**
32+
* @return true if the function does not use values of structs or arrays
33+
* (note: unions are represented as arrays)
34+
*/
35+
bool isLegalScalaNativeFunction() const;
36+
3037
private:
3138
std::string getVarargsParameterName() const;
3239

bindgen/ir/IR.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,15 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
122122
}
123123

124124
for (const auto &func : ir.functions) {
125-
s << *func;
125+
if (func->isLegalScalaNativeFunction()) {
126+
s << *func;
127+
} else {
128+
llvm::errs()
129+
<< "Warning: Function " << func->getName()
130+
<< " is skipped because Scala Native does not support "
131+
"passing structs and arrays by value.\n";
132+
llvm::errs().flush();
133+
}
126134
}
127135

128136
s << "}\n\n";

bindgen/ir/TypeDef.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,27 @@ class TypeDef : public TypeAndName, public Type {
2323

2424
std::shared_ptr<Location> getLocation() const;
2525

26+
/**
27+
* @tparam T Type
28+
* @return true if the typedef is an alias for give type directly or through
29+
* a chain of typedefs
30+
*/
31+
template <typename T> bool isAliasFor() const {
32+
/* if body is moved to cpp file then linker gives undefined symbols
33+
* error */
34+
if (!type) {
35+
return false;
36+
}
37+
if (dynamic_cast<T *>(type.get())) {
38+
return true;
39+
}
40+
auto *typeDef = dynamic_cast<TypeDef *>(type.get());
41+
if (typeDef) {
42+
return typeDef->isAliasFor<T>();
43+
}
44+
return false;
45+
}
46+
2647
private:
2748
/**
2849
* nullptr if type is generated.

tests/samples/Function.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,21 @@ char one_arg(int a);
44
void *two_args(float a, int b);
55
double anonymous_args(float, int);
66
double variadic_args(double a, char *varArgs, ...);
7+
8+
struct s {
9+
int val;
10+
};
11+
12+
void acceptsStructValue(struct s); // function is skipped with warning
13+
14+
typedef struct s s;
15+
16+
s returnsStructValue(); // function is skipped with warning
17+
18+
union u {
19+
int a;
20+
};
21+
22+
void acceptsUnionValue(union u); // function is skipped with warning
23+
24+
void acceptsArray(int[10]); // it's okay because the type is pointer to int

tests/samples/Function.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,32 @@ import scala.scalanative.native._
66
@native.link("bindgentests")
77
@native.extern
88
object Function {
9+
type struct_s = native.CStruct1[native.CInt]
10+
type s = struct_s
11+
type union_u = native.CArray[Byte, native.Nat._4]
912
def no_args(): native.CInt = native.extern
1013
def void_arg(): native.CFloat = native.extern
1114
def one_arg(a: native.CInt): native.CChar = native.extern
1215
def two_args(a: native.CFloat, b: native.CInt): native.Ptr[Byte] = native.extern
1316
def anonymous_args(anonymous0: native.CFloat, anonymous1: native.CInt): native.CDouble = native.extern
1417
def variadic_args(a: native.CDouble, varArgs: native.CString, varArgs0: native.CVararg*): native.CDouble = native.extern
18+
def acceptsArray(anonymous0: native.Ptr[native.CInt]): Unit = native.extern
1519
}
20+
21+
import Function._
22+
23+
object FunctionHelpers {
24+
25+
implicit class struct_s_ops(val p: native.Ptr[struct_s]) extends AnyVal {
26+
def `val`: native.CInt = !p._1
27+
def `val_=`(value: native.CInt): Unit = !p._1 = value
28+
}
29+
30+
def struct_s()(implicit z: native.Zone): native.Ptr[struct_s] = native.alloc[struct_s]
31+
32+
implicit class union_u_pos(val p: native.Ptr[union_u]) extends AnyVal {
33+
def a: native.Ptr[native.CInt] = p.cast[native.Ptr[native.CInt]]
34+
def a_=(value: native.CInt): Unit = !p.cast[native.Ptr[native.CInt]] = value
35+
}
36+
}
37+

tests/samples/PrivateMembers.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void __privateFunction();
3838

3939
// functions that should not be removed:
4040
__private_type *getPrivateType();
41-
void usesPrivateUnion(union __unionWithPrivateName);
41+
void usesPrivateUnion(union __unionWithPrivateName *);
4242
void usesPrivateStruct(struct structWithPrivateType *, struct normalStruct *);
4343
void usesPrivateEnum(enum __privateEnum *);
4444

tests/samples/PrivateMembers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ object PrivateMembers {
1919
type privateStructWithTypedefPtr = native.Ptr[struct_privateStructWithTypedef]
2020
def getTypeThatUsesPrivateTypes(): pid_t = native.extern
2121
def getPrivateType(): native.Ptr[__private_type] = native.extern
22-
def usesPrivateUnion(anonymous0: union___unionWithPrivateName): Unit = native.extern
22+
def usesPrivateUnion(anonymous0: native.Ptr[union___unionWithPrivateName]): Unit = native.extern
2323
def usesPrivateStruct(anonymous0: native.Ptr[struct_structWithPrivateType], anonymous1: native.Ptr[struct_normalStruct]): Unit = native.extern
2424
def usesPrivateEnum(anonymous0: native.Ptr[enum___privateEnum]): Unit = native.extern
2525
}

tests/samples/ReservedWords.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ union lazy {
2020

2121
typedef union lazy lazy;
2222

23-
type with(match sealed, var implicit, lazy forSome);
23+
type *with(match sealed, var implicit, lazy *forSome);
2424

2525
typedef match def;
2626
typedef struct {

tests/samples/ReservedWords.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ object ReservedWords {
1616
type `def` = `match`
1717
type struct_finally = native.CStruct2[`def`, `lazy`]
1818
type `finally` = struct_finally
19-
def `with`(`sealed`: `match`, `implicit`: native.Ptr[`match`], `forSome`: `lazy`): `type` = native.extern
19+
def `with`(`sealed`: `match`, `implicit`: native.Ptr[`match`], `forSome`: native.Ptr[`lazy`]): native.Ptr[`type`] = native.extern
2020
def `implicit`(`type`: native.Ptr[`finally`]): `match` = native.extern
2121
def _1(): Unit = native.extern
2222
}

0 commit comments

Comments
 (0)