Skip to content

ClangImporter: use nameless arguments for anonymous struct/unions in constructors #6935

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

Fruneau
Copy link
Contributor

@Fruneau Fruneau commented Jan 20, 2017

Explanation

This patch follows that discussion: #6816 (review)

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))

Scope

This patch only impacts the constructor generation of structure/unions containing anonymous structure/union fields. This changes a behavior that was introduced during the development phase of the 3.1 release and as such shouldn't have impact on existing code.

Risk

None, since this patch only changes a behavior introduced in the development phase of the 3.1 release.

Testing

The patch includes the corresponding tests. AFAICT, no further testing is required.

@slavapestov
Copy link
Contributor

Looks good. @jrose-apple Do we want this for 3.1 as well, to maintain source compatibility between 3.1 and 4.0?

continue;
bool generateParamName = wantCtorParamNames;

if (var->hasClangNode()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: It seems like we should still honor wantCtorParamNames being false, even if no callers do this now with imported structs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, indeed, good catch. Fixed

@jrose-apple
Copy link
Contributor

Yeah, I agree, @slavapestov. No reason to have this diverge right when it's introduced.

…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]>
@Fruneau Fruneau force-pushed the anonymous-field-constructor branch from 6024b15 to 4c133fc Compare January 21, 2017 10:41
@jrose-apple
Copy link
Contributor

This does need to go into master before it can go to the 3.1 branch. (There's no automerge back to master.) The cherry-pick to the 3.1 branch should then follow the template described in the Swift 3.1 Release Process and must be approved by @tkremenek.

@DougGregor
Copy link
Member

@Fruneau , can you create a PR against master ?

@slavapestov
Copy link
Contributor

@swift-ci Please test

@swift-ci
Copy link
Contributor

Build failed
Jenkins build - Swift Test Linux Platform
Git Commit - 6024b15263a3c6120a68083f85b85582333f0caa
Test requested by - @slavapestov

@swift-ci
Copy link
Contributor

Build failed
Jenkins build - Swift Test OS X Platform
Git Commit - 6024b15263a3c6120a68083f85b85582333f0caa
Test requested by - @slavapestov

@slavapestov
Copy link
Contributor

@swift-ci Please test

@slavapestov slavapestov self-assigned this Jan 25, 2017
@jrose-apple
Copy link
Contributor

This needs to be approved by @tkremenek as release manager before it can be merged, and it still needs to follow the PR format for the release branch.

@Fruneau
Copy link
Contributor Author

Fruneau commented Jan 25, 2017

@jrose-apple I've updated the PR to match the requested format. Let me know if you think there are missing pieces of information in the description.

@ematejska ematejska merged commit 4f10511 into swiftlang:swift-3.1-branch Jan 26, 2017
@Fruneau Fruneau deleted the anonymous-field-constructor branch January 31, 2017 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants