Skip to content

Commit 34be8f9

Browse files
authored
Merge pull request #81228 from j-hui/fix-ast-layout-dependent-types
2 parents 3cad5c5 + ff596d5 commit 34be8f9

File tree

6 files changed

+79
-24
lines changed

6 files changed

+79
-24
lines changed

benchmark/cxx-source/CxxSetToCollection.swift

-4
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
// This is a benchmark that tracks how quickly Swift can convert a C++ set
1414
// to a Swift collection.
1515

16-
/* FIXME: rdar://150067288
17-
1816
import TestsUtils
1917
import CxxStdlibPerformance
2018
import Cxx
@@ -66,5 +64,3 @@ public func run_CxxSetOfU32_forEach(_ n: Int) {
6664
}
6765
}
6866
}
69-
70-
*/

benchmark/cxx-source/CxxStringConversion.swift

-4
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
/* FIXME: rdar://150067288
14-
1513
import TestsUtils
1614
import CxxStdlibPerformance
1715
import CxxStdlib
@@ -60,5 +58,3 @@ public func run_cxxToSwift(_ n: Int) {
6058
blackHole(x)
6159
}
6260
}
63-
64-
*/

benchmark/cxx-source/CxxVectorSum.swift

-4
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
// This is a benchmark that tracks how quickly Swift can sum up a C++ vector
1414
// as compared to the C++ implementation of such sum.
1515

16-
/* FIXME: rdar://150067288
17-
1816
import TestsUtils
1917
import CxxStdlibPerformance
2018
import Cxx
@@ -121,5 +119,3 @@ public func run_CxxVectorOfU32_Sum_Swift_Reduce(_ n: Int) {
121119
}
122120
blackHole(sum)
123121
}
124-
125-
*/

lib/ClangImporter/ImportDecl.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -4480,11 +4480,17 @@ namespace {
44804480
}
44814481

44824482
Decl *VisitFieldDecl(const clang::FieldDecl *decl) {
4483-
if (decl->hasAttr<clang::NoUniqueAddressAttr>()) {
4483+
if (!Impl.importSymbolicCXXDecls &&
4484+
decl->hasAttr<clang::NoUniqueAddressAttr>()) {
44844485
if (const auto *rd = decl->getType()->getAsRecordDecl()) {
44854486
// Clang can store the next field in the padding of this one. Swift
44864487
// does not support this yet so let's not import the field and
44874488
// represent it with an opaque blob in codegen.
4489+
//
4490+
// This check is not relevant when importing the decl symbolically
4491+
// (since that isn't used for codegen). In fact, we need to avoid this
4492+
// check because symbolic imports can expose us to dependent types
4493+
// whose ASTRecordLayout cannot be queried.
44884494
const auto &fieldLayout =
44894495
decl->getASTContext().getASTRecordLayout(rd);
44904496
auto &clangCtx = decl->getASTContext();

test/Interop/Cxx/class/Inputs/member-variables.h

+36-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define TEST_INTEROP_CXX_CLASS_INPUTS_MEMBER_VARIABLES_H
33

44
#include <cstddef>
5+
#include <type_traits>
56
#include <optional>
67

78
class MyClass {
@@ -27,25 +28,56 @@ struct HasZeroSizedField {
2728
void set_c(short c) { this->c = c; }
2829
};
2930

30-
struct ReuseFieldPadding {
31+
struct ReuseOptionalFieldPadding {
3132
[[no_unique_address]] std::optional<int> a = {2};
3233
char c;
3334
char get_c() const { return c; }
3435
void set_c(char c) { this->c = c; }
35-
int offset() const { return offsetof(ReuseFieldPadding, c); }
36+
int offset() const { return offsetof(ReuseOptionalFieldPadding, c); }
3637
std::optional<int> getOptional() { return a; }
3738
};
3839

3940
using OptInt = std::optional<int>;
4041

41-
struct ReuseFieldPaddingWithTypedef {
42+
struct ReuseOptionalFieldPaddingWithTypedef {
4243
[[no_unique_address]] OptInt a;
4344
char c;
4445
char get_c() const { return c; }
4546
void set_c(char c) { this->c = c; }
46-
int offset() const { return offsetof(ReuseFieldPadding, c); }
47+
int offset() const { return offsetof(ReuseOptionalFieldPadding, c); }
4748
};
4849

50+
// Using a mix of private and public fields prevents this class from being
51+
// standard-layout, which is necessary to allow clang to reuse its padding.
52+
template<typename T>
53+
struct NonStandardLayoutClass {
54+
private:
55+
T x;
56+
public:
57+
char pad_me;
58+
};
59+
static_assert(std::is_standard_layout_v<NonStandardLayoutClass<int>> == false);
60+
61+
struct ReuseNonStandardLayoutFieldPadding {
62+
[[no_unique_address]] NonStandardLayoutClass<int> a;
63+
char c;
64+
char get_c() const { return c; }
65+
void set_c(char c) { this->c = c; }
66+
// C-style implementation of offsetof() to avoid non-standard-layout warning
67+
int offset() const { return (char *) &this->c - (char *) this; }
68+
};
69+
70+
template<typename T>
71+
struct ReuseDependentFieldPadding {
72+
[[no_unique_address]] struct { private: T x; public: char pad_me; } a;
73+
char c;
74+
char get_c() const { return c; }
75+
void set_c(char c) { this->c = c; }
76+
// C-style implementation of offsetof() to avoid non-standard-layout warning
77+
int offset() const { return (char *) &this->c - (char *) this; }
78+
};
79+
80+
typedef ReuseDependentFieldPadding<int> ReuseDependentFieldPaddingInt;
4981

5082
inline int takesZeroSizedInCpp(HasZeroSizedField x) {
5183
return x.a;

test/Interop/Cxx/class/zero-sized-field.swift

+36-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -enable-experimental-cxx-interop -Xcc -std=c++20)
1+
// RUN: %empty-directory(%t/index)
2+
// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -enable-experimental-cxx-interop -Xcc -std=c++20 -Xfrontend -index-store-path -Xfrontend %t/index)
23
//
34
// REQUIRES: executable_test
45

@@ -24,12 +25,12 @@ FieldsTestSuite.test("Zero sized field") {
2425
expectEqual(s.b.getNum(), 42)
2526
}
2627

27-
FieldsTestSuite.test("Field padding reused") {
28-
var s = ReuseFieldPadding()
28+
FieldsTestSuite.test("Optional field padding reused") {
29+
var s = ReuseOptionalFieldPadding()
2930
let opt = s.getOptional()
3031
expectEqual(Int(opt.pointee), 2)
3132
s.c = 5
32-
expectEqual(Int(s.offset()), MemoryLayout<ReuseFieldPadding>.offset(of: \.c)!)
33+
expectEqual(Int(s.offset()), MemoryLayout<ReuseOptionalFieldPadding>.offset(of: \.c)!)
3334
expectEqual(s.c, 5)
3435
expectEqual(s.get_c(), 5)
3536
s.set_c(6)
@@ -40,10 +41,38 @@ FieldsTestSuite.test("Field padding reused") {
4041
expectEqual(s2.get_c(), 6)
4142
}
4243

43-
FieldsTestSuite.test("Typedef'd field padding reused") {
44-
var s = ReuseFieldPaddingWithTypedef()
44+
FieldsTestSuite.test("Typedef'd optional field padding reused") {
45+
var s = ReuseOptionalFieldPaddingWithTypedef()
4546
s.c = 5
46-
expectEqual(Int(s.offset()), MemoryLayout<ReuseFieldPadding>.offset(of: \.c)!)
47+
expectEqual(Int(s.offset()), MemoryLayout<ReuseOptionalFieldPadding>.offset(of: \.c)!)
48+
expectEqual(s.c, 5)
49+
expectEqual(s.get_c(), 5)
50+
s.set_c(6)
51+
expectEqual(s.c, 6)
52+
expectEqual(s.get_c(), 6)
53+
let s2 = s
54+
expectEqual(s2.c, 6)
55+
expectEqual(s2.get_c(), 6)
56+
}
57+
58+
FieldsTestSuite.test("Non-standard-layout field padding reused") {
59+
var s = ReuseNonStandardLayoutFieldPadding()
60+
s.c = 5
61+
expectEqual(Int(s.offset()), MemoryLayout<ReuseNonStandardLayoutFieldPadding>.offset(of: \.c)!)
62+
expectEqual(s.c, 5)
63+
expectEqual(s.get_c(), 5)
64+
s.set_c(6)
65+
expectEqual(s.c, 6)
66+
expectEqual(s.get_c(), 6)
67+
let s2 = s
68+
expectEqual(s2.c, 6)
69+
expectEqual(s2.get_c(), 6)
70+
}
71+
72+
FieldsTestSuite.test("Non-standard-layout field padding in templated class reused") {
73+
var s = ReuseDependentFieldPaddingInt()
74+
s.c = 5
75+
expectEqual(Int(s.offset()), MemoryLayout<ReuseDependentFieldPaddingInt>.offset(of: \.c)!)
4776
expectEqual(s.c, 5)
4877
expectEqual(s.get_c(), 5)
4978
s.set_c(6)

0 commit comments

Comments
 (0)