Skip to content

Classify C++ structs as loadable or address-only #31707

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 4 commits into from
May 13, 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
14 changes: 12 additions & 2 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -558,10 +558,12 @@ class alignas(1 << DeclAlignInBits) Decl {
IsIncompatibleWithWeakReferences : 1
);

SWIFT_INLINE_BITFIELD(StructDecl, NominalTypeDecl, 1,
SWIFT_INLINE_BITFIELD(StructDecl, NominalTypeDecl, 1+1,
/// True if this struct has storage for fields that aren't accessible in
/// Swift.
HasUnreferenceableStorage : 1
HasUnreferenceableStorage : 1,
/// True if this struct is imported from C++ and not trivially copyable.
IsCxxNotTriviallyCopyable : 1
);

SWIFT_INLINE_BITFIELD(EnumDecl, NominalTypeDecl, 2+1,
Expand Down Expand Up @@ -3822,6 +3824,14 @@ class StructDecl final : public NominalTypeDecl {
void setHasUnreferenceableStorage(bool v) {
Bits.StructDecl.HasUnreferenceableStorage = v;
}

bool isCxxNotTriviallyCopyable() const {
return Bits.StructDecl.IsCxxNotTriviallyCopyable;
}

void setIsCxxNotTriviallyCopyable(bool v) {
Bits.StructDecl.IsCxxNotTriviallyCopyable = v;
}
};

/// This is the base type for AncestryOptions. Each flag describes possible
Expand Down
1 change: 1 addition & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4090,6 +4090,7 @@ StructDecl::StructDecl(SourceLoc StructLoc, Identifier Name, SourceLoc NameLoc,
StructLoc(StructLoc)
{
Bits.StructDecl.HasUnreferenceableStorage = false;
Bits.StructDecl.IsCxxNotTriviallyCopyable = false;
}

bool NominalTypeDecl::hasMemberwiseInitializer() const {
Expand Down
20 changes: 20 additions & 0 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/Basic/CharInfo.h"
#include "swift/Basic/Statistic.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Lookup.h"
Expand Down Expand Up @@ -3468,6 +3469,25 @@ namespace {

result->setHasUnreferenceableStorage(hasUnreferenceableStorage);

if (auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(decl)) {
result->setIsCxxNotTriviallyCopyable(
!cxxRecordDecl->isTriviallyCopyable());

for (auto ctor : cxxRecordDecl->ctors()) {
if (ctor->isCopyConstructor() &&
(ctor->isDeleted() || ctor->getAccess() != clang::AS_public)) {
result->setIsCxxNotTriviallyCopyable(true);
break;
}
}

if (auto dtor = cxxRecordDecl->getDestructor()) {
if (dtor->isDeleted() || dtor->getAccess() != clang::AS_public) {
result->setIsCxxNotTriviallyCopyable(true);
}
}
}

return result;
}

Expand Down
4 changes: 4 additions & 0 deletions lib/SIL/IR/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1446,6 +1446,10 @@ namespace {
if (handleResilience(structType, D, properties))
return handleAddressOnly(structType, properties);

if (D->isCxxNotTriviallyCopyable()) {
properties.setAddressOnly();
}

auto subMap = structType->getContextSubstitutionMap(&TC.M, D);

// Classify the type according to its stored properties.
Expand Down
158 changes: 158 additions & 0 deletions test/Interop/Cxx/class/Inputs/loadable-types.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#ifndef TEST_INTEROP_CXX_CLASS_INPUTS_LOADABLE_TYPES_H
#define TEST_INTEROP_CXX_CLASS_INPUTS_LOADABLE_TYPES_H

struct EmptyStruct {};

// Tests for individual special members

struct StructWithDefaultConstructor {
StructWithDefaultConstructor() {}
};

struct StructWithAdditionalConstructor {
StructWithAdditionalConstructor() {}
StructWithAdditionalConstructor(int parameter) {}
};

struct StructWithCopyConstructor {
StructWithCopyConstructor(const StructWithCopyConstructor &) {}
};

struct StructWithInheritedCopyConstructor : StructWithCopyConstructor {};

struct StructWithSubobjectCopyConstructor {
StructWithCopyConstructor subobject;
};

struct StructWithDefaultedCopyConstructor {
StructWithDefaultedCopyConstructor(
const StructWithDefaultedCopyConstructor &) = default;
};

struct StructWithInheritedDefaultedCopyConstructor
: StructWithDefaultedCopyConstructor {};

struct StructWithSubobjectDefaultedCopyConstructor {
StructWithDefaultedCopyConstructor subobject;
};

struct StructWithPrivateDefaultedCopyConstructor {
private:
StructWithPrivateDefaultedCopyConstructor(
const StructWithPrivateDefaultedCopyConstructor &) = default;
};

struct StructWithInheritedPrivateDefaultedCopyConstructor
: StructWithPrivateDefaultedCopyConstructor {};

struct StructWithSubobjectPrivateDefaultedCopyConstructor {
StructWithPrivateDefaultedCopyConstructor subobject;
};

struct StructWithMoveConstructor {
StructWithMoveConstructor(StructWithMoveConstructor &&) {}
};

struct StructWithInheritedMoveConstructor : StructWithMoveConstructor {};

struct StructWithSubobjectMoveConstructor {
StructWithMoveConstructor subobject;
};

struct StructWithCopyAssignment {
StructWithCopyAssignment &operator=(const StructWithCopyAssignment &) {}
};

struct StructWithInheritedCopyAssignment : StructWithCopyAssignment {};

struct StructWithSubobjectCopyAssignment {
StructWithCopyAssignment subobject;
};

struct StructWithMoveAssignment {
StructWithMoveAssignment &operator=(StructWithMoveAssignment &&) {}
};

struct StructWithInheritedMoveAssignment : StructWithMoveAssignment {};

struct StructWithSubobjectMoveAssignment {
StructWithMoveAssignment subobject;
};

struct StructWithDestructor {
~StructWithDestructor(){}
};

struct StructWithInheritedDestructor : StructWithDestructor {};

struct StructWithSubobjectDestructor {
StructWithDestructor subobject;
};

struct StructWithDefaultedDestructor {
~StructWithDefaultedDestructor() = default;
};

struct StructWithInheritedDefaultedDestructor : StructWithDefaultedDestructor {
};

struct StructWithSubobjectDefaultedDestructor {
StructWithDefaultedDestructor subobject;
};

struct StructWithPrivateDefaultedDestructor {
private:
~StructWithPrivateDefaultedDestructor() = default;
};

struct StructWithInheritedPrivateDefaultedDestructor
: StructWithPrivateDefaultedDestructor {};

struct StructWithSubobjectPrivateDefaultedDestructor {
StructWithPrivateDefaultedDestructor subobject;
};

// Tests for common sets of special member functions.

struct StructTriviallyCopyableMovable {
StructTriviallyCopyableMovable(const StructTriviallyCopyableMovable &) =
default;
StructTriviallyCopyableMovable(StructTriviallyCopyableMovable &&) = default;
StructTriviallyCopyableMovable &
operator=(const StructTriviallyCopyableMovable &) = default;
StructTriviallyCopyableMovable &
operator=(StructTriviallyCopyableMovable &&) = default;
~StructTriviallyCopyableMovable() = default;
};

struct StructNonCopyableTriviallyMovable {
StructNonCopyableTriviallyMovable(const StructNonCopyableTriviallyMovable &) =
delete;
StructNonCopyableTriviallyMovable(StructNonCopyableTriviallyMovable &&) =
default;
StructNonCopyableTriviallyMovable &
operator=(const StructNonCopyableTriviallyMovable &) = delete;
StructNonCopyableTriviallyMovable &
operator=(StructNonCopyableTriviallyMovable &&) = default;
~StructNonCopyableTriviallyMovable() = default;
};

struct StructNonCopyableNonMovable {
StructNonCopyableNonMovable(const StructNonCopyableNonMovable &) = delete;
StructNonCopyableNonMovable(StructNonCopyableNonMovable &&) = default;
StructNonCopyableNonMovable &
operator=(const StructNonCopyableNonMovable &) = delete;
StructNonCopyableNonMovable &
operator=(StructNonCopyableNonMovable &&) = default;
~StructNonCopyableNonMovable() = default;
};

struct StructDeletedDestructor {
StructDeletedDestructor(const StructDeletedDestructor &) = default;
StructDeletedDestructor(StructDeletedDestructor &&) = default;
StructDeletedDestructor &operator=(const StructDeletedDestructor &) = default;
StructDeletedDestructor &operator=(StructDeletedDestructor &&) = default;
~StructDeletedDestructor() = delete;
};

#endif
4 changes: 4 additions & 0 deletions test/Interop/Cxx/class/Inputs/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ module AccessSpecifiers {
header "access-specifiers.h"
}

module LoadableTypes {
header "loadable-types.h"
}

module MemberwiseInitializer {
header "memberwise-initializer.h"
}
Expand Down
Loading