Skip to content
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
77 changes: 75 additions & 2 deletions lib/IRGen/GenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

#include "GenClass.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/RecordLayout.h"
#include "swift/ABI/Class.h"
#include "swift/ABI/MetadataValues.h"
#include "swift/AST/ASTContext.h"
Expand All @@ -28,6 +31,7 @@
#include "swift/AST/SemanticAttrs.h"
#include "swift/AST/TypeMemberVisitor.h"
#include "swift/AST/Types.h"
#include "swift/Basic/Defer.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/IRGen/Linking.h"
#include "swift/SIL/SILModule.h"
Expand Down Expand Up @@ -281,6 +285,55 @@ namespace {
superclass);
}

void maybeAddCxxRecordBases(ClassDecl *cd) {
auto cxxRecord = dyn_cast_or_null<clang::CXXRecordDecl>(cd->getClangDecl());
if (!cxxRecord)
return;

auto &layout = cxxRecord->getASTContext().getASTRecordLayout(cxxRecord);

for (auto base : cxxRecord->bases()) {
if (base.isVirtual())
continue;

auto baseType = base.getType().getCanonicalType();

auto baseRecord = cast<clang::RecordType>(baseType)->getDecl();
auto baseCxxRecord = cast<clang::CXXRecordDecl>(baseRecord);

if (baseCxxRecord->isEmpty())
continue;

auto offset = Size(layout.getBaseClassOffset(baseCxxRecord).getQuantity());
auto size = Size(cxxRecord->getASTContext().getTypeSizeInChars(baseType).getQuantity());

if (offset != CurSize) {
assert(offset > CurSize);
auto paddingSize = offset - CurSize;
auto &opaqueTI = IGM.getOpaqueStorageTypeInfo(paddingSize, Alignment(1));
auto element = ElementLayout::getIncomplete(opaqueTI);
addField(element, LayoutStrategy::Universal);
}

auto &opaqueTI = IGM.getOpaqueStorageTypeInfo(size, Alignment(1));
auto element = ElementLayout::getIncomplete(opaqueTI);
addField(element, LayoutStrategy::Universal);
}
}

void addPaddingBeforeClangField(const clang::FieldDecl *fd) {
auto offset = Size(fd->getASTContext().toCharUnitsFromBits(
fd->getASTContext().getFieldOffset(fd)).getQuantity());

if (offset != CurSize) {
assert(offset > CurSize);
auto paddingSize = offset - CurSize;
auto &opaqueTI = IGM.getOpaqueStorageTypeInfo(paddingSize, Alignment(1));
auto element = ElementLayout::getIncomplete(opaqueTI);
addField(element, LayoutStrategy::Universal);
}
}

void addDirectFieldsFromClass(ClassDecl *rootClass, SILType rootClassType,
ClassDecl *theClass, SILType classType,
bool superclass) {
Expand All @@ -290,7 +343,9 @@ namespace {
->getRecursiveProperties()
.hasUnboundGeneric());

forEachField(IGM, theClass, [&](Field field) {
maybeAddCxxRecordBases(theClass);

auto fn = [&](Field field) {
// Ignore missing properties here; we should have flagged these
// with the classHasIncompleteLayout call above.
if (!field.isConcrete()) {
Expand Down Expand Up @@ -325,7 +380,25 @@ namespace {
AllStoredProperties.push_back(field);
AllFieldAccesses.push_back(getFieldAccess(isKnownEmpty));
}
});
};

auto classDecl = dyn_cast<ClassDecl>(theClass);
if (classDecl && classDecl->isRootDefaultActor()) {
fn(Field::DefaultActorStorage);
}

for (auto decl :
theClass->getStoredPropertiesAndMissingMemberPlaceholders()) {
if (decl->getClangDecl())
if (auto clangField = cast<clang::FieldDecl>(decl->getClangDecl()))
addPaddingBeforeClangField(clangField);

if (auto var = dyn_cast<VarDecl>(decl)) {
fn(var);
} else {
fn(cast<MissingMemberDecl>(decl));
}
}

if (!superclass) {
// If we're calculating the layout of a specialized generic class type,
Expand Down
56 changes: 56 additions & 0 deletions test/Interop/Cxx/foreign-reference/Inputs/member-layout.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#ifndef TEST_INTEROP_CXX_FOREIGN_REFERENCE_INPUTS_NULLABLE_H
#define TEST_INTEROP_CXX_FOREIGN_REFERENCE_INPUTS_NULLABLE_H

struct IntHolder { int value; };

struct
__attribute__((swift_attr("import_reference")))
__attribute__((swift_attr("retain:immortal")))
__attribute__((swift_attr("release:immortal")))
IntBase : IntHolder {
int i;
};

struct NoDtorThreeByte {
char x;
char y;
char z;
~NoDtorThreeByte() = delete;
};

struct
__attribute__((swift_attr("import_reference")))
__attribute__((swift_attr("retain:immortal")))
__attribute__((swift_attr("release:immortal")))
IntCharRef {
int i;
char b;
};

struct
__attribute__((swift_attr("import_reference")))
__attribute__((swift_attr("retain:immortal")))
__attribute__((swift_attr("release:immortal")))
IntCharValue {
int i;
char b;
};


struct
__attribute__((swift_attr("import_reference")))
__attribute__((swift_attr("retain:immortal")))
__attribute__((swift_attr("release:immortal")))
UnimportableMemberRef {
int z; int zz; NoDtorThreeByte x; NoDtorThreeByte xx; int y;
};

struct
__attribute__((swift_attr("import_reference")))
__attribute__((swift_attr("retain:immortal")))
__attribute__((swift_attr("release:immortal")))
UnimportableMemberValue {
int z; int zz; NoDtorThreeByte x; NoDtorThreeByte xx; int y;
};

#endif // TEST_INTEROP_CXX_FOREIGN_REFERENCE_INPUTS_NULLABLE_H
5 changes: 5 additions & 0 deletions test/Interop/Cxx/foreign-reference/Inputs/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@ module ReferenceCounted {
header "reference-counted.h"
requires cplusplus
}

module MemberLayout {
header "member-layout.h"
requires cplusplus
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-experimental-cxx-interop -module-name=test | %FileCheck %s
//
// XFAIL: OS=linux-android, OS=linux-androideabi

import MemberLayout

// CHECK: %TSo7IntBaseV = type <{ [4 x i8], %Ts5Int32V }>

// CHECK-LABEL: define {{.*}}swiftcc i32 @"$s4testAA1ys5Int32VSo7IntBaseV_tF"(%TSo7IntBaseV* %0)
// CHECK: getelementptr inbounds %TSo7IntBaseV, %TSo7IntBaseV* %0, i32 0, i32 1
public func test(y: IntBase) -> CInt {
return y.i
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-experimental-cxx-interop -module-name=test | %FileCheck %s
//
// XFAIL: OS=linux-android, OS=linux-androideabi

import MemberLayout

// Make sure the "refs" and "values" look *exactly* the same.

// CHECK: %TSo10IntCharRefV = type <{ %Ts5Int32V, %Ts4Int8V }>
// CHECK: %TSo12IntCharValueV = type <{ %Ts5Int32V, %Ts4Int8V }>

// CHECK: %TSo21UnimportableMemberRefV = type <{ %Ts5Int32V, %Ts5Int32V, [8 x i8], %Ts5Int32V }>
// CHECK: %TSo23UnimportableMemberValueV = type <{ %Ts5Int32V, %Ts5Int32V, [8 x i8], %Ts5Int32V }>

// CHECK-LABEL: define {{.*}}swiftcc i8 @"$s4testAA1ys4Int8VSo10IntCharRefV_tF"(%TSo10IntCharRefV* %0)
// CHECK: getelementptr inbounds %TSo10IntCharRefV, %TSo10IntCharRefV* %0, i32 0, i32 1
public func test(y: IntCharRef) -> CChar {
return y.b
}

// CHECK-LABEL: define {{.*}}swiftcc i8 @"$s4testAA1ys4Int8VSo12IntCharValueV_tF"(%TSo12IntCharValueV* %0)
// CHECK: getelementptr inbounds %TSo12IntCharValueV, %TSo12IntCharValueV* %0, i32 0, i32 1
public func test(y: IntCharValue) -> CChar {
return y.b
}

// CHECK-LABEL: define {{.*}}swiftcc i32 @"$s4testAA1ys5Int32VSo21UnimportableMemberRefV_tF"(%TSo21UnimportableMemberRefV* %0)
// CHECK: getelementptr inbounds %TSo21UnimportableMemberRefV, %TSo21UnimportableMemberRefV* %0, i32 0, i32 3
public func test(y: UnimportableMemberRef) -> CInt {
return y.y
}

// CHECK-LABEL: define {{.*}}swiftcc i32 @"$s4testAA1ys5Int32VSo23UnimportableMemberValueV_tF"(%TSo23UnimportableMemberValueV* %0)
// CHECK: getelementptr inbounds %TSo23UnimportableMemberValueV, %TSo23UnimportableMemberValueV* %0, i32 0, i32 3
public func test(y: UnimportableMemberValue) -> CInt {
return y.y
}