diff --git a/benchmark/cxx-source/CxxSetToCollection.swift b/benchmark/cxx-source/CxxSetToCollection.swift index 4af092075982d..5a9e9904ba706 100644 --- a/benchmark/cxx-source/CxxSetToCollection.swift +++ b/benchmark/cxx-source/CxxSetToCollection.swift @@ -13,8 +13,6 @@ // This is a benchmark that tracks how quickly Swift can convert a C++ set // to a Swift collection. -/* FIXME: rdar://150067288 - import TestsUtils import CxxStdlibPerformance import Cxx @@ -66,5 +64,3 @@ public func run_CxxSetOfU32_forEach(_ n: Int) { } } } - -*/ diff --git a/benchmark/cxx-source/CxxStringConversion.swift b/benchmark/cxx-source/CxxStringConversion.swift index 8ab65a8065ba5..a10418800e269 100644 --- a/benchmark/cxx-source/CxxStringConversion.swift +++ b/benchmark/cxx-source/CxxStringConversion.swift @@ -10,8 +10,6 @@ // //===----------------------------------------------------------------------===// -/* FIXME: rdar://150067288 - import TestsUtils import CxxStdlibPerformance import CxxStdlib @@ -60,5 +58,3 @@ public func run_cxxToSwift(_ n: Int) { blackHole(x) } } - -*/ diff --git a/benchmark/cxx-source/CxxVectorSum.swift b/benchmark/cxx-source/CxxVectorSum.swift index c17d5ec22abed..ad6d37773e583 100644 --- a/benchmark/cxx-source/CxxVectorSum.swift +++ b/benchmark/cxx-source/CxxVectorSum.swift @@ -13,8 +13,6 @@ // This is a benchmark that tracks how quickly Swift can sum up a C++ vector // as compared to the C++ implementation of such sum. -/* FIXME: rdar://150067288 - import TestsUtils import CxxStdlibPerformance import Cxx @@ -121,5 +119,3 @@ public func run_CxxVectorOfU32_Sum_Swift_Reduce(_ n: Int) { } blackHole(sum) } - -*/ diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 734fae0d59257..87f439a8d2b75 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -4480,11 +4480,17 @@ namespace { } Decl *VisitFieldDecl(const clang::FieldDecl *decl) { - if (decl->hasAttr()) { + if (!Impl.importSymbolicCXXDecls && + decl->hasAttr()) { if (const auto *rd = decl->getType()->getAsRecordDecl()) { // Clang can store the next field in the padding of this one. Swift // does not support this yet so let's not import the field and // represent it with an opaque blob in codegen. + // + // This check is not relevant when importing the decl symbolically + // (since that isn't used for codegen). In fact, we need to avoid this + // check because symbolic imports can expose us to dependent types + // whose ASTRecordLayout cannot be queried. const auto &fieldLayout = decl->getASTContext().getASTRecordLayout(rd); auto &clangCtx = decl->getASTContext(); diff --git a/test/Interop/Cxx/class/Inputs/member-variables.h b/test/Interop/Cxx/class/Inputs/member-variables.h index fbf6b3ecf4998..720939a591a84 100644 --- a/test/Interop/Cxx/class/Inputs/member-variables.h +++ b/test/Interop/Cxx/class/Inputs/member-variables.h @@ -2,6 +2,7 @@ #define TEST_INTEROP_CXX_CLASS_INPUTS_MEMBER_VARIABLES_H #include +#include #include class MyClass { @@ -27,25 +28,56 @@ struct HasZeroSizedField { void set_c(short c) { this->c = c; } }; -struct ReuseFieldPadding { +struct ReuseOptionalFieldPadding { [[no_unique_address]] std::optional a = {2}; char c; char get_c() const { return c; } void set_c(char c) { this->c = c; } - int offset() const { return offsetof(ReuseFieldPadding, c); } + int offset() const { return offsetof(ReuseOptionalFieldPadding, c); } std::optional getOptional() { return a; } }; using OptInt = std::optional; -struct ReuseFieldPaddingWithTypedef { +struct ReuseOptionalFieldPaddingWithTypedef { [[no_unique_address]] OptInt a; char c; char get_c() const { return c; } void set_c(char c) { this->c = c; } - int offset() const { return offsetof(ReuseFieldPadding, c); } + int offset() const { return offsetof(ReuseOptionalFieldPadding, c); } }; +// Using a mix of private and public fields prevents this class from being +// standard-layout, which is necessary to allow clang to reuse its padding. +template +struct NonStandardLayoutClass { +private: + T x; +public: + char pad_me; +}; +static_assert(std::is_standard_layout_v> == false); + +struct ReuseNonStandardLayoutFieldPadding { + [[no_unique_address]] NonStandardLayoutClass a; + char c; + char get_c() const { return c; } + void set_c(char c) { this->c = c; } + // C-style implementation of offsetof() to avoid non-standard-layout warning + int offset() const { return (char *) &this->c - (char *) this; } +}; + +template +struct ReuseDependentFieldPadding { + [[no_unique_address]] struct { private: T x; public: char pad_me; } a; + char c; + char get_c() const { return c; } + void set_c(char c) { this->c = c; } + // C-style implementation of offsetof() to avoid non-standard-layout warning + int offset() const { return (char *) &this->c - (char *) this; } +}; + +typedef ReuseDependentFieldPadding ReuseDependentFieldPaddingInt; inline int takesZeroSizedInCpp(HasZeroSizedField x) { return x.a; diff --git a/test/Interop/Cxx/class/zero-sized-field.swift b/test/Interop/Cxx/class/zero-sized-field.swift index 0706daf12d770..115f4df19c360 100644 --- a/test/Interop/Cxx/class/zero-sized-field.swift +++ b/test/Interop/Cxx/class/zero-sized-field.swift @@ -1,4 +1,5 @@ -// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -enable-experimental-cxx-interop -Xcc -std=c++20) +// RUN: %empty-directory(%t/index) +// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -enable-experimental-cxx-interop -Xcc -std=c++20 -Xfrontend -index-store-path -Xfrontend %t/index) // // REQUIRES: executable_test @@ -24,12 +25,12 @@ FieldsTestSuite.test("Zero sized field") { expectEqual(s.b.getNum(), 42) } -FieldsTestSuite.test("Field padding reused") { - var s = ReuseFieldPadding() +FieldsTestSuite.test("Optional field padding reused") { + var s = ReuseOptionalFieldPadding() let opt = s.getOptional() expectEqual(Int(opt.pointee), 2) s.c = 5 - expectEqual(Int(s.offset()), MemoryLayout.offset(of: \.c)!) + expectEqual(Int(s.offset()), MemoryLayout.offset(of: \.c)!) expectEqual(s.c, 5) expectEqual(s.get_c(), 5) s.set_c(6) @@ -40,10 +41,38 @@ FieldsTestSuite.test("Field padding reused") { expectEqual(s2.get_c(), 6) } -FieldsTestSuite.test("Typedef'd field padding reused") { - var s = ReuseFieldPaddingWithTypedef() +FieldsTestSuite.test("Typedef'd optional field padding reused") { + var s = ReuseOptionalFieldPaddingWithTypedef() s.c = 5 - expectEqual(Int(s.offset()), MemoryLayout.offset(of: \.c)!) + expectEqual(Int(s.offset()), MemoryLayout.offset(of: \.c)!) + expectEqual(s.c, 5) + expectEqual(s.get_c(), 5) + s.set_c(6) + expectEqual(s.c, 6) + expectEqual(s.get_c(), 6) + let s2 = s + expectEqual(s2.c, 6) + expectEqual(s2.get_c(), 6) +} + +FieldsTestSuite.test("Non-standard-layout field padding reused") { + var s = ReuseNonStandardLayoutFieldPadding() + s.c = 5 + expectEqual(Int(s.offset()), MemoryLayout.offset(of: \.c)!) + expectEqual(s.c, 5) + expectEqual(s.get_c(), 5) + s.set_c(6) + expectEqual(s.c, 6) + expectEqual(s.get_c(), 6) + let s2 = s + expectEqual(s2.c, 6) + expectEqual(s2.get_c(), 6) +} + +FieldsTestSuite.test("Non-standard-layout field padding in templated class reused") { + var s = ReuseDependentFieldPaddingInt() + s.c = 5 + expectEqual(Int(s.offset()), MemoryLayout.offset(of: \.c)!) expectEqual(s.c, 5) expectEqual(s.get_c(), 5) s.set_c(6)