Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[cxx-interop] Fix metadata mismatch regarding fields of structs #81035

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

susmonteiro
Copy link
Contributor

@susmonteiro susmonteiro commented Apr 23, 2025

In #78467 and #78961, we stopped emitting metadata for private C++ fields. However, this created a mismatch between the fields emitted and the number of fields + their offsets in the StructDescriptor.

rdar://147263490

@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

@susmonteiro susmonteiro added the c++ interop Feature: Interoperability with C++ label Apr 23, 2025
@susmonteiro susmonteiro force-pushed the susmonteiro/metadata-private-fields branch from f36ff56 to a39010b Compare April 24, 2025 10:59
@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

@susmonteiro susmonteiro marked this pull request as ready for review April 24, 2025 11:03
Copy link
Contributor

@Xazax-hun Xazax-hun left a comment

Choose a reason for hiding this comment

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

This is great, thanks for tracking this down! I am not super confident about some details, asked some questions inline. Maybe we should get someone more familiar with type metadata reviewed this PR.

@@ -1845,7 +1845,7 @@ namespace {

void addLayoutInfo() {
// uint32_t NumFields;
B.addInt32(getNumFields(getType()));
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we need to do something similar for ClassContextDescriptorBuilder too.

Copy link
Contributor

Choose a reason for hiding this comment

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

I am less sure about emitInitializeFieldOffsetVector and co. Maybe those are good as is but maybe we want to ask someone familiar with type metadata.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wonder if we need to do something similar for ClassContextDescriptorBuilder too.

Yes I think you're right. I intend to check if we need a similar fix for classes and add those changes in a future PR

Regarding emitInitializeFieldOffsetVector, I'm also not sure. I'll investigate this further

Copy link
Contributor

Choose a reason for hiding this comment

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

emitInitializeFieldOffsetVector should include all fields. We are using that information to handle values in value witness functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@drexin would it be a problem to have a discrepancy between the fields in emitInitializeFieldOffsetVector and the fields in StructContextDescriptorBuilder/FieldTypeMetadataBuilder?

Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, I am not sure. cc: @mikeash

Copy link
Contributor

Choose a reason for hiding this comment

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

Reflection relies on the indexes in the field offset vector and the indexes of the descriptor's fields lining up. In theory you could get away with having additional entries at the end of the field offset vector, but not in the middle, and not more field records than field offsets.

@@ -64,7 +65,8 @@ template <class Impl> class StructMetadataVisitor
// Struct field offsets.
asImpl().noteStartOfFieldOffsets();
for (VarDecl *prop : Target->getStoredProperties())
asImpl().addFieldOffset(prop);
if (!isPrivateField(prop))
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we can get out of sync with emitInitializeFieldOffsetVector here.

@susmonteiro susmonteiro force-pushed the susmonteiro/metadata-private-fields branch from a39010b to a49738e Compare April 24, 2025 14:49
@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

@susmonteiro susmonteiro force-pushed the susmonteiro/metadata-private-fields branch from a49738e to abd2549 Compare April 25, 2025 11:52
@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

// CHECK-linux-gnu: 42
// CHECK-linux-gnu: shared_ptr<CInt>()
printStdSharedPtrOfString()
// CHECK-macosx: basic_string<CChar, std.__1.char_traits<CChar>, std.__1.allocator<CChar>>()
Copy link
Contributor

Choose a reason for hiding this comment

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

Alternatively, you could add regexes that match on all platforms. I don't have a preference.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestion!
Hopefully we will soon fix the conformance of std::string to CustomStringConvertible. Then we can remove all these os options, since the value of the string will be printed instead of the type name.
That said, I don't mind switching to regex

Copy link
Contributor

Choose a reason for hiding this comment

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

Good point, the string one is temporary (maybe not the shared_ptr one though). Let's leave it as is.

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 right!

Copy link
Contributor

Choose a reason for hiding this comment

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

I think using regexes would be a bit more reliable here, since that would ensure the correct behavior on platforms that aren't listed here, e.g. Android or FreeBSD. The regex could be really permissive: something like {{.*}}.basic_string<CChar, {{.*}}> should do the trick.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I'll make this change.

@susmonteiro susmonteiro force-pushed the susmonteiro/metadata-private-fields branch from abd2549 to 2a99a7d Compare April 25, 2025 15:25
@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

Xazax-hun
Xazax-hun previously approved these changes Apr 25, 2025
// CHECK-linux-gnu: 42
// CHECK-linux-gnu: shared_ptr<CInt>()
printStdSharedPtrOfString()
// CHECK-macosx: basic_string<CChar, std.__1.char_traits<CChar>, std.__1.allocator<CChar>>()
Copy link
Contributor

Choose a reason for hiding this comment

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

Good point, the string one is temporary (maybe not the shared_ptr one though). Let's leave it as is.

@Xazax-hun Xazax-hun dismissed their stale review April 25, 2025 15:32

Misclicked.

@susmonteiro susmonteiro force-pushed the susmonteiro/metadata-private-fields branch from 2a99a7d to bdacdd0 Compare April 25, 2025 15:42
@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

@susmonteiro
Copy link
Contributor Author

@swift-ci Please test macOS platform

@egorzhdan egorzhdan requested a review from tbkka May 1, 2025 14:37
Copy link
Contributor

@egorzhdan egorzhdan left a comment

Choose a reason for hiding this comment

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

This looks great, thanks!
I only have a couple of comments on testing.

@@ -0,0 +1,24 @@
#ifndef TEST_INTEROP_CXX_STDLIB_INPUTS_STD_TYPES_H
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we reuse an existing test header in this directory, e.g. std-string-and-vector.h or std-vector.h and std-unique-ptr.h, instead of adding a new one?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure!

// CHECK-linux-gnu: 42
// CHECK-linux-gnu: shared_ptr<CInt>()
printStdSharedPtrOfString()
// CHECK-macosx: basic_string<CChar, std.__1.char_traits<CChar>, std.__1.allocator<CChar>>()
Copy link
Contributor

Choose a reason for hiding this comment

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

I think using regexes would be a bit more reliable here, since that would ensure the correct behavior on platforms that aren't listed here, e.g. Android or FreeBSD. The regex could be really permissive: something like {{.*}}.basic_string<CChar, {{.*}}> should do the trick.

@susmonteiro susmonteiro force-pushed the susmonteiro/metadata-private-fields branch from bdacdd0 to 3efa921 Compare May 7, 2025 15:18
@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ interop Feature: Interoperability with C++
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants