Skip to content

Commit b6b6336

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 c3f247c commit b6b6336

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
@@ -1088,12 +1088,20 @@ createValueConstructor(ClangImporter::Implementation &Impl,
10881088
// Construct the set of parameters from the list of members.
10891089
SmallVector<ParamDecl *, 8> valueParameters;
10901090
for (auto var : members) {
1091-
// TODO create value constructor with indirect fields instead of the
1092-
// generated __Anonymous_field.
1093-
if (var->hasClangNode() && isa<clang::IndirectFieldDecl>(var->getClangDecl()))
1094-
continue;
1091+
bool generateParamName = wantCtorParamNames;
1092+
1093+
if (var->hasClangNode()) {
1094+
// TODO create value constructor with indirect fields instead of the
1095+
// generated __Anonymous_field.
1096+
if (isa<clang::IndirectFieldDecl>(var->getClangDecl()))
1097+
continue;
1098+
1099+
if (auto clangField = dyn_cast<clang::FieldDecl>(var->getClangDecl()))
1100+
if (clangField->isAnonymousStructOrUnion())
1101+
generateParamName = false;
1102+
}
10951103

1096-
Identifier argName = wantCtorParamNames ? var->getName() : Identifier();
1104+
Identifier argName = generateParamName ? var->getName() : Identifier();
10971105
auto param = new (context)
10981106
ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(), argName,
10991107
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)