Skip to content

Commit a5c00aa

Browse files
committed
Replace opaque type with CStruct0
Add comment line to incomplete types
1 parent 4ead1bc commit a5c00aa

File tree

18 files changed

+220
-32
lines changed

18 files changed

+220
-32
lines changed

bindgen/Utils.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,20 @@ template <typename T> static inline bool isAliasForType(Type *type) {
126126
return false;
127127
}
128128

129+
/**
130+
* @return true if typedef references opaque type directly or through a
131+
* chain of typedefs.
132+
*/
133+
static inline bool isAliasForOpaqueType(const Type *type) {
134+
assert(type);
135+
auto *typeDef = dynamic_cast<const TypeDef *>(type);
136+
if (typeDef) {
137+
if (!typeDef->getType()) {
138+
return true;
139+
}
140+
return isAliasForOpaqueType(typeDef->getType().get());
141+
}
142+
return false;
143+
}
144+
129145
#endif // UTILS_H

bindgen/defines/DefineFinder.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,6 @@ void DefineFinder::MacroUndefined(const clang::Token &macroNameTok,
104104
const clang::MacroDefinition &md,
105105
const clang::MacroDirective *undef) {
106106
clang::SourceManager &sm = compiler.getSourceManager();
107-
if (!sm.isInMainFile(undef->getLocation())) {
108-
return;
109-
}
110107
if (sm.isWrittenInMainFile(macroNameTok.getLocation()) &&
111108
md.getMacroInfo() && !md.getMacroInfo()->isFunctionLike()) {
112109
std::string macroName = macroNameTok.getIdentifierInfo()->getName();

bindgen/ir/Function.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,14 @@ bool Function::isLegalScalaNativeFunction() const {
7272
/* Return type and parameters types cannot be array types because array type
7373
* in this case is always represented as a pointer to element type */
7474
if (isAliasForType<Struct>(retType.get()) ||
75-
isAliasForType<Union>(retType.get())) {
75+
isAliasForType<Union>(retType.get()) ||
76+
isAliasForOpaqueType(retType.get())) {
7677
return false;
7778
}
7879
for (const auto &parameter : parameters) {
7980
if (isAliasForType<Struct>(parameter->getType().get()) ||
80-
isAliasForType<Union>(parameter->getType().get())) {
81+
isAliasForType<Union>(parameter->getType().get()) ||
82+
isAliasForOpaqueType(parameter->getType().get())) {
8183
return false;
8284
}
8385
}

bindgen/ir/IR.cpp

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "IR.h"
22
#include "../Utils.h"
3+
#include "types/PointerType.h"
34

45
IR::IR(std::string libName, std::string linkName, std::string objectName,
56
std::string packageName, const LocationManager &locationManager)
@@ -111,26 +112,49 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
111112
for (const auto &typeDef : ir.typeDefs) {
112113
if (ir.shouldOutput(typeDef)) {
113114
s << *typeDef;
115+
if (typeDef->getType()) {
116+
auto *structOrUnion =
117+
dynamic_cast<StructOrUnion *>(typeDef->getType().get());
118+
if (structOrUnion &&
119+
structOrUnion->hasIllegalUsageOfOpaqueType()) {
120+
llvm::errs()
121+
<< "Error: record " << structOrUnion->getName()
122+
<< " has field of incomplete type. Declarations "
123+
"that use this type may not work properly.\n";
124+
llvm::errs().flush();
125+
}
126+
}
114127
}
115128
}
116129

117130
for (const auto &variable : ir.variables) {
118-
s << *variable;
131+
if (!variable->hasIllegalUsageOfOpaqueType()) {
132+
s << *variable;
133+
} else {
134+
llvm::errs() << "Error: Variable " << variable->getName()
135+
<< " is skipped because it has incomplete type.\n";
136+
}
119137
}
120138

121139
for (const auto &varDefine : ir.varDefines) {
122-
s << *varDefine;
140+
if (!varDefine->hasIllegalUsageOfOpaqueType()) {
141+
s << *varDefine;
142+
} else {
143+
llvm::errs() << "Error: Variable alias " << varDefine->getName()
144+
<< " is skipped because it has incomplete type\n";
145+
llvm::errs().flush();
146+
}
123147
}
124148

125149
for (const auto &func : ir.functions) {
126-
if (func->isLegalScalaNativeFunction()) {
127-
s << *func;
128-
} else {
150+
if (!func->isLegalScalaNativeFunction()) {
129151
llvm::errs()
130152
<< "Warning: Function " << func->getName()
131153
<< " is skipped because Scala Native does not support "
132154
"passing structs and arrays by value.\n";
133155
llvm::errs().flush();
156+
} else {
157+
s << *func;
134158
}
135159
}
136160

@@ -167,13 +191,15 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
167191
s << "object " << ir.libName << "Helpers {\n";
168192

169193
for (const auto &st : ir.structs) {
170-
if (ir.shouldOutput(st) && st->hasHelperMethods()) {
194+
if (ir.shouldOutput(st) && st->hasHelperMethods() &&
195+
!st->hasIllegalUsageOfOpaqueType()) {
171196
s << "\n" << st->generateHelperClass();
172197
}
173198
}
174199

175200
for (const auto &u : ir.unions) {
176-
if (ir.shouldOutput(u) && u->hasHelperMethods()) {
201+
if (ir.shouldOutput(u) && u->hasHelperMethods() &&
202+
!u->hasIllegalUsageOfOpaqueType()) {
177203
s << "\n" << u->generateHelperClass();
178204
}
179205
}
@@ -447,5 +473,14 @@ bool IR::hasOutputtedDeclaration(
447473

448474
template <typename T>
449475
bool IR::shouldOutput(const std::shared_ptr<T> &type) const {
450-
return inMainFile(*type) || isTypeUsed(type, true);
476+
if (isTypeUsed(type, true)) {
477+
return true;
478+
}
479+
auto *typeDef = dynamic_cast<TypeDef *>(type.get());
480+
if (typeDef) {
481+
/* unused typedefs from main file are not printed if they are aliases
482+
* for opaque types */
483+
return !isAliasForOpaqueType(typeDef) && inMainFile(*typeDef);
484+
}
485+
return inMainFile(*type);
451486
}

bindgen/ir/IR.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,13 @@ class IR {
148148
template <typename T> bool inMainFile(const T &type) const;
149149

150150
/**
151-
* @tparam T Type subclass
152-
* @return true if type is in main file or it is used by declaration from
153-
* main file.
151+
* @tparam T Enum, Struct, Union or TypeDef
152+
* @return true if the type will be printed.
153+
* Following types are not printed:
154+
* - Unused types from included headers
155+
* - Unused typedefs from main header if they reference an opaque
156+
* type (if such typedef is used then true is returned but error
157+
* message is printed when bindings are generated)
154158
*/
155159
template <typename T>
156160
bool shouldOutput(const std::shared_ptr<T> &type) const;

bindgen/ir/Struct.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ std::shared_ptr<Location> StructOrUnion::getLocation() const {
4949

5050
bool StructOrUnion::hasHelperMethods() const { return !fields.empty(); }
5151

52+
bool StructOrUnion::hasIllegalUsageOfOpaqueType() const {
53+
for (const auto &field : fields) {
54+
if (isAliasForOpaqueType(field->getType().get())) {
55+
return true;
56+
}
57+
}
58+
return false;
59+
}
60+
5261
Struct::Struct(std::string name, std::vector<std::shared_ptr<Field>> fields,
5362
uint64_t typeSize, std::shared_ptr<Location> location)
5463
: StructOrUnion(std::move(name), std::move(fields), std::move(location)),

bindgen/ir/Struct.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ class StructOrUnion {
4343

4444
bool hasHelperMethods() const;
4545

46+
/**
47+
* @return true if the record contains field of opaque type or an array
48+
* of elements of opaque type.
49+
*/
50+
bool hasIllegalUsageOfOpaqueType() const;
51+
4652
protected:
4753
std::string name;
4854
std::vector<std::shared_ptr<Field>> fields;

bindgen/ir/TypeDef.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ TypeDef::TypeDef(std::string name, std::shared_ptr<Type> type,
99
location(std::move(location)) {}
1010

1111
llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const TypeDef &typeDef) {
12-
if (!typeDef.getType()) {
13-
llvm::errs() << "Error: type definition for " << typeDef.getName()
14-
<< " was not found.\n";
15-
llvm::errs().flush();
16-
return s;
12+
s << " type " << handleReservedWords(typeDef.name) << " = ";
13+
if (typeDef.type) {
14+
s << typeDef.getType()->str();
15+
} else {
16+
s << "native.CStruct0 // incomplete type";
1717
}
18-
s << " type " + handleReservedWords(typeDef.name) + " = " +
19-
typeDef.getType()->str() + "\n";
18+
s << "\n";
2019
return s;
2120
}
2221

bindgen/ir/VarDefine.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s,
1010
<< varDefine.variable->getType()->str() << " = native.extern\n";
1111
return s;
1212
}
13+
14+
bool VarDefine::hasIllegalUsageOfOpaqueType() const {
15+
return variable->hasIllegalUsageOfOpaqueType();
16+
}

bindgen/ir/VarDefine.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ class VarDefine : public Define {
1414
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s,
1515
const VarDefine &varDefine);
1616

17+
bool hasIllegalUsageOfOpaqueType() const;
18+
1719
private:
1820
std::shared_ptr<Variable> variable;
1921
};

0 commit comments

Comments
 (0)