Skip to content

[CxxInterop] Expose C++ static members as Swift static properties #31070

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

Merged
merged 1 commit into from
Apr 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@
#include "swift/Demangling/ManglingUtils.h"
#include "swift/Demangling/Demangler.h"
#include "swift/Strings.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/CharInfo.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Mangle.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -235,14 +237,19 @@ std::string ASTMangler::mangleClosureWitnessThunk(
}

std::string ASTMangler::mangleGlobalVariableFull(const VarDecl *decl) {
// As a special case, Clang functions and globals don't get mangled at all.
// FIXME: When we can import C++, use Clang's mangler.
// Clang globals get mangled using Clang's mangler.
if (auto clangDecl =
dyn_cast_or_null<clang::DeclaratorDecl>(decl->getClangDecl())) {
if (auto asmLabel = clangDecl->getAttr<clang::AsmLabelAttr>()) {
Buffer << '\01' << asmLabel->getLabel();
} else {
Buffer << clangDecl->getName();
if (clangDecl->getDeclContext()->isTranslationUnit()) {
Buffer << clangDecl->getName();
} else {
clang::MangleContext *mangler =
decl->getClangDecl()->getASTContext().createMangleContext();
mangler->mangleName(clangDecl, Buffer);
}
}
return finalize();
}
Expand Down
4 changes: 0 additions & 4 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3954,10 +3954,6 @@ namespace {
}

Decl *VisitVarDecl(const clang::VarDecl *decl) {
// FIXME: Swift does not have static variables in structs/classes yet.
if (decl->getDeclContext()->isRecord())
return nullptr;

// Variables are imported as... variables.
Optional<ImportedName> correctSwiftName;
auto importedName = importFullName(decl, correctSwiftName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
// CHECK-NEXT: typealias Element = PublicPrivate.PublicFlagEnum
// CHECK-NEXT: typealias ArrayLiteralElement = PublicPrivate.PublicFlagEnum
// CHECK-NEXT: }
// CHECK-NEXT: static var PublicStaticMemberVar: Int32
// CHECK-NEXT: var PublicMemberVar: Int32
// CHECK-NEXT: init()
// CHECK-NEXT: mutating func publicMemberFunc()
Expand Down
6 changes: 1 addition & 5 deletions test/Interop/Cxx/class/access-specifiers-typechecker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ var v = PublicPrivate()
// Can access all public members and types.

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

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

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

Expand Down
20 changes: 6 additions & 14 deletions test/Interop/Cxx/extern-var/Inputs/extern-var.cc
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
int counter = 12;

int getCounterFromCxx() {
return counter;
}
int getCounterFromCxx() { return counter; }

void setCounterFromCxx(int c) {
counter = c;
}
void setCounterFromCxx(int c) { counter = c; }

namespace Namespaced {
int counter = 12;
int counter = 12;

int getCounterFromCxx() {
return counter;
}
int getCounterFromCxx() { return counter; }

void setCounterFromCxx(int c) {
counter = c;
}
}
void setCounterFromCxx(int c) { counter = c; }
} // namespace Namespaced
8 changes: 4 additions & 4 deletions test/Interop/Cxx/extern-var/Inputs/extern-var.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ int getCounterFromCxx();
void setCounterFromCxx(int);

namespace Namespaced {
extern int counter;
extern int counter;

int getCounterFromCxx();
void setCounterFromCxx(int);
}
int getCounterFromCxx();
void setCounterFromCxx(int);
} // namespace Namespaced
8 changes: 3 additions & 5 deletions test/Interop/Cxx/extern-var/extern-var-irgen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public func getCounter() -> CInt {
}

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

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

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

public func setNamespacedCounter(_ c: CInt) {
Namespaced.counter = c
}

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

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

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

11 changes: 5 additions & 6 deletions test/Interop/Cxx/extern-var/extern-var-silgen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ func getCounter() -> CInt {
}

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

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

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

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

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

func modifyInout(_ c: inout CInt) {
Expand Down
41 changes: 20 additions & 21 deletions test/Interop/Cxx/extern-var/extern-var.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,25 @@ ExternVarTestSuite.test("write-from-cxx") {
expectEqual(84, getCounterFromCxx())
}

//FIXME mangle non-top-level var names to prevent name collisions
// ExternVarTestSuite.test("namespaced-write-from-swift") {
// Namespaced.counter = 42
// expectEqual(42, Namespaced.counter)
// expectEqual(42, amespaced.getCounterFromCxx())
// }

//FIXME mangle non-top-level var names to prevent name collisions
// ExternVarTestSuite.test("namespaced-write-from-cxx") {
// Namespaced.setCounterFromCxx(84)
// expectEqual(84, Namespaced.counter)
// expectEqual(84, Namespaced.getCounterFromCxx())
// }

//FIXME mangle non-top-level var names to prevent name collisions
// ExternVarTestSuite.test("no-collisions") {
// counter = 12
// Namespaced.counter = 42
// expectEqual(12, counter)
// expectEqual(42, Namespaced.counter)
// }
ExternVarTestSuite.test("namespaced-write-from-swift") {
Namespaced.counter = 42
expectEqual(42, Namespaced.counter)
expectEqual(42, Namespaced.getCounterFromCxx())
}

ExternVarTestSuite.test("namespaced-write-from-cxx") {
Namespaced.setCounterFromCxx(84)
expectEqual(84, Namespaced.counter)
expectEqual(84, Namespaced.getCounterFromCxx())
}

// Check that variables with identical names in different namespaces don't
// collide in any intermediate representation of the compiler.
ExternVarTestSuite.test("no-collisions") {
counter = 12
Namespaced.counter = 42
expectEqual(12, counter)
expectEqual(42, Namespaced.counter)
}

runAllTests()
9 changes: 9 additions & 0 deletions test/Interop/Cxx/static/Inputs/inline-static-member-var.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include "inline-static-member-var.h"

int *WithInlineStaticMember::getStaticMemberAddress() { return &staticMember; }

int WithInlineStaticMember::getStaticMemberFromCxx() { return staticMember; }

void WithInlineStaticMember::setStaticMemberFromCxx(int newVal) {
staticMember = newVal;
}
12 changes: 12 additions & 0 deletions test/Interop/Cxx/static/Inputs/inline-static-member-var.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
inline static int init() { return 42; }

class WithInlineStaticMember {
public:
inline static int staticMember = 12;
//TODO needs C++ stdlib symbols, fix after apple/swift#30914 is merged.
// inline static int staticMemberInitializedAtRuntime = init();

static int getStaticMemberFromCxx();
static int *getStaticMemberAddress();
static void setStaticMemberFromCxx(int);
};
11 changes: 11 additions & 0 deletions test/Interop/Cxx/static/Inputs/module.modulemap
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module StaticLocalVar {
header "static-local-var.h"
}

module StaticMemberVar {
header "static-member-var.h"
}

module InlineStaticMemberVar {
header "inline-static-member-var.h"
}
5 changes: 5 additions & 0 deletions test/Interop/Cxx/static/Inputs/static-local-var.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "static-local-var.h"

int counterWrapper() {
return counter();
}
6 changes: 6 additions & 0 deletions test/Interop/Cxx/static/Inputs/static-local-var.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
int counterWrapper();

inline int counter() {
static int a = 0;
return a++;
}
32 changes: 32 additions & 0 deletions test/Interop/Cxx/static/Inputs/static-member-var.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "static-member-var.h"

int WithStaticMember::staticMember = 42;

int *WithStaticMember::getStaticMemberAddress() { return &staticMember; }

int WithStaticMember::getStaticMemberFromCxx() { return staticMember; }

void WithStaticMember::setStaticMemberFromCxx(int newVal) {
staticMember = newVal;
}

int WithIncompleteStaticMember::arrayMember[3] = {18, 19, 20};

WithIncompleteStaticMember WithIncompleteStaticMember::selfMember =
WithIncompleteStaticMember();

WithIncompleteStaticMember *
WithIncompleteStaticMember::getStaticMemberFromCxx() {
return &selfMember;
}

void WithIncompleteStaticMember::setStaticMemberFromCxx(
WithIncompleteStaticMember newVal) {
selfMember = newVal;
}

const int WithConstStaticMember::defined;
const int WithConstStaticMember::definedOutOfLine = 96;

int ClassA::notUniqueName = 144;
int ClassB::notUniqueName = 169;
39 changes: 39 additions & 0 deletions test/Interop/Cxx/static/Inputs/static-member-var.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
class WithStaticMember {
public:
static int staticMember;
static int *getStaticMemberAddress();
static int getStaticMemberFromCxx();
static void setStaticMemberFromCxx(int);
};

class WithIncompleteStaticMember {
public:
static int arrayMember[];
static WithIncompleteStaticMember selfMember;
int id = 3;

static WithIncompleteStaticMember *getStaticMemberFromCxx();
static void setStaticMemberFromCxx(WithIncompleteStaticMember);
};

class WithConstStaticMember {
public:
const static int notDefined = 24;
const static int defined = 48;
const static int definedOutOfLine;
};

class WithConstexprStaticMember {
public:
constexpr static int definedInline = 139;
};

class ClassA {
public:
static int notUniqueName;
};

class ClassB {
public:
static int notUniqueName;
};
18 changes: 18 additions & 0 deletions test/Interop/Cxx/static/constexpr-static-member-var.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// RUN: %empty-directory(%t)
// RUN: %target-clang -c %S/Inputs/static-member-var.cc -I %S/Inputs -o %t/static-member-var.o -std=c++17
// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-member-var.o -Xfrontend -enable-cxx-interop -Xcc -std=c++17
// RUN: %target-codesign %t/statics
// RUN: %target-run %t/statics
//
// REQUIRES: executable_test

import StaticMemberVar
import StdlibUnittest

var ConstexprStaticMemberVarTestSuite = TestSuite("ConstexprStaticMemberVarTestSuite")

ConstexprStaticMemberVarTestSuite.test("constexpr-static-member") {
expectEqual(139, WithConstexprStaticMember.definedInline)
}

runAllTests()
31 changes: 31 additions & 0 deletions test/Interop/Cxx/static/inline-static-member-var-irgen.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// RUN: %target-swift-emit-ir -I %S/Inputs -enable-cxx-interop %s | %FileCheck %s

import InlineStaticMemberVar

public func readStaticMember() -> CInt {
return WithInlineStaticMember.staticMember
}

// CHECK: @{{_ZN22WithInlineStaticMember12staticMemberE|"\?staticMember@WithInlineStaticMember@@2HA"}} = linkonce_odr {{(dso_local )?}}global i32 12, {{(comdat, )?}}align 4

// CHECK: define {{(protected |dllexport )?}}swiftcc i32 @"$s4main16readStaticMembers5Int32VyF"()
// CHECK: [[VALUE:%.*]] = load i32, i32* getelementptr inbounds (%Ts5Int32V, %Ts5Int32V* bitcast (i32* @{{_ZN22WithInlineStaticMember12staticMemberE|"\?staticMember@WithInlineStaticMember@@2HA"}} to %Ts5Int32V*), i32 0, i32 0), align 4
// CHECK: ret i32 [[VALUE]]

public func writeStaticMember(_ c: CInt) {
WithInlineStaticMember.staticMember = c
}

// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main17writeStaticMemberyys5Int32VF"(i32 %0)
// CHECK: store i32 %0, i32* getelementptr inbounds (%Ts5Int32V, %Ts5Int32V* bitcast (i32* @{{_ZN22WithInlineStaticMember12staticMemberE|"\?staticMember@WithInlineStaticMember@@2HA"}} to %Ts5Int32V*), i32 0, i32 0), align 4

func modifyInout(_ c: inout CInt) {
c = 42
}

public func passingVarAsInout() {
modifyInout(&WithInlineStaticMember.staticMember)
}

// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main17passingVarAsInoutyyF"()
// CHECK: call swiftcc void @"$s4main11modifyInoutyys5Int32VzF"(%Ts5Int32V* nocapture dereferenceable(4) bitcast (i32* @{{_ZN22WithInlineStaticMember12staticMemberE|"\?staticMember@WithInlineStaticMember@@2HA"}} to %Ts5Int32V*))
Loading