Skip to content

Commit 4c133fc

Browse files
author
Florent Bruneau
committed
ClangImporter: use nameless arguments for anonymous struct/unions in constructors.
Following a13c134, constructors of structures/unions containing anonymous structures/unions fields include those field in their parameter list, using the generated field name as parameter name: typedef struct foo_t { union { int a; int b; }; } foo_t; Generates: struct foo_t { init(__Anonymous_field0: foo_t.__Unnamed_union__Anonymous_field0) } let foo = foo_t(__Anonymous_field0: .init(a: 1)) One important downside here is that the generated field name get exposed in the API. An idealistic approach would be to generate the constructors that expose the fields indirectly inherited from those structures: struct foo_t { init(a: Int32) init(b: Int32) } However, this approach requires the generation of a constructor per valid combination of indirect fields, which might start having a huge cardinality when we have nested anonymous structures in nested anonymous unions... typedef struct bar_t { union { struct { int a; int b; }; struct { int c; int d; }; }; union { int e; int f; }; } bar_t; In this examples, we have 4 constructors to generates, for (a, b, e), (a, b, f), (c, d, e) and (c, d, f). The proposed approach is to use a nameless parameter for anonymous structures/unions, still forcing the user to build that sub-object by hand, but without exposing the generated field name. This is very similar to what can be done in C: foo_t foo = { { .a = 1 } }; let foo = foo_t(.init(a: 1)) Or bar_t bar = { { { .a = 1, .b = 2 } }, { .e = 1 } }; let bar = bar_t(.init(.init(a: 1, b: 2)), .init(e: 1)) Signed-off-by: Florent Bruneau <[email protected]>
1 parent 635581a commit 4c133fc

File tree

3 files changed

+37
-8
lines changed

3 files changed

+37
-8
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,12 +1087,20 @@ createValueConstructor(ClangImporter::Implementation &Impl,
10871087
// Construct the set of parameters from the list of members.
10881088
SmallVector<ParamDecl *, 8> valueParameters;
10891089
for (auto var : members) {
1090-
// TODO create value constructor with indirect fields instead of the
1091-
// generated __Anonymous_field.
1092-
if (var->hasClangNode() && isa<clang::IndirectFieldDecl>(var->getClangDecl()))
1093-
continue;
1090+
bool generateParamName = wantCtorParamNames;
1091+
1092+
if (var->hasClangNode()) {
1093+
// TODO create value constructor with indirect fields instead of the
1094+
// generated __Anonymous_field.
1095+
if (isa<clang::IndirectFieldDecl>(var->getClangDecl()))
1096+
continue;
1097+
1098+
if (auto clangField = dyn_cast<clang::FieldDecl>(var->getClangDecl()))
1099+
if (clangField->isAnonymousStructOrUnion())
1100+
generateParamName = false;
1101+
}
10941102

1095-
Identifier argName = wantCtorParamNames ? var->getName() : Identifier();
1103+
Identifier argName = generateParamName ? var->getName() : Identifier();
10961104
auto param = new (context)
10971105
ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(), argName,
10981106
SourceLoc(), var->getName(), var->getType(), structDecl);

test/ClangImporter/Inputs/custom-modules/IndirectFields.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,16 @@ union UnionWithIndirectField {
1414
};
1515
int c;
1616
};
17+
18+
struct DeepIndirectField {
19+
union {
20+
struct {
21+
int a;
22+
int b;
23+
};
24+
struct {
25+
int c;
26+
int d;
27+
};
28+
};
29+
};

test/ClangImporter/indirect_fields.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,25 @@
33
import IndirectFields
44

55
func build_struct(a: Int32, c: Int32, d: Int32) -> StructWithIndirectField {
6-
return StructWithIndirectField(__Anonymous_field0: .init(a: a), c: c, d: d)
6+
return StructWithIndirectField(.init(a: a), c: c, d: d)
77
}
88

99
func build_struct(b: Int32, c: Int32, d: Int32) -> StructWithIndirectField {
10-
return StructWithIndirectField(__Anonymous_field0: .init(b: b), c: c, d: d)
10+
return StructWithIndirectField(.init(b: b), c: c, d: d)
1111
}
1212

1313
func build_union(a: Int32, b: Int32) -> UnionWithIndirectField {
14-
return UnionWithIndirectField(__Anonymous_field0: .init(a: a, b: b))
14+
return UnionWithIndirectField(.init(a: a, b: b))
1515
}
1616

1717
func build_union(c: Int32) -> UnionWithIndirectField {
1818
return UnionWithIndirectField(c: c)
1919
}
20+
21+
func build_deep(a: Int32, b: Int32) -> DeepIndirectField {
22+
return DeepIndirectField(.init(.init(a: a, b: b)))
23+
}
24+
25+
func build_deep(c: Int32, d: Int32) -> DeepIndirectField {
26+
return DeepIndirectField(.init(.init(c: c, d: d)))
27+
}

0 commit comments

Comments
 (0)