Skip to content

Commit bc55dba

Browse files
authored
Merge pull request #31070 from hlopko/statics-tests
[CxxInterop] Expose C++ static members as Swift static properties
2 parents 9c1615c + 8832627 commit bc55dba

24 files changed

+558
-62
lines changed

lib/AST/ASTMangler.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@
3333
#include "swift/Demangling/ManglingUtils.h"
3434
#include "swift/Demangling/Demangler.h"
3535
#include "swift/Strings.h"
36+
#include "clang/AST/ASTContext.h"
3637
#include "clang/Basic/CharInfo.h"
3738
#include "clang/AST/Attr.h"
3839
#include "clang/AST/Decl.h"
3940
#include "clang/AST/DeclObjC.h"
41+
#include "clang/AST/Mangle.h"
4042
#include "llvm/ADT/DenseMap.h"
4143
#include "llvm/ADT/SmallString.h"
4244
#include "llvm/ADT/StringRef.h"
@@ -235,14 +237,19 @@ std::string ASTMangler::mangleClosureWitnessThunk(
235237
}
236238

237239
std::string ASTMangler::mangleGlobalVariableFull(const VarDecl *decl) {
238-
// As a special case, Clang functions and globals don't get mangled at all.
239-
// FIXME: When we can import C++, use Clang's mangler.
240+
// Clang globals get mangled using Clang's mangler.
240241
if (auto clangDecl =
241242
dyn_cast_or_null<clang::DeclaratorDecl>(decl->getClangDecl())) {
242243
if (auto asmLabel = clangDecl->getAttr<clang::AsmLabelAttr>()) {
243244
Buffer << '\01' << asmLabel->getLabel();
244245
} else {
245-
Buffer << clangDecl->getName();
246+
if (clangDecl->getDeclContext()->isTranslationUnit()) {
247+
Buffer << clangDecl->getName();
248+
} else {
249+
clang::MangleContext *mangler =
250+
decl->getClangDecl()->getASTContext().createMangleContext();
251+
mangler->mangleName(clangDecl, Buffer);
252+
}
246253
}
247254
return finalize();
248255
}

lib/ClangImporter/ImportDecl.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3954,10 +3954,6 @@ namespace {
39543954
}
39553955

39563956
Decl *VisitVarDecl(const clang::VarDecl *decl) {
3957-
// FIXME: Swift does not have static variables in structs/classes yet.
3958-
if (decl->getDeclContext()->isRecord())
3959-
return nullptr;
3960-
39613957
// Variables are imported as... variables.
39623958
Optional<ImportedName> correctSwiftName;
39633959
auto importedName = importFullName(decl, correctSwiftName);

test/Interop/Cxx/class/access-specifiers-module-interface.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
// CHECK-NEXT: typealias Element = PublicPrivate.PublicFlagEnum
3838
// CHECK-NEXT: typealias ArrayLiteralElement = PublicPrivate.PublicFlagEnum
3939
// CHECK-NEXT: }
40+
// CHECK-NEXT: static var PublicStaticMemberVar: Int32
4041
// CHECK-NEXT: var PublicMemberVar: Int32
4142
// CHECK-NEXT: init()
4243
// CHECK-NEXT: mutating func publicMemberFunc()

test/Interop/Cxx/class/access-specifiers-typechecker.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ var v = PublicPrivate()
1010
// Can access all public members and types.
1111

1212
v.PublicMemberVar = 1
13-
// TODO: Static member variables don't appear to be imported correctly yet. Once
14-
// they are, verify that PublicStaticMemberVar is accessible.
15-
// PublicPrivate.PublicStaticMemberVar = 1
13+
PublicPrivate.PublicStaticMemberVar = 1
1614
v.publicMemberFunc()
1715

1816
var publicTypedefVar: PublicPrivate.PublicTypedef
@@ -29,8 +27,6 @@ var publicFlagEnumVar: PublicPrivate.PublicFlagEnum
2927
// Cannot access any private members and types.
3028

3129
v.PrivateMemberVar = 1 // expected-error {{value of type 'PublicPrivate' has no member 'PrivateMemberVar'}}
32-
// TODO: This gives the expected error, but only because static member variables
33-
// (private or public) aren't imported at all. Once that is fixed, remove this
3430
PublicPrivate.PrivateStaticMemberVar = 1 // expected-error {{'PublicPrivate' has no member 'PrivateStaticMemberVar'}}
3531
v.privateMemberFunc() // expected-error {{value of type 'PublicPrivate' has no member 'privateMemberFunc'}}
3632

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
int counter = 12;
22

3-
int getCounterFromCxx() {
4-
return counter;
5-
}
3+
int getCounterFromCxx() { return counter; }
64

7-
void setCounterFromCxx(int c) {
8-
counter = c;
9-
}
5+
void setCounterFromCxx(int c) { counter = c; }
106

117
namespace Namespaced {
12-
int counter = 12;
8+
int counter = 12;
139

14-
int getCounterFromCxx() {
15-
return counter;
16-
}
10+
int getCounterFromCxx() { return counter; }
1711

18-
void setCounterFromCxx(int c) {
19-
counter = c;
20-
}
21-
}
12+
void setCounterFromCxx(int c) { counter = c; }
13+
} // namespace Namespaced

test/Interop/Cxx/extern-var/Inputs/extern-var.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ int getCounterFromCxx();
44
void setCounterFromCxx(int);
55

66
namespace Namespaced {
7-
extern int counter;
7+
extern int counter;
88

9-
int getCounterFromCxx();
10-
void setCounterFromCxx(int);
11-
}
9+
int getCounterFromCxx();
10+
void setCounterFromCxx(int);
11+
} // namespace Namespaced

test/Interop/Cxx/extern-var/extern-var-irgen.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public func getCounter() -> CInt {
77
}
88

99
// CHECK: @{{counter|"\?counter@@3HA"}} = external {{(dso_local )?}}global i32, align 4
10+
// CHECK: @{{_ZN10Namespaced7counterE|"\?counter@Namespaced@@3HA"}} = external {{(dso_local )?}}global i32, align 4
1011

1112
// CHECK: define {{(protected |dllexport )?}}swiftcc i32 @"$s4main10getCounters5Int32VyF"() #0
1213
// CHECK: [[LOAD:%.*]] = load i32, i32* getelementptr inbounds (%Ts5Int32V, %Ts5Int32V* bitcast (i32* @{{counter|"\?counter@@3HA"}} to %Ts5Int32V*), i32 0, i32 0), align 4
@@ -24,17 +25,15 @@ public func getNamespacedCounter() -> CInt {
2425
}
2526

2627
// CHECK: define {{(protected |dllexport )?}}swiftcc i32 @"$s4main20getNamespacedCounters5Int32VyF"() #0
27-
//FIXME mangle non-top-level var names to prevent name collisions and check:
28-
// load i32, i32* getelementptr inbounds (%Ts5Int32V, %Ts5Int32V* bitcast (i32* @Namespaced.counter to %Ts5Int32V*), i32 0, i32 0), align 4
28+
// CHECK: load i32, i32* getelementptr inbounds (%Ts5Int32V, %Ts5Int32V* bitcast (i32* @{{_ZN10Namespaced7counterE|"\?counter@Namespaced@@3HA"}} to %Ts5Int32V*), i32 0, i32 0), align 4
2929
// CHECK: ret i32 %1
3030

3131
public func setNamespacedCounter(_ c: CInt) {
3232
Namespaced.counter = c
3333
}
3434

3535
// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20setNamespacedCounteryys5Int32VF"(i32 %0) #0
36-
//FIXME mangle non-top-level var names to prevent name collisions and check:
37-
// store i32 %0, i32* getelementptr inbounds (%Ts5Int32V, %Ts5Int32V* bitcast (i32* @Namespaced.counter to %Ts5Int32V*), i32 0, i32 0), align 4
36+
// CHECK: store i32 %0, i32* getelementptr inbounds (%Ts5Int32V, %Ts5Int32V* bitcast (i32* @{{_ZN10Namespaced7counterE|"\?counter@Namespaced@@3HA"}} to %Ts5Int32V*), i32 0, i32 0), align 4
3837

3938
func modifyInout(_ c: inout CInt) {
4039
c = 42
@@ -46,4 +45,3 @@ public func passingVarAsInout() {
4645

4746
// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main17passingVarAsInoutyyF"() #0
4847
// CHECK: call swiftcc void @"$s4main11modifyInoutyys5Int32VzF"(%Ts5Int32V* nocapture dereferenceable(4) bitcast (i32* @{{counter|"\?counter@@3HA"}} to %Ts5Int32V*))
49-

test/Interop/Cxx/extern-var/extern-var-silgen.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ func getCounter() -> CInt {
77
}
88

99
// CHECK: sil_global @counter : $Int32
10+
// CHECK: sil_global @{{_ZN10Namespaced7counterE|\?counter@Namespaced@@3HA}} : $Int32
1011

1112
// CHECK: sil hidden @$s4main10getCounters5Int32VyF : $@convention(thin) () -> Int32
1213
// CHECK: [[COUNTER:%.*]] = global_addr @counter : $*Int32
@@ -28,9 +29,8 @@ func getNamespacedCounter() -> CInt {
2829
}
2930

3031
// sil hidden @$s4main20getNamespacedCounters5Int32VyF : $@convention(thin) () -> Int32
31-
//FIXME mangle non-top-level var names to prevent name collisions
32-
// %0 = global_addr @Namespaced.counter : $*Int32
33-
// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] %0 : $*Int32
32+
// CHECK: [[ADDR:%.*]] = global_addr @{{_ZN10Namespaced7counterE|\?counter@Namespaced@@3HA}} : $*Int32
33+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[ADDR]] : $*Int32
3434
// CHECK: [[LOAD:%.*]] = load [[ACCESS]] : $*Int32
3535
// CHECK: return [[LOAD]] : $Int32
3636

@@ -39,9 +39,8 @@ func setNamespacedCounter(_ c: CInt) {
3939
}
4040

4141
// CHECK: sil hidden @$s4main20setNamespacedCounteryys5Int32VF : $@convention(thin) (Int32) -> ()
42-
//FIXME mangle non-top-level var names to prevent name collisions
43-
// %1 = global_addr @Namespaced.counter : $*Int32
44-
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] %1 : $*Int32
42+
// CHECK: [[ADDR:%.*]] = global_addr @{{_ZN10Namespaced7counterE|\?counter@Namespaced@@3HA}} : $*Int32
43+
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADDR]] : $*Int32
4544
// CHECK: store %0 to [[ACCESS]] : $*Int32
4645

4746
func modifyInout(_ c: inout CInt) {

test/Interop/Cxx/extern-var/extern-var.swift

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,25 @@ ExternVarTestSuite.test("write-from-cxx") {
2323
expectEqual(84, getCounterFromCxx())
2424
}
2525

26-
//FIXME mangle non-top-level var names to prevent name collisions
27-
// ExternVarTestSuite.test("namespaced-write-from-swift") {
28-
// Namespaced.counter = 42
29-
// expectEqual(42, Namespaced.counter)
30-
// expectEqual(42, amespaced.getCounterFromCxx())
31-
// }
32-
33-
//FIXME mangle non-top-level var names to prevent name collisions
34-
// ExternVarTestSuite.test("namespaced-write-from-cxx") {
35-
// Namespaced.setCounterFromCxx(84)
36-
// expectEqual(84, Namespaced.counter)
37-
// expectEqual(84, Namespaced.getCounterFromCxx())
38-
// }
39-
40-
//FIXME mangle non-top-level var names to prevent name collisions
41-
// ExternVarTestSuite.test("no-collisions") {
42-
// counter = 12
43-
// Namespaced.counter = 42
44-
// expectEqual(12, counter)
45-
// expectEqual(42, Namespaced.counter)
46-
// }
26+
ExternVarTestSuite.test("namespaced-write-from-swift") {
27+
Namespaced.counter = 42
28+
expectEqual(42, Namespaced.counter)
29+
expectEqual(42, Namespaced.getCounterFromCxx())
30+
}
31+
32+
ExternVarTestSuite.test("namespaced-write-from-cxx") {
33+
Namespaced.setCounterFromCxx(84)
34+
expectEqual(84, Namespaced.counter)
35+
expectEqual(84, Namespaced.getCounterFromCxx())
36+
}
37+
38+
// Check that variables with identical names in different namespaces don't
39+
// collide in any intermediate representation of the compiler.
40+
ExternVarTestSuite.test("no-collisions") {
41+
counter = 12
42+
Namespaced.counter = 42
43+
expectEqual(12, counter)
44+
expectEqual(42, Namespaced.counter)
45+
}
4746

4847
runAllTests()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include "inline-static-member-var.h"
2+
3+
int *WithInlineStaticMember::getStaticMemberAddress() { return &staticMember; }
4+
5+
int WithInlineStaticMember::getStaticMemberFromCxx() { return staticMember; }
6+
7+
void WithInlineStaticMember::setStaticMemberFromCxx(int newVal) {
8+
staticMember = newVal;
9+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
inline static int init() { return 42; }
2+
3+
class WithInlineStaticMember {
4+
public:
5+
inline static int staticMember = 12;
6+
//TODO needs C++ stdlib symbols, fix after apple/swift#30914 is merged.
7+
// inline static int staticMemberInitializedAtRuntime = init();
8+
9+
static int getStaticMemberFromCxx();
10+
static int *getStaticMemberAddress();
11+
static void setStaticMemberFromCxx(int);
12+
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module StaticLocalVar {
2+
header "static-local-var.h"
3+
}
4+
5+
module StaticMemberVar {
6+
header "static-member-var.h"
7+
}
8+
9+
module InlineStaticMemberVar {
10+
header "inline-static-member-var.h"
11+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include "static-local-var.h"
2+
3+
int counterWrapper() {
4+
return counter();
5+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
int counterWrapper();
2+
3+
inline int counter() {
4+
static int a = 0;
5+
return a++;
6+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "static-member-var.h"
2+
3+
int WithStaticMember::staticMember = 42;
4+
5+
int *WithStaticMember::getStaticMemberAddress() { return &staticMember; }
6+
7+
int WithStaticMember::getStaticMemberFromCxx() { return staticMember; }
8+
9+
void WithStaticMember::setStaticMemberFromCxx(int newVal) {
10+
staticMember = newVal;
11+
}
12+
13+
int WithIncompleteStaticMember::arrayMember[3] = {18, 19, 20};
14+
15+
WithIncompleteStaticMember WithIncompleteStaticMember::selfMember =
16+
WithIncompleteStaticMember();
17+
18+
WithIncompleteStaticMember *
19+
WithIncompleteStaticMember::getStaticMemberFromCxx() {
20+
return &selfMember;
21+
}
22+
23+
void WithIncompleteStaticMember::setStaticMemberFromCxx(
24+
WithIncompleteStaticMember newVal) {
25+
selfMember = newVal;
26+
}
27+
28+
const int WithConstStaticMember::defined;
29+
const int WithConstStaticMember::definedOutOfLine = 96;
30+
31+
int ClassA::notUniqueName = 144;
32+
int ClassB::notUniqueName = 169;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
class WithStaticMember {
2+
public:
3+
static int staticMember;
4+
static int *getStaticMemberAddress();
5+
static int getStaticMemberFromCxx();
6+
static void setStaticMemberFromCxx(int);
7+
};
8+
9+
class WithIncompleteStaticMember {
10+
public:
11+
static int arrayMember[];
12+
static WithIncompleteStaticMember selfMember;
13+
int id = 3;
14+
15+
static WithIncompleteStaticMember *getStaticMemberFromCxx();
16+
static void setStaticMemberFromCxx(WithIncompleteStaticMember);
17+
};
18+
19+
class WithConstStaticMember {
20+
public:
21+
const static int notDefined = 24;
22+
const static int defined = 48;
23+
const static int definedOutOfLine;
24+
};
25+
26+
class WithConstexprStaticMember {
27+
public:
28+
constexpr static int definedInline = 139;
29+
};
30+
31+
class ClassA {
32+
public:
33+
static int notUniqueName;
34+
};
35+
36+
class ClassB {
37+
public:
38+
static int notUniqueName;
39+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-clang -c %S/Inputs/static-member-var.cc -I %S/Inputs -o %t/static-member-var.o -std=c++17
3+
// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-member-var.o -Xfrontend -enable-cxx-interop -Xcc -std=c++17
4+
// RUN: %target-codesign %t/statics
5+
// RUN: %target-run %t/statics
6+
//
7+
// REQUIRES: executable_test
8+
9+
import StaticMemberVar
10+
import StdlibUnittest
11+
12+
var ConstexprStaticMemberVarTestSuite = TestSuite("ConstexprStaticMemberVarTestSuite")
13+
14+
ConstexprStaticMemberVarTestSuite.test("constexpr-static-member") {
15+
expectEqual(139, WithConstexprStaticMember.definedInline)
16+
}
17+
18+
runAllTests()
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %target-swift-emit-ir -I %S/Inputs -enable-cxx-interop %s | %FileCheck %s
2+
3+
import InlineStaticMemberVar
4+
5+
public func readStaticMember() -> CInt {
6+
return WithInlineStaticMember.staticMember
7+
}
8+
9+
// CHECK: @{{_ZN22WithInlineStaticMember12staticMemberE|"\?staticMember@WithInlineStaticMember@@2HA"}} = linkonce_odr {{(dso_local )?}}global i32 12, {{(comdat, )?}}align 4
10+
11+
// CHECK: define {{(protected |dllexport )?}}swiftcc i32 @"$s4main16readStaticMembers5Int32VyF"()
12+
// CHECK: [[VALUE:%.*]] = load i32, i32* getelementptr inbounds (%Ts5Int32V, %Ts5Int32V* bitcast (i32* @{{_ZN22WithInlineStaticMember12staticMemberE|"\?staticMember@WithInlineStaticMember@@2HA"}} to %Ts5Int32V*), i32 0, i32 0), align 4
13+
// CHECK: ret i32 [[VALUE]]
14+
15+
public func writeStaticMember(_ c: CInt) {
16+
WithInlineStaticMember.staticMember = c
17+
}
18+
19+
// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main17writeStaticMemberyys5Int32VF"(i32 %0)
20+
// CHECK: store i32 %0, i32* getelementptr inbounds (%Ts5Int32V, %Ts5Int32V* bitcast (i32* @{{_ZN22WithInlineStaticMember12staticMemberE|"\?staticMember@WithInlineStaticMember@@2HA"}} to %Ts5Int32V*), i32 0, i32 0), align 4
21+
22+
func modifyInout(_ c: inout CInt) {
23+
c = 42
24+
}
25+
26+
public func passingVarAsInout() {
27+
modifyInout(&WithInlineStaticMember.staticMember)
28+
}
29+
30+
// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main17passingVarAsInoutyyF"()
31+
// CHECK: call swiftcc void @"$s4main11modifyInoutyys5Int32VzF"(%Ts5Int32V* nocapture dereferenceable(4) bitcast (i32* @{{_ZN22WithInlineStaticMember12staticMemberE|"\?staticMember@WithInlineStaticMember@@2HA"}} to %Ts5Int32V*))

0 commit comments

Comments
 (0)