Skip to content

Commit 68bc423

Browse files
author
Florent Bruneau
committed
Clang Importer: import all indirect fields.
Until now, only indirect fields that didn't belong to a C union (somewhere between the field declaration and the type in which it is indirectly exposed) were imported in swift. This patch tries to provide an approach that allows all those fields to be exposed in swift. However, the downside is that we introduce new intermediate fields and types, some of the fields may already have been manually defined in type extension (as seen with the GLKit overlay). The main idea here is that we can simply expose the anonymous struct/unions from which the indirect types are taken and then use swift computed properties to access the content of those anonymous struct/unions. As a consequence, each time we encounter an anonymous struct or union, we actually expose it at __Anonymous_field<id> (where id is the index of the field in the structure). At this point, we use the existing mechanism to expose the type as __Unnamed_<struct|union>_<fieldname>. Then, each indirect field is exposed as a computed property. The C object: typedef union foo_t { struct { int a; int b; }; int c; } foo_t; Is imported as struct foo_t { struct __Unnamed_struct___Anonymous_field1 { var a : Int32 var b : Int32 } var __Anonymous_field1 : foo_t.__Unnamed_struct___Anonymous_field1 var a : Int32 { get { return __Anonymous_field1.a } set(newValue) { __Anonymous_field1.a = newValue } } var b : Int32 { get { return __Anonymous_field1.b } set(newValue) { __Anonymous_field1.b = newValue } } var c : Int32 } This has the advantage to work for both struct and union, even in case we have several nested anonymous struct/unions. This does not require to know the size and/or the offset of the fields in the structures and thus can be properly implemented using front-end data. Signed-off-by: Florent Bruneau <[email protected]>
1 parent 474096b commit 68bc423

File tree

3 files changed

+185
-129
lines changed

3 files changed

+185
-129
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 164 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,122 @@ static FuncDecl *makeFieldSetterDecl(ClangImporter::Implementation &Impl,
596596
return setterDecl;
597597
}
598598

599+
/// Build the indirect field getter and setter.
600+
///
601+
/// \code
602+
/// struct SomeImportedIndirectField {
603+
/// struct __Unnamed_struct___Anonymous_field_1 {
604+
/// var myField : Int
605+
/// }
606+
/// var __Anonymous_field_1 : __Unnamed_struct___Anonymous_field_1
607+
/// var myField : Int {
608+
/// get {
609+
/// __Anonymous_field_1.myField
610+
/// }
611+
/// set(newValue) {
612+
/// __Anonymous_field_1.myField = newValue
613+
/// }
614+
/// }
615+
/// }
616+
/// \endcode
617+
///
618+
/// \returns a pair of getter and setter function decls.
619+
static std::pair<FuncDecl *, FuncDecl *>
620+
makeIndirectFieldAccessors(ClangImporter::Implementation &Impl,
621+
const clang::IndirectFieldDecl *indirectField,
622+
ArrayRef<VarDecl *> members,
623+
StructDecl *importedStructDecl,
624+
VarDecl *importedFieldDecl) {
625+
auto &C = Impl.SwiftContext;
626+
627+
auto getterDecl = makeFieldGetterDecl(Impl,
628+
importedStructDecl,
629+
importedFieldDecl);
630+
631+
auto setterDecl = makeFieldSetterDecl(Impl,
632+
importedStructDecl,
633+
importedFieldDecl);
634+
635+
importedFieldDecl->makeComputed(SourceLoc(), getterDecl, setterDecl, nullptr,
636+
SourceLoc());
637+
638+
auto containingField = indirectField->chain().front();
639+
VarDecl *anonymousFieldDecl = nullptr;
640+
641+
// Reverse scan of the members because indirect field are generated just
642+
// after the corresponding anonymous type, so a reverse scan allows
643+
// swiftching from O(n) to O(1) here.
644+
for (auto decl : reverse(members)) {
645+
if (decl->getClangDecl() == containingField) {
646+
anonymousFieldDecl = cast<VarDecl>(decl);
647+
break;
648+
}
649+
}
650+
assert (anonymousFieldDecl && "anonymous field not generated");
651+
652+
auto anonymousFieldType = anonymousFieldDecl->getInterfaceType();
653+
auto anonymousFieldTypeDecl = anonymousFieldType->getStructOrBoundGenericStruct();
654+
655+
VarDecl *anonymousInnerFieldDecl = nullptr;
656+
for (auto decl : anonymousFieldTypeDecl->lookupDirect(importedFieldDecl->getName())) {
657+
if (isa<VarDecl>(decl)) {
658+
anonymousInnerFieldDecl = cast<VarDecl>(decl);
659+
break;
660+
}
661+
}
662+
assert (anonymousInnerFieldDecl && "cannot find field in anonymous generated structure");
663+
664+
// Don't bother synthesizing the body if we've already finished type-checking.
665+
if (Impl.hasFinishedTypeChecking())
666+
return { getterDecl, setterDecl };
667+
668+
// Synthesize the getter body
669+
{
670+
auto selfDecl = getterDecl->getImplicitSelfDecl();
671+
Expr *expr = new (C) DeclRefExpr(selfDecl, DeclNameLoc(),
672+
/*implicit*/true);
673+
expr = new (C) MemberRefExpr(expr, SourceLoc(), anonymousFieldDecl,
674+
DeclNameLoc(), /*implicit*/true);
675+
676+
expr = new (C) MemberRefExpr(expr, SourceLoc(), anonymousInnerFieldDecl,
677+
DeclNameLoc(), /*implicit*/true);
678+
679+
auto ret = new (C) ReturnStmt(SourceLoc(), expr);
680+
auto body = BraceStmt::create(C, SourceLoc(), ASTNode(ret), SourceLoc(),
681+
/*implicit*/ true);
682+
getterDecl->setBody(body);
683+
getterDecl->getAttrs().add(new (C) TransparentAttr(/*implicit*/ true));
684+
C.addExternalDecl(getterDecl);
685+
}
686+
687+
// Synthesize the setter body
688+
{
689+
auto selfDecl = setterDecl->getImplicitSelfDecl();
690+
Expr *lhs = new (C) DeclRefExpr(selfDecl, DeclNameLoc(),
691+
/*implicit*/true);
692+
lhs = new (C) MemberRefExpr(lhs, SourceLoc(), anonymousFieldDecl,
693+
DeclNameLoc(), /*implicit*/true);
694+
695+
lhs = new (C) MemberRefExpr(lhs, SourceLoc(), anonymousInnerFieldDecl,
696+
DeclNameLoc(), /*implicit*/true);
697+
698+
auto newValueDecl = setterDecl->getParameterList(1)->get(0);
699+
700+
auto rhs = new (C) DeclRefExpr(newValueDecl, DeclNameLoc(),
701+
/*implicit*/ true);
702+
703+
auto assign = new (C) AssignExpr(lhs, SourceLoc(), rhs, /*implicit*/true);
704+
705+
auto body = BraceStmt::create(C, SourceLoc(), { assign }, SourceLoc(),
706+
/*implicit*/ true);
707+
setterDecl->setBody(body);
708+
setterDecl->getAttrs().add(new (C) TransparentAttr(/*implicit*/ true));
709+
C.addExternalDecl(setterDecl);
710+
}
711+
712+
return { getterDecl, setterDecl };
713+
}
714+
599715
/// Build the union field getter and setter.
600716
///
601717
/// \code
@@ -969,6 +1085,11 @@ createValueConstructor(ClangImporter::Implementation &Impl,
9691085
// Construct the set of parameters from the list of members.
9701086
SmallVector<ParamDecl *, 8> valueParameters;
9711087
for (auto var : members) {
1088+
// TODO create value constructor with indirect fields instead of the
1089+
// generated __Anonymous_field.
1090+
if (var->hasClangNode() && isa<clang::IndirectFieldDecl>(var->getClangDecl()))
1091+
continue;
1092+
9721093
Identifier argName = wantCtorParamNames ? var->getName() : Identifier();
9731094
auto param = new (context)
9741095
ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(), argName,
@@ -1012,6 +1133,10 @@ createValueConstructor(ClangImporter::Implementation &Impl,
10121133
for (unsigned pass = 0; pass < 2; pass++) {
10131134
for (unsigned i = 0, e = members.size(); i < e; i++) {
10141135
auto var = members[i];
1136+
1137+
if (var->hasClangNode() && isa<clang::IndirectFieldDecl>(var->getClangDecl()))
1138+
continue;
1139+
10151140
if (var->hasStorage() == (pass != 0))
10161141
continue;
10171142

@@ -1749,10 +1874,6 @@ namespace {
17491874
decl->getLexicalDeclContext())) {
17501875
for (auto field : recordDecl->fields()) {
17511876
if (field->getType()->getAsTagDecl() == decl) {
1752-
// We found the field. The field should not be anonymous, since we are
1753-
// using its name to derive the generated declaration name.
1754-
assert(!field->isAnonymousStructOrUnion());
1755-
17561877
// Create a name for the declaration from the field name.
17571878
std::string Id;
17581879
llvm::raw_string_ostream IdStream(Id);
@@ -1765,8 +1886,12 @@ namespace {
17651886
else
17661887
llvm_unreachable("unknown decl kind");
17671888

1768-
IdStream << "__Unnamed_" << kind
1769-
<< "_" << field->getName();
1889+
IdStream << "__Unnamed_" << kind << "_";
1890+
if (field->isAnonymousStructOrUnion()) {
1891+
IdStream << "__Anonymous_field" << field->getFieldIndex();
1892+
} else {
1893+
IdStream << field->getName();
1894+
}
17701895
ImportedName Result;
17711896
Result.setDeclName(Impl.SwiftContext.getIdentifier(IdStream.str()));
17721897
Result.setEffectiveContext(decl->getDeclContext());
@@ -2430,11 +2555,6 @@ namespace {
24302555
if (decl->isInterface())
24312556
return nullptr;
24322557

2433-
// The types of anonymous structs or unions are never imported; their
2434-
// fields are dumped directly into the enclosing class.
2435-
if (decl->isAnonymousStructOrUnion())
2436-
return nullptr;
2437-
24382558
// FIXME: Figure out how to deal with incomplete types, since that
24392559
// notion doesn't exist in Swift.
24402560
decl = decl->getDefinition();
@@ -2491,11 +2611,6 @@ namespace {
24912611
}
24922612

24932613
if (auto field = dyn_cast<clang::FieldDecl>(nd)) {
2494-
// Skip anonymous structs or unions; they'll be dealt with via the
2495-
// IndirectFieldDecls.
2496-
if (field->isAnonymousStructOrUnion())
2497-
continue;
2498-
24992614
// Non-nullable pointers can't be zero-initialized.
25002615
if (auto nullability = field->getType()
25012616
->getNullability(Impl.getClangASTContext())) {
@@ -2544,6 +2659,15 @@ namespace {
25442659

25452660
auto VD = cast<VarDecl>(member);
25462661

2662+
if (isa<clang::IndirectFieldDecl>(nd) || decl->isUnion()) {
2663+
// Don't import unavailable fields that have no associated storage.
2664+
if (VD->getAttrs().isUnavailable(Impl.SwiftContext)) {
2665+
continue;
2666+
}
2667+
}
2668+
2669+
members.push_back(VD);
2670+
25472671
// Bitfields are imported as computed properties with Clang-generated
25482672
// accessors.
25492673
if (auto field = dyn_cast<clang::FieldDecl>(nd)) {
@@ -2560,19 +2684,16 @@ namespace {
25602684
}
25612685
}
25622686

2563-
if (decl->isUnion()) {
2687+
if (auto ind = dyn_cast<clang::IndirectFieldDecl>(nd)) {
2688+
// Indirect fields are created as computed property accessible the
2689+
// fields on the anonymous field from which they are injected.
2690+
makeIndirectFieldAccessors(Impl, ind, members, result, VD);
2691+
} else if (decl->isUnion()) {
25642692
// Union fields should only be available indirectly via a computed
25652693
// property. Since the union is made of all of the fields at once,
25662694
// this is a trivial accessor that casts self to the correct
25672695
// field type.
2568-
2569-
// FIXME: Allow indirect field access of anonymous structs.
2570-
if (isa<clang::IndirectFieldDecl>(nd))
2571-
continue;
2572-
2573-
Decl *getter, *setter;
2574-
std::tie(getter, setter) = makeUnionFieldAccessors(Impl, result, VD);
2575-
members.push_back(VD);
2696+
makeUnionFieldAccessors(Impl, result, VD);
25762697

25772698
// Create labeled initializers for unions that take one of the
25782699
// fields, which only initializes the data for that field.
@@ -2581,8 +2702,6 @@ namespace {
25812702
/*want param names*/true,
25822703
/*wantBody=*/!Impl.hasFinishedTypeChecking());
25832704
ctors.push_back(valueCtor);
2584-
} else {
2585-
members.push_back(VD);
25862705
}
25872706
}
25882707

@@ -2758,16 +2877,6 @@ namespace {
27582877
}
27592878

27602879
Decl *VisitIndirectFieldDecl(const clang::IndirectFieldDecl *decl) {
2761-
// Check whether the context of any of the fields in the chain is a
2762-
// union. If so, don't import this field.
2763-
for (auto f = decl->chain_begin(), fEnd = decl->chain_end(); f != fEnd;
2764-
++f) {
2765-
if (auto record = dyn_cast<clang::RecordDecl>((*f)->getDeclContext())) {
2766-
if (record->isUnion())
2767-
return nullptr;
2768-
}
2769-
}
2770-
27712880
Optional<ImportedName> correctSwiftName;
27722881
auto importedName = importFullName(decl, correctSwiftName);
27732882
if (!importedName) return nullptr;
@@ -2963,8 +3072,24 @@ namespace {
29633072
Decl *VisitFieldDecl(const clang::FieldDecl *decl) {
29643073
// Fields are imported as variables.
29653074
Optional<ImportedName> correctSwiftName;
2966-
auto importedName = importFullName(decl, correctSwiftName);
2967-
if (!importedName) return nullptr;
3075+
ImportedName importedName;
3076+
3077+
if (!decl->isAnonymousStructOrUnion()) {
3078+
importedName = importFullName(decl, correctSwiftName);
3079+
if (!importedName) {
3080+
return nullptr;
3081+
}
3082+
} else {
3083+
// Generate a field name for anonymous fields, this will be used in
3084+
// order to be able to expose the indirect fields injected from there
3085+
// as computed properties forwarding the access to the subfield.
3086+
std::string Id;
3087+
llvm::raw_string_ostream IdStream(Id);
3088+
3089+
IdStream << "__Anonymous_field" << decl->getFieldIndex();
3090+
importedName.setDeclName(Impl.SwiftContext.getIdentifier(IdStream.str()));
3091+
importedName.setEffectiveContext(decl->getDeclContext());
3092+
}
29683093

29693094
auto name = importedName.getDeclName().getBaseName();
29703095

stdlib/public/SDK/GLKit/GLKMath.swift.gyb

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,6 @@
2020
// This overlay generates Swift accessors for the GLKit matrix and vector
2121
// types.
2222

23-
%{
24-
# Each element of the array is a tuple of the element labels and the minimum
25-
# vector length at which to apply them.
26-
vectorElementNames = [
27-
(['x', 'y', 'z', 'w'], 2),
28-
(['s', 't', 'p', 'q'], 2),
29-
(['r', 'g', 'b', 'a'], 3),
30-
]
31-
}%
32-
3323
// Do dirty pointer manipulations to index an opaque struct like an array.
3424
@inline(__always)
3525
public func _indexHomogeneousValue<TTT, T>(_ aggregate: UnsafePointer<TTT>,
@@ -58,69 +48,15 @@ def defineSubscript(Type, limit):
5848
% for size in [2, 3, 4]:
5949

6050
extension GLKMatrix${size} {
61-
public typealias _Tuple = (${ ', '.join(['Float'] * (size * size)) })
62-
public var _tuple: _Tuple {
63-
@inline(__always) get { return unsafeBitCast(self, to: _Tuple.self) }
64-
}
65-
% for i in xrange(0, size):
66-
% for j in xrange(0, size):
67-
public var m${i}${j}: Float {
68-
@inline(__always) get { return _tuple.${i * size + j} }
69-
}
70-
% end
71-
% end
72-
7351
${ defineSubscript("GLKMatrix" + str(size), size * size) }
7452
}
7553

7654
extension GLKVector${size} {
77-
public typealias _Tuple = (${ ', '.join(['Float'] * size) })
78-
public var _tuple: _Tuple {
79-
@inline(__always) get { return unsafeBitCast(self, to: _Tuple.self) }
80-
}
81-
82-
% for (names, minSize) in vectorElementNames:
83-
% for i in xrange(0, size if size >= minSize else 0):
84-
public var ${names[i]}: Float {
85-
@inline(__always) get { return _tuple.${i} }
86-
}
87-
% end
88-
% end
89-
9055
${ defineSubscript("GLKVector" + str(size), size) }
9156
}
9257

9358
% end
9459

9560
extension GLKQuaternion {
96-
public typealias _Tuple = (Float, Float, Float, Float)
97-
public var _tuple: _Tuple {
98-
@inline(__always) get { return unsafeBitCast(self, to: _Tuple.self) }
99-
}
100-
101-
public var v: GLKVector3 {
102-
@inline(__always) get {
103-
let (i, j, k, _) = _tuple
104-
return GLKVector3Make(i, j, k)
105-
}
106-
}
107-
108-
public var s: Float {
109-
@inline(__always) get { return _tuple.3 }
110-
}
111-
112-
public var x: Float {
113-
@inline(__always) get { return _tuple.0 }
114-
}
115-
public var y: Float {
116-
@inline(__always) get { return _tuple.1 }
117-
}
118-
public var z: Float {
119-
@inline(__always) get { return _tuple.2 }
120-
}
121-
public var w: Float {
122-
@inline(__always) get { return _tuple.3 }
123-
}
124-
12561
${ defineSubscript("GLKQuaternion", 4) }
12662
}

0 commit comments

Comments
 (0)