diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index b951a3357a6ba..256de392a2c55 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -4546,6 +4546,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/StructLayout.cpp b/lib/IRGen/StructLayout.cpp index f6eea34220094..a6a7f854af394 100644 --- a/lib/IRGen/StructLayout.cpp +++ b/lib/IRGen/StructLayout.cpp @@ -589,10 +589,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/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)