diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 937f6f1052e00..e4768a3851931 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3064,11 +3064,11 @@ namespace { } } } - if (copyCtor) { + if (copyCtor && !decl->isAnonymousStructOrUnion()) { clangSema.DefineImplicitCopyConstructor(clang::SourceLocation(), copyCtor); } - if (moveCtor) { + if (moveCtor && !decl->isAnonymousStructOrUnion()) { clangSema.DefineImplicitMoveConstructor(clang::SourceLocation(), moveCtor); } @@ -4598,6 +4598,10 @@ namespace { // FIXME: Temporarily unreachable because of check above. markAsVariant(result, *correctSwiftName); + if (decl->isAnonymousStructOrUnion()) + Impl.markUnavailable( + result, "refer to the members of the anonymous type instead"); + return result; } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index f52b85106b27a..09e6ca686fe0a 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -6935,7 +6935,13 @@ namespace { } void addValueWitnessTable() { - auto vwtPointer = emitValueWitnessTable(/*relative*/ false).getValue(); + llvm::Constant* vwtPointer = nullptr; + if (auto cd = Target->getClangDecl()) + if (auto rd = dyn_cast(cd)) + if (rd->isAnonymousStructOrUnion()) + vwtPointer = llvm::Constant::getNullValue(IGM.WitnessTablePtrTy); + if (!vwtPointer) + vwtPointer = emitValueWitnessTable(/*relative*/ false).getValue(); B.addSignedPointer(vwtPointer, IGM.getOptions().PointerAuth.ValueWitnessTable, PointerAuthEntity()); diff --git a/lib/IRGen/StructLayout.cpp b/lib/IRGen/StructLayout.cpp index 368ff61dbf9fc..964696f5f3e30 100644 --- a/lib/IRGen/StructLayout.cpp +++ b/lib/IRGen/StructLayout.cpp @@ -590,10 +590,17 @@ unsigned irgen::getNumFields(const NominalTypeDecl *target) { } bool irgen::isExportableField(Field field) { - if (field.getKind() == Field::Kind::Var && - field.getVarDecl()->getClangDecl() && - field.getVarDecl()->getFormalAccess() == AccessLevel::Private) - return false; + if (field.getKind() == Field::Kind::Var) { + if (field.getVarDecl()->getClangDecl() && + field.getVarDecl()->getFormalAccess() == AccessLevel::Private) + return false; + // We should not be able to refer to anonymous types. + if (const auto *vd = dyn_cast_or_null( + field.getVarDecl()->getClangDecl())) + if (const auto *rd = vd->getType()->getAsRecordDecl()) + if (rd->isAnonymousStructOrUnion()) + return false; + } // All other fields are exportable return true; } diff --git a/test/Interop/Cxx/class/Inputs/simple-structs.h b/test/Interop/Cxx/class/Inputs/simple-structs.h index cdda0654dbb5f..c8f84b4e7eea2 100644 --- a/test/Interop/Cxx/class/Inputs/simple-structs.h +++ b/test/Interop/Cxx/class/Inputs/simple-structs.h @@ -17,6 +17,15 @@ struct HasPublicFieldsOnly { HasPublicFieldsOnly(int i1, int i2) : publ1(i1), publ2(i2) {} }; +struct HasAnonymousType { + HasAnonymousType(int a, int b, int c) : a(a), b(b), c(c) {} + + struct { + int a, b; + }; + int c; +}; + struct HasPrivatePublicProtectedFields { private: int priv1; diff --git a/test/Interop/Cxx/class/access-anonymous-field.swift b/test/Interop/Cxx/class/access-anonymous-field.swift new file mode 100644 index 0000000000000..767d70baee38d --- /dev/null +++ b/test/Interop/Cxx/class/access-anonymous-field.swift @@ -0,0 +1,12 @@ +// RUN: %target-typecheck-verify-swift -I %S/Inputs -swift-version 6 -cxx-interoperability-mode=upcoming-swift + +// CHECK: Foobar + +import SimpleStructs + +let s = HasAnonymousType(1, 2, 3) +let _ = s.__Anonymous_field0 // expected-error {{'__Anonymous_field0' is unavailable: refer to the members of the anonymous type instead}} +// Referring to the members of the anonymous type directly. +let _ = s.a +let _ = s.b +let _ = s.c diff --git a/test/Interop/Cxx/class/move-only/Inputs/move-only-cxx-value-type.h b/test/Interop/Cxx/class/move-only/Inputs/move-only-cxx-value-type.h index 388a686dd233c..16c4f1bf65504 100644 --- a/test/Interop/Cxx/class/move-only/Inputs/move-only-cxx-value-type.h +++ b/test/Interop/Cxx/class/move-only/Inputs/move-only-cxx-value-type.h @@ -56,4 +56,16 @@ struct NonCopyableHolderDerivedDerived: NonCopyableHolderDerived { inline NonCopyable *getNonCopyablePtr() { return nullptr; } inline NonCopyableDerived *getNonCopyableDerivedPtr() { return nullptr; } +template +struct FieldInAnonStruct { + FieldInAnonStruct() : field(5) {} + FieldInAnonStruct(const FieldInAnonStruct &) = delete; + FieldInAnonStruct(FieldInAnonStruct &&) = default; + struct { + T field; + }; +}; + +using FieldInAnonStructNC = FieldInAnonStruct; + #endif // TEST_INTEROP_CXX_CLASS_MOVE_ONLY_VT_H diff --git a/test/Interop/Cxx/class/move-only/move-only-cxx-value-type.swift b/test/Interop/Cxx/class/move-only/move-only-cxx-value-type.swift index a9ccb692a3431..7e7a306192de6 100644 --- a/test/Interop/Cxx/class/move-only/move-only-cxx-value-type.swift +++ b/test/Interop/Cxx/class/move-only/move-only-cxx-value-type.swift @@ -76,4 +76,8 @@ MoveOnlyCxxValueType.test("Test move only field access in derived holder") { } #endif +MoveOnlyCxxValueType.test("Test move only field in anonymous struct") { + let a = FieldInAnonStructNC() + let b = a +} runAllTests() diff --git a/test/Interop/Cxx/class/print-simple-structs.swift b/test/Interop/Cxx/class/print-simple-structs.swift index 27088944d40d0..ee8e3209e0add 100644 --- a/test/Interop/Cxx/class/print-simple-structs.swift +++ b/test/Interop/Cxx/class/print-simple-structs.swift @@ -24,6 +24,11 @@ func printCxxStructNested() { print(s) } +func printCxxStructWithAnonType() { + let s = HasAnonymousType(1, 2, 3) + print(s) +} + printCxxStructPrivateFields() // CHECK: HasPrivateFieldsOnly() @@ -35,3 +40,6 @@ printCxxStructPrivatePublicProtectedFields() printCxxStructNested() // CHECK: Outer(publStruct: {{.*}}.HasPrivatePublicProtectedFields(publ1: 8, publ2: 12)) + +printCxxStructWithAnonType() +// CHECK: HasAnonymousType(c: 3)