Skip to content

Commit 458a6e5

Browse files
committed
Generate types for anonymous declarations
1 parent 4bc278e commit 458a6e5

File tree

12 files changed

+214
-106
lines changed

12 files changed

+214
-106
lines changed

bindgen/TypeTranslator.cpp

+83-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include "TypeTranslator.h"
22
#include "Utils.h"
33
#include "ir/types/FunctionPointerType.h"
4-
#include "ir/types/PointerType.h"
4+
#include "clang/AST/RecordLayout.h"
55

66
TypeTranslator::TypeTranslator(clang::ASTContext *ctx_, IR &ir)
77
: ctx(ctx_), ir(ir), typeMap() {
@@ -106,13 +106,17 @@ TypeTranslator::translateStructOrUnionOrEnum(const clang::QualType &qtpe) {
106106
std::shared_ptr<Type>
107107
TypeTranslator::translateStructOrUnion(const clang::QualType &qtpe) {
108108
if (qtpe->hasUnnamedOrLocalType()) {
109-
// TODO: Verify that the local part is not a problem
110-
uint64_t sizeInBits = ctx->getTypeSize(qtpe);
111-
assert(sizeInBits % 8 == 0);
112-
return std::make_shared<ArrayType>(
113-
std::make_shared<PrimitiveType>("Byte"), sizeInBits / 8);
109+
if (qtpe->isStructureType()) {
110+
std::string name = "anonymous_" + std::to_string(anonymousTypeId++);
111+
clang::RecordDecl *record = qtpe->getAsStructureType()->getDecl();
112+
return addStructDefinition(record, name);
113+
} else if (qtpe->isUnionType()) {
114+
std::string name = "anonymous_" + std::to_string(anonymousTypeId++);
115+
clang::RecordDecl *record = qtpe->getAsUnionType()->getDecl();
116+
return addUnionDefinition(record, name);
117+
}
118+
return nullptr;
114119
}
115-
116120
return translateStructOrUnionOrEnum(qtpe);
117121
}
118122

@@ -176,3 +180,75 @@ std::string TypeTranslator::getTypeFromTypeMap(std::string cType) {
176180
}
177181
return "";
178182
}
183+
184+
std::shared_ptr<Location> TypeTranslator::getLocation(clang::Decl *decl) {
185+
clang::SourceManager &sm = ctx->getSourceManager();
186+
std::string filename = std::string(sm.getFilename(decl->getLocation()));
187+
char *p = realpath(filename.c_str(), nullptr);
188+
std::string path;
189+
if (p) {
190+
path = p;
191+
delete[] p;
192+
} else {
193+
// TODO: check when it happens
194+
path = "";
195+
}
196+
197+
unsigned lineNumber = sm.getSpellingLineNumber(decl->getLocation());
198+
return std::make_shared<Location>(path, lineNumber);
199+
}
200+
201+
std::shared_ptr<TypeDef>
202+
TypeTranslator::addUnionDefinition(clang::RecordDecl *record,
203+
std::string name) {
204+
std::vector<std::shared_ptr<Field>> fields;
205+
206+
for (const clang::FieldDecl *field : record->fields()) {
207+
std::string fname = field->getNameAsString();
208+
std::shared_ptr<Type> ftype = translate(field->getType());
209+
210+
fields.push_back(std::make_shared<Field>(fname, ftype));
211+
}
212+
213+
uint64_t sizeInBits = ctx->getTypeSize(record->getTypeForDecl());
214+
assert(sizeInBits % 8 == 0);
215+
216+
return ir.addUnion(name, std::move(fields), sizeInBits / 8,
217+
getLocation(record));
218+
}
219+
220+
std::shared_ptr<TypeDef>
221+
TypeTranslator::addStructDefinition(clang::RecordDecl *record,
222+
std::string name) {
223+
std::string newName = "struct_" + name;
224+
225+
if (record->hasAttr<clang::PackedAttr>()) {
226+
llvm::errs() << "Warning: struct " << name << " is packed. "
227+
<< "Packed structs are not supported by Scala Native. "
228+
<< "Access to fields will not work correctly.\n";
229+
llvm::errs().flush();
230+
}
231+
232+
std::vector<std::shared_ptr<Field>> fields;
233+
const clang::ASTRecordLayout &recordLayout =
234+
ctx->getASTRecordLayout(record);
235+
236+
bool isBitFieldStruct = false;
237+
for (const clang::FieldDecl *field : record->fields()) {
238+
if (field->isBitField()) {
239+
isBitFieldStruct = true;
240+
}
241+
std::shared_ptr<Type> ftype = translate(field->getType());
242+
uint64_t recordOffsetInBits =
243+
recordLayout.getFieldOffset(field->getFieldIndex());
244+
fields.push_back(std::make_shared<Field>(field->getNameAsString(),
245+
ftype, recordOffsetInBits));
246+
}
247+
248+
uint64_t sizeInBits = ctx->getTypeSize(record->getTypeForDecl());
249+
assert(sizeInBits % 8 == 0);
250+
251+
return ir.addStruct(name, std::move(fields), sizeInBits / 8,
252+
getLocation(record),
253+
record->hasAttr<clang::PackedAttr>(), isBitFieldStruct);
254+
}

bindgen/TypeTranslator.h

+9
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,18 @@ class TypeTranslator {
1616

1717
std::string getTypeFromTypeMap(std::string cType);
1818

19+
std::shared_ptr<TypeDef> addUnionDefinition(clang::RecordDecl *record,
20+
std::string name);
21+
22+
std::shared_ptr<TypeDef> addStructDefinition(clang::RecordDecl *record,
23+
std::string name);
24+
25+
std::shared_ptr<Location> getLocation(clang::Decl *decl);
26+
1927
private:
2028
clang::ASTContext *ctx;
2129
IR &ir;
30+
int anonymousTypeId = 0;
2231

2332
/**
2433
* Primitive types

bindgen/ir/IR.cpp

+11-5
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ void IR::addEnum(std::string name, const std::string &type,
3333
}
3434
}
3535

36-
void IR::addStruct(std::string name, std::vector<std::shared_ptr<Field>> fields,
37-
uint64_t typeSize, std::shared_ptr<Location> location,
38-
bool isPacked, bool isBitField) {
36+
std::shared_ptr<TypeDef>
37+
IR::addStruct(std::string name, std::vector<std::shared_ptr<Field>> fields,
38+
uint64_t typeSize, std::shared_ptr<Location> location,
39+
bool isPacked, bool isBitField) {
3940
std::shared_ptr<Struct> s =
4041
std::make_shared<Struct>(name, std::move(fields), typeSize,
4142
std::move(location), isPacked, isBitField);
@@ -44,22 +45,27 @@ void IR::addStruct(std::string name, std::vector<std::shared_ptr<Field>> fields,
4445
if (typeDef) {
4546
/* the struct type used to be opaque type, typeDef contains nullptr */
4647
typeDef.get()->setType(s);
48+
return typeDef;
4749
} else {
4850
typeDefs.push_back(s->generateTypeDef());
51+
return typeDefs.back();
4952
}
5053
}
5154

52-
void IR::addUnion(std::string name, std::vector<std::shared_ptr<Field>> fields,
53-
uint64_t maxSize, std::shared_ptr<Location> location) {
55+
std::shared_ptr<TypeDef>
56+
IR::addUnion(std::string name, std::vector<std::shared_ptr<Field>> fields,
57+
uint64_t maxSize, std::shared_ptr<Location> location) {
5458
std::shared_ptr<Union> u = std::make_shared<Union>(
5559
name, std::move(fields), maxSize, std::move(location));
5660
unions.push_back(u);
5761
std::shared_ptr<TypeDef> typeDef = getTypeDefWithName("union_" + name);
5862
if (typeDef) {
5963
/* the union type used to be opaque type, typeDef contains nullptr */
6064
typeDef.get()->setType(u);
65+
return typeDef;
6166
} else {
6267
typeDefs.push_back(u->generateTypeDef());
68+
return typeDefs.back();
6369
}
6470
}
6571

bindgen/ir/IR.h

+8-6
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,14 @@ class IR {
3535
std::vector<Enumerator> enumerators,
3636
std::shared_ptr<Location> location);
3737

38-
void addStruct(std::string name, std::vector<std::shared_ptr<Field>> fields,
39-
uint64_t typeSize, std::shared_ptr<Location> location,
40-
bool isPacked, bool isBitField);
41-
42-
void addUnion(std::string name, std::vector<std::shared_ptr<Field>> fields,
43-
uint64_t maxSize, std::shared_ptr<Location> location);
38+
std::shared_ptr<TypeDef>
39+
addStruct(std::string name, std::vector<std::shared_ptr<Field>> fields,
40+
uint64_t typeSize, std::shared_ptr<Location> location,
41+
bool isPacked, bool isBitField);
42+
43+
std::shared_ptr<TypeDef>
44+
addUnion(std::string name, std::vector<std::shared_ptr<Field>> fields,
45+
uint64_t maxSize, std::shared_ptr<Location> location);
4446

4547
void addLiteralDefine(std::string name, std::string literal,
4648
std::shared_ptr<Type> type);

bindgen/visitor/TreeVisitor.cpp

+5-73
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include "TreeVisitor.h"
2-
#include "clang/AST/RecordLayout.h"
32

43
bool TreeVisitor::VisitFunctionDecl(clang::FunctionDecl *func) {
54
if (!astContext->getSourceManager().isInMainFile(func->getLocation())) {
@@ -37,7 +36,7 @@ bool TreeVisitor::VisitTypedefDecl(clang::TypedefDecl *tpdef) {
3736
std::shared_ptr<Type> type =
3837
typeTranslator.translate(tpdef->getUnderlyingType());
3938
if (type) {
40-
ir.addTypeDef(name, type, getLocation(tpdef));
39+
ir.addTypeDef(name, type, typeTranslator.getLocation(tpdef));
4140
}
4241
return true;
4342
}
@@ -59,7 +58,8 @@ bool TreeVisitor::VisitEnumDecl(clang::EnumDecl *enumdecl) {
5958
std::string scalaType = typeTranslator.getTypeFromTypeMap(
6059
enumdecl->getIntegerType().getUnqualifiedType().getAsString());
6160

62-
ir.addEnum(name, scalaType, std::move(enumerators), getLocation(enumdecl));
61+
ir.addEnum(name, scalaType, std::move(enumerators),
62+
typeTranslator.getLocation(enumdecl));
6363

6464
return true;
6565
}
@@ -76,68 +76,17 @@ bool TreeVisitor::VisitRecordDecl(clang::RecordDecl *record) {
7676

7777
if (record->isUnion() && record->isThisDeclarationADefinition() &&
7878
!record->isAnonymousStructOrUnion() && !name.empty()) {
79-
handleUnion(record, name);
79+
typeTranslator.addUnionDefinition(record, name);
8080
return true;
8181

8282
} else if (record->isStruct() && record->isThisDeclarationADefinition() &&
8383
!record->isAnonymousStructOrUnion() && !name.empty()) {
84-
handleStruct(record, name);
84+
typeTranslator.addStructDefinition(record, name);
8585
return true;
8686
}
8787
return false;
8888
}
8989

90-
void TreeVisitor::handleUnion(clang::RecordDecl *record, std::string name) {
91-
std::vector<std::shared_ptr<Field>> fields;
92-
93-
for (const clang::FieldDecl *field : record->fields()) {
94-
std::string fname = field->getNameAsString();
95-
std::shared_ptr<Type> ftype =
96-
typeTranslator.translate(field->getType());
97-
98-
fields.push_back(std::make_shared<Field>(fname, ftype));
99-
}
100-
101-
uint64_t sizeInBits = astContext->getTypeSize(record->getTypeForDecl());
102-
assert(sizeInBits % 8 == 0);
103-
104-
ir.addUnion(name, std::move(fields), sizeInBits / 8, getLocation(record));
105-
}
106-
107-
void TreeVisitor::handleStruct(clang::RecordDecl *record, std::string name) {
108-
std::string newName = "struct_" + name;
109-
110-
if (record->hasAttr<clang::PackedAttr>()) {
111-
llvm::errs() << "Warning: struct " << name << " is packed. "
112-
<< "Packed structs are not supported by Scala Native. "
113-
<< "Access to fields will not work correctly.\n";
114-
llvm::errs().flush();
115-
}
116-
117-
std::vector<std::shared_ptr<Field>> fields;
118-
const clang::ASTRecordLayout &recordLayout =
119-
astContext->getASTRecordLayout(record);
120-
121-
bool isBitFieldStruct = false;
122-
for (const clang::FieldDecl *field : record->fields()) {
123-
if (field->isBitField()) {
124-
isBitFieldStruct = true;
125-
}
126-
std::shared_ptr<Type> ftype =
127-
typeTranslator.translate(field->getType());
128-
uint64_t recordOffsetInBits =
129-
recordLayout.getFieldOffset(field->getFieldIndex());
130-
fields.push_back(std::make_shared<Field>(field->getNameAsString(),
131-
ftype, recordOffsetInBits));
132-
}
133-
134-
uint64_t sizeInBits = astContext->getTypeSize(record->getTypeForDecl());
135-
assert(sizeInBits % 8 == 0);
136-
137-
ir.addStruct(name, std::move(fields), sizeInBits / 8, getLocation(record),
138-
record->hasAttr<clang::PackedAttr>(), isBitFieldStruct);
139-
}
140-
14190
bool TreeVisitor::VisitVarDecl(clang::VarDecl *varDecl) {
14291
if (!astContext->getSourceManager().isInMainFile(varDecl->getLocation())) {
14392
/* include variables only from the original header */
@@ -157,20 +106,3 @@ bool TreeVisitor::VisitVarDecl(clang::VarDecl *varDecl) {
157106
}
158107
return true;
159108
}
160-
161-
std::shared_ptr<Location> TreeVisitor::getLocation(clang::Decl *decl) {
162-
clang::SourceManager &sm = astContext->getSourceManager();
163-
std::string filename = std::string(sm.getFilename(decl->getLocation()));
164-
char *p = realpath(filename.c_str(), nullptr);
165-
std::string path;
166-
if (p) {
167-
path = p;
168-
delete[] p;
169-
} else {
170-
// TODO: check when it happens
171-
path = "";
172-
}
173-
174-
unsigned lineNumber = sm.getSpellingLineNumber(decl->getLocation());
175-
return std::make_shared<Location>(path, lineNumber);
176-
}

bindgen/visitor/TreeVisitor.h

-6
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@ class TreeVisitor : public clang::RecursiveASTVisitor<TreeVisitor> {
1111
TypeTranslator typeTranslator;
1212
IR &ir;
1313

14-
void handleUnion(clang::RecordDecl *record, std::string name);
15-
16-
void handleStruct(clang::RecordDecl *record, std::string name);
17-
18-
std::shared_ptr<Location> getLocation(clang::Decl *decl);
19-
2014
public:
2115
TreeVisitor(clang::CompilerInstance *CI, IR &ir)
2216
: astContext(&(CI->getASTContext())), typeTranslator(astContext, ir),

tests/samples/AnonymousTypes.h

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* structs */
2+
3+
void foo(struct { char a; } * s);
4+
5+
struct StructWithAnonymousStruct {
6+
struct {
7+
union {
8+
long a;
9+
} * innerUnion;
10+
} * innerStruct;
11+
};
12+
13+
struct {
14+
int result;
15+
} * bar();

tests/samples/AnonymousTypes.scala

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.scalanative.bindgen.samples
2+
3+
import scala.scalanative._
4+
import scala.scalanative.native._
5+
6+
@native.link("bindgentests")
7+
@native.extern
8+
object AnonymousTypes {
9+
type struct_anonymous_0 = native.CStruct1[native.CChar]
10+
type union_anonymous_2 = native.CArray[Byte, native.Nat._8]
11+
type struct_anonymous_1 = native.CStruct1[native.Ptr[union_anonymous_2]]
12+
type struct_StructWithAnonymousStruct = native.CStruct1[native.Ptr[struct_anonymous_1]]
13+
type struct_anonymous_3 = native.CStruct1[native.CInt]
14+
def foo(s: native.Ptr[struct_anonymous_0]): Unit = native.extern
15+
def bar(): native.Ptr[struct_anonymous_3] = native.extern
16+
}
17+
18+
import AnonymousTypes._
19+
20+
object AnonymousTypesHelpers {
21+
22+
implicit class struct_anonymous_0_ops(val p: native.Ptr[struct_anonymous_0]) extends AnyVal {
23+
def a: native.CChar = !p._1
24+
def a_=(value: native.CChar): Unit = !p._1 = value
25+
}
26+
27+
def struct_anonymous_0()(implicit z: native.Zone): native.Ptr[struct_anonymous_0] = native.alloc[struct_anonymous_0]
28+
29+
implicit class struct_anonymous_1_ops(val p: native.Ptr[struct_anonymous_1]) extends AnyVal {
30+
def innerUnion: native.Ptr[union_anonymous_2] = !p._1
31+
def innerUnion_=(value: native.Ptr[union_anonymous_2]): Unit = !p._1 = value
32+
}
33+
34+
def struct_anonymous_1()(implicit z: native.Zone): native.Ptr[struct_anonymous_1] = native.alloc[struct_anonymous_1]
35+
36+
implicit class struct_StructWithAnonymousStruct_ops(val p: native.Ptr[struct_StructWithAnonymousStruct]) extends AnyVal {
37+
def innerStruct: native.Ptr[struct_anonymous_1] = !p._1
38+
def innerStruct_=(value: native.Ptr[struct_anonymous_1]): Unit = !p._1 = value
39+
}
40+
41+
def struct_StructWithAnonymousStruct()(implicit z: native.Zone): native.Ptr[struct_StructWithAnonymousStruct] = native.alloc[struct_StructWithAnonymousStruct]
42+
43+
implicit class struct_anonymous_3_ops(val p: native.Ptr[struct_anonymous_3]) extends AnyVal {
44+
def result: native.CInt = !p._1
45+
def result_=(value: native.CInt): Unit = !p._1 = value
46+
}
47+
48+
def struct_anonymous_3()(implicit z: native.Zone): native.Ptr[struct_anonymous_3] = native.alloc[struct_anonymous_3]
49+
50+
implicit class union_anonymous_2_pos(val p: native.Ptr[union_anonymous_2]) extends AnyVal {
51+
def a: native.Ptr[native.CLong] = p.cast[native.Ptr[native.CLong]]
52+
def a_=(value: native.CLong): Unit = !p.cast[native.Ptr[native.CLong]] = value
53+
}
54+
}

0 commit comments

Comments
 (0)