-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Clang Importer: import all indirect fields. #6531
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
Conversation
Excellent! |
Thanks for looking at this, @Fruneau! The reason it is the way it is today is because we wanted to avoid having to generate names for types, which can then show up in mangling and such. I'm concerned about tying names to declaration order. On the other hand, though, it's not too different from other kinds of "binary-compatible" changes you can make in C, like replacing one struct with another one that's layout-compatible. Hm. cc @milseman |
@jrose-apple We could ban users from referencing the types by name. If they don't appear in public declaration signatures they shouldn't get mangled either. |
@swift-ci Please smoke test |
@jrose-apple Thx for the feedback. I don't really think the patch is about generating type names, since the mechanism for generating type names was already in place (it was introduced in commit 0235967). This is more about renaming anonymous fields, which has the side effect of generating more type names since those fields were previously ignored. |
It looks like this introduces a problem with duplicate members added somewhere?
|
@slavapestov It looks like the GLKit worked-around the lack of indirect field exposition by adding swift extensions to some of their structures. I don't know what the right approach is at this point. I can see several possibilities:
|
Since the GLKit overlay is also part of this repository, we can certainly just edit it if we get sign-off from some of the GLKit folks. I am worried about existing third-party libraries having done the same thing, though. Another option would be to change overload resolution to allow overlays to shadow imported members, or to always prefer members in the original type over members in extensions. @rudkx, @DougGregor, any thoughts on those? |
My preference is to fix the GLKit overlay and remove the workaround there. Another option is to only import indirect fields in Swift 4 mode. I'm worried about introducing a one-off workaround to overload resolution to handle this case, it might be more trouble than it's worth. |
We could also give the indirect members unique names, maybe with some kind of prefix. But again, ugh... let's try to just fix GLKit and see if there is any additional fallout. We can always change the policy later. |
Ho! I just didn't see the overlay was part of the repository (I tried to grep |
b174d79
to
71529ba
Compare
@swift-ci Please smoke test |
71529ba
to
1636745
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks fantastic, thank you! Just a few minor concerns, then I'd like to get it tested and merged.
As for the GLKit overlay, I am absolutely fine with making the changes in the implementation of the overlay when we're getting the same API out of it. The overlay here is working around Clang importer limitations; we can fix the overlay when we remove the limitations.
It is possible that there are other sources like this overlay that will break with this change. Personally, I'd like to see if that happens in the wild before we go and add a Swift 4 version check + associated trickery here.
@@ -2544,6 +2659,25 @@ namespace { | |||
|
|||
auto VD = cast<VarDecl>(member); | |||
|
|||
if (isa<clang::IndirectFieldDecl>(nd) || decl->isUnion()) { | |||
// Don't import unconditionnaly unavailable fields that have |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo "unconditionnaly".
if (isUnconditionallyUnavailable) { | ||
continue; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This loop looks equivalent to VD->getAttrs().isUnavailable(VD->getASTContext())
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not strictly equivalent since using isUnavailable()
will cause the fields to be hidden for any unavailability reason (not just unconditional unavailability).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... Can you at least pull this out into a separate static function, then? It's odd to have the loop inlined here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually repushed with isUnavailable()
since after a few manual tests it does not seem to affect error reporting (I was worried that the error message for accessing an unimported field would be different from the one we get for an unavailable field, but it does not seem to be the case).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, thanks!
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]>
1636745
to
68bc423
Compare
@swift-ci Please smoke test |
@@ -58,69 +48,15 @@ def defineSubscript(Type, limit): | |||
% for size in [2, 3, 4]: | |||
|
|||
extension GLKMatrix${size} { | |||
public typealias _Tuple = (${ ', '.join(['Float'] * (size * size)) }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really great to see this gunk go away.
Just waiting to see if @DougGregor has any more feedback. |
Nope, I'm happy with it now. Thanks! |
@Fruneau Do you mind creating a new PR to add an entry to CHANGLEOG.md as well? We have several new ClangImporter features that might affect users so I'm following up with PR authors about documenting them. |
Following PR swiftlang#6531 there is a position mismatch in the final loop between the position of the member in the members arrays and the position in the valueParameters array. As a consequence, a structure containing indirect fields before a computed properties (like a bitfield) caused an invalid access in the valueParameters array resulting in a crash of the compiler. This patch maintains a separate position for accessing valueParameters. A non-regression test is also added. Signed-off-by: Florent Bruneau <[email protected]>
ClangImporter: fix crash when importing type containing bitfields (regression from #6531)
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.
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 idis 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 exposedas a computed property.
The C object:
Is imported as
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.