From 21b9b9f71323f0f4cb625d939c4b1a91304ed380 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Sun, 27 Jul 2025 19:47:07 -0700 Subject: [PATCH] [Clang importer] Allow C structs to be noncopyable, too In C interoperability mode, respect the ~Copyable annotation on C structs to import them as ~Copyable types. Fixes rdar://156877772. --- lib/ClangImporter/ClangImporter.cpp | 3 ++ test/Interop/C/struct/Inputs/module.modulemap | 4 +++ .../C/struct/Inputs/noncopyable-struct.h | 5 ++++ .../C/struct/noncopyable_structs.swift | 29 +++++++++++++++++++ 4 files changed, 41 insertions(+) create mode 100644 test/Interop/C/struct/Inputs/noncopyable-struct.h create mode 100644 test/Interop/C/struct/noncopyable_structs.swift diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index f3f6a446cd3e2..de466879e09a8 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -8232,6 +8232,9 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator, auto cxxDecl = dyn_cast(decl); if (!cxxDecl) { + if (hasNonCopyableAttr(decl)) + return CxxRecordSemanticsKind::MoveOnly; + return CxxRecordSemanticsKind::Trivial; } diff --git a/test/Interop/C/struct/Inputs/module.modulemap b/test/Interop/C/struct/Inputs/module.modulemap index 641158b9978ef..ba61a05b26407 100644 --- a/test/Interop/C/struct/Inputs/module.modulemap +++ b/test/Interop/C/struct/Inputs/module.modulemap @@ -10,3 +10,7 @@ module ForeignReference { module StructAsOptionSet { header "struct-as-option-set.h" } + +module NoncopyableStructs { + header "noncopyable-struct.h" +} \ No newline at end of file diff --git a/test/Interop/C/struct/Inputs/noncopyable-struct.h b/test/Interop/C/struct/Inputs/noncopyable-struct.h new file mode 100644 index 0000000000000..14a96c396f86d --- /dev/null +++ b/test/Interop/C/struct/Inputs/noncopyable-struct.h @@ -0,0 +1,5 @@ +// RUN: %target-typecheck-verify-swift -I %S/Inputs/ + +typedef struct __attribute__((swift_attr("~Copyable"))) NonCopyable { + float x, y; +} NonCopyable; diff --git a/test/Interop/C/struct/noncopyable_structs.swift b/test/Interop/C/struct/noncopyable_structs.swift new file mode 100644 index 0000000000000..c1e3ca8bcf64d --- /dev/null +++ b/test/Interop/C/struct/noncopyable_structs.swift @@ -0,0 +1,29 @@ + +// Check that we get the expected errors for incorrect uses of noncopyable +// imported types with both C and C++ interoperability. + +// RUN: %target-swift-frontend -emit-sil -I %S/Inputs/ %s -verify -DERRORS +// RUN: %target-swift-frontend -emit-sil -I %S/Inputs/ %s -verify -DERRORS -cxx-interoperability-mode=default + +// Check that we get the expected IR + +// RUN: %target-swift-frontend -emit-ir -I %S/Inputs/ %s -o - | %FileCheck %s +// RUN: %target-swift-frontend -emit-ir -I %S/Inputs/ %s -o - -cxx-interoperability-mode=default| %FileCheck %s + +import NoncopyableStructs + +// CHECK-LABEL: define hidden swiftcc void @"$s19noncopyable_structs9consumeNCyySo11NonCopyableVnF"(float %0, float %1) #0 { +// CHECK: call ptr @"$sSo11NonCopyableVWOh" +// CHECK: define linkonce_odr hidden ptr @"$sSo11NonCopyableVWOh"(ptr %0) +// CHECK-NEXT: entry: +// CHECK-NEXT: ret ptr +func consumeNC(_ nc: consuming NonCopyable) { } + +func testNC() { + let nc = NonCopyable() // expected-error{{'nc' consumed more than once}} + consumeNC(nc) // expected-note{{consumed here}} + + #if ERRORS + consumeNC(nc) // expected-note{{consumed again here}} + #endif +}