From 5ef54aaada998a7603533a5cf72254e200b62d87 Mon Sep 17 00:00:00 2001 From: "Henrik G. Olsson" Date: Fri, 30 May 2025 22:53:15 -0700 Subject: [PATCH 1/3] [ClangImporter] Look through __ended_by and __null_terminated (#81630) Previously we would not import decls containing these types. This was not an issue, because they can only occur when -fbounds-safety or -fexperimental-bounds-safety-attributes is passed to clang. When SafeInteropWrappers is enabled we pass -fexperimental-bound-safety-attributes to clang however, so these types can now occur without the user specifying any -Xcc flags. rdar://151611718 (cherry picked from commit ac068c2a6ba7153e076c3d02bd10c04945358661) --- lib/ClangImporter/ImportType.cpp | 10 +- .../Inputs/bounds-attributed-function.h | 56 +++++++ .../Inputs/bounds-attributed-global.h | 13 ++ .../Inputs/bounds-attributed-struct.h | 90 +++++++++++ .../C/bounds-safety/Inputs/module.modulemap | 12 ++ .../import-bounds-attributed-function.swift | 85 ++++++++++ .../import-bounds-attributed-global.swift | 36 +++++ .../import-bounds-attributed-struct.swift | 153 ++++++++++++++++++ 8 files changed, 449 insertions(+), 6 deletions(-) create mode 100644 test/Interop/C/bounds-safety/Inputs/bounds-attributed-function.h create mode 100644 test/Interop/C/bounds-safety/Inputs/bounds-attributed-global.h create mode 100644 test/Interop/C/bounds-safety/Inputs/bounds-attributed-struct.h create mode 100644 test/Interop/C/bounds-safety/Inputs/module.modulemap create mode 100644 test/Interop/C/bounds-safety/import-bounds-attributed-function.swift create mode 100644 test/Interop/C/bounds-safety/import-bounds-attributed-global.swift create mode 100644 test/Interop/C/bounds-safety/import-bounds-attributed-struct.swift diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 1510f744e3672..086601dc649d1 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -425,17 +425,15 @@ namespace { ImportResult VisitDynamicRangePointerType( const clang::DynamicRangePointerType *type) { // DynamicRangePointerType is a clang type representing a pointer with - // an "ended_by" type attribute for -fbounds-safety. For now, we don't - // import these into Swift. - return Type(); + // an "ended_by" type attribute for -fbounds-safety. + return Visit(type->desugar()); } ImportResult VisitValueTerminatedType( const clang::ValueTerminatedType *type) { // ValueTerminatedType is a clang type representing a pointer with - // a "terminated_by" type attribute for -fbounds-safety. For now, we don't - // import these into Swift. - return Type(); + // a "terminated_by" type attribute for -fbounds-safety. + return Visit(type->desugar()); } ImportResult VisitMemberPointerType(const clang::MemberPointerType *type) { diff --git a/test/Interop/C/bounds-safety/Inputs/bounds-attributed-function.h b/test/Interop/C/bounds-safety/Inputs/bounds-attributed-function.h new file mode 100644 index 0000000000000..46a4b96eaacb1 --- /dev/null +++ b/test/Interop/C/bounds-safety/Inputs/bounds-attributed-function.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +// Test __counted_by, __sized_by, __ended_by, __single, __indexable and __bidi_indexable pointers +// in function parameters, return values, nested and unnested, pointing to void, char and int. +// Also test VLAs, and incomplete pointer type with __counted_by, since they are pretty much the same +// as __counted_by pointers in the -fbounds-safety model. + +#ifndef __unsafe_late_const +#define __unsafe_late_const +#endif + +int * __counted_by(len) a(int *__counted_by(len) p, int len); +char * __counted_by(len) b(char *__counted_by(len) p, int len); +char * __sized_by(len) c(char *__sized_by(len) p, int len); +void * __sized_by(len) d(void *__sized_by(len) p, int len); +int * __sized_by(len) e(int *__sized_by(len) p, int len); + +int * __ended_by(end) f(int *__ended_by(end) p, int * end); +void * __ended_by(end) g(void *__ended_by(end) p, void * end); + +char * __null_terminated h(char *__null_terminated p); +const char * i(const char * p); + +char * __single j(char *__single p); +void *__single k(void *__single p); + +#if __has_ptrcheck +// __indexable and __bidi_indexable are not defined unless -fbounds-safety is enabled +char * __indexable l(char *__indexable p); +void *__indexable m(void *__indexable p); + +char * __bidi_indexable n(char *__bidi_indexable p); +void * __bidi_indexable o(void *__bidi_indexable p); +#endif + +#if !__cplusplus +// No VLAs in C++ +void p(int len, int p[len]); +#endif +void q(int p[__counted_by(len)], int len); + +void r(int * __counted_by(*len) *__single p, int *len); +char * __null_terminated *__null_terminated s(char * __null_terminated *__null_terminated p); +char * __single *__single t(char * __single *__single p); + +const int len1 = 7; +int * __counted_by(len1) u(int * __counted_by(len1) p); + +int len2 __unsafe_late_const; +int * __counted_by(len2) v(int * __counted_by(len2) p); + +// -fbounds-safety can sometimes affect va_list +void w(va_list p); diff --git a/test/Interop/C/bounds-safety/Inputs/bounds-attributed-global.h b/test/Interop/C/bounds-safety/Inputs/bounds-attributed-global.h new file mode 100644 index 0000000000000..7f746134c601b --- /dev/null +++ b/test/Interop/C/bounds-safety/Inputs/bounds-attributed-global.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +extern int len; +extern int a[__counted_by(len)]; // expected-note{{'a' declared here}} + +const char * __null_terminated b = "b"; + +extern int * __single * __single c; +#if __has_ptrcheck +extern int * __bidi_indexable d; +#endif diff --git a/test/Interop/C/bounds-safety/Inputs/bounds-attributed-struct.h b/test/Interop/C/bounds-safety/Inputs/bounds-attributed-struct.h new file mode 100644 index 0000000000000..739c615e574b2 --- /dev/null +++ b/test/Interop/C/bounds-safety/Inputs/bounds-attributed-struct.h @@ -0,0 +1,90 @@ +#pragma once + +#include + +// Test __counted_by, __sized_by, __ended_by, __single, __indexable and __bidi_indexable pointers +// in function parameters, return values, nested and unnested, pointing to void, char and int. +// Also test VLAs, and incomplete pointer type with __counted_by, since they are pretty much the same +// as __counted_by pointers in the -fbounds-safety model. + +struct a { + int * __counted_by(len) a; + int len; +}; +struct a *a(struct a); + +struct b { + int * __sized_by(len) a; + int len; +}; +struct b *b(struct b); + +struct c { + char * __sized_by(len) a; + int len; +}; +struct c *c(struct c); + +struct d { + void * __sized_by(len) a; + int len; +}; +struct d *d(struct d); + +struct e { + void * __single a; + int * __single b; +}; +struct e *e(struct e); + +struct f { + const char * a; + char * __null_terminated b; +}; +struct f *f(struct f); + +#if __has_ptrcheck +struct g { + void * __bidi_indexable a; + int * __bidi_indexable b; +}; +struct g *g(struct g); + +struct h { + void * __indexable a; + int * __indexable b; +}; +struct h *h(struct h); +#endif + +struct i { + int len; + int a[__counted_by(len)]; // expected-note {{field 'a' unavailable (cannot import)}} +}; +struct i *__single i(struct i *); + +const int len1 = 7; +struct j { + int * __counted_by(len1) a; + void * __sized_by(len1) b; +}; +struct j *j(struct j); + +int len2 __unsafe_late_const; +struct k { + int * __counted_by(len2) a; + void * __sized_by(len2) b; +}; +struct k *k(struct k); + +struct l { + int * __ended_by(end) a; + int * end; +}; +struct l *l(struct l); + +struct m { + void * __ended_by(end) a; + void * end; +}; +struct m *m(struct m); diff --git a/test/Interop/C/bounds-safety/Inputs/module.modulemap b/test/Interop/C/bounds-safety/Inputs/module.modulemap new file mode 100644 index 0000000000000..a484dbbb430d1 --- /dev/null +++ b/test/Interop/C/bounds-safety/Inputs/module.modulemap @@ -0,0 +1,12 @@ +module BoundsAttributedFunction { + header "bounds-attributed-function.h" + export * +} +module BoundsAttributedGlobal { + header "bounds-attributed-global.h" + export * +} +module BoundsAttributedStruct { + header "bounds-attributed-struct.h" + export * +} diff --git a/test/Interop/C/bounds-safety/import-bounds-attributed-function.swift b/test/Interop/C/bounds-safety/import-bounds-attributed-function.swift new file mode 100644 index 0000000000000..b9b3f26903db1 --- /dev/null +++ b/test/Interop/C/bounds-safety/import-bounds-attributed-function.swift @@ -0,0 +1,85 @@ +// RUN: %target-swift-ide-test -Xcc -fexperimental-bounds-safety-attributes -print-module -module-to-print=BoundsAttributedFunction -I %S/Inputs -source-filename=x | %FileCheck %s --check-prefixes=CHECK,C-ONLY +// RUN: %target-swift-ide-test -Xcc -fexperimental-bounds-safety-attributes -print-module -module-to-print=BoundsAttributedFunction -I %S/Inputs -source-filename=x -cxx-interoperability-mode=default | %FileCheck %s +// RUN: %target-swift-ide-test -Xcc -fbounds-safety -disable-objc-interop -print-module -module-to-print=BoundsAttributedFunction -I %S/Inputs -source-filename=x | %FileCheck %s --check-prefixes=CHECK,BOUNDS-SAFETY,C-ONLY + +// This test case checks that ClangImporter can import declarations using various bounds attributes, +// rather than being marked unavailable because of an unknown type. + +// CHECK: func a(_ p: UnsafeMutablePointer!, _ len: Int{{[0-9]+}}) -> UnsafeMutablePointer! +// CHECK-NEXT: func b(_ p: UnsafeMutablePointer!, _ len: Int{{[0-9]+}}) -> UnsafeMutablePointer! +// CHECK-NEXT: func c(_ p: UnsafeMutablePointer!, _ len: Int{{[0-9]+}}) -> UnsafeMutablePointer! +// CHECK-NEXT: func d(_ p: UnsafeMutableRawPointer!, _ len: Int{{[0-9]+}}) -> UnsafeMutableRawPointer! +// CHECK-NEXT: func e(_ p: UnsafeMutablePointer!, _ len: Int{{[0-9]+}}) -> UnsafeMutablePointer! +// CHECK-NEXT: func f(_ p: UnsafeMutablePointer!, _ end: UnsafeMutablePointer!) -> UnsafeMutablePointer! +// CHECK-NEXT: func g(_ p: UnsafeMutableRawPointer!, _ end: UnsafeMutableRawPointer!) -> UnsafeMutableRawPointer! +// CHECK-NEXT: func h(_ p: UnsafeMutablePointer!) -> UnsafeMutablePointer! +// CHECK-NEXT: func i(_ p: UnsafePointer!) -> UnsafePointer! +// CHECK-NEXT: func j(_ p: UnsafeMutablePointer!) -> UnsafeMutablePointer! +// CHECK-NEXT: func k(_ p: UnsafeMutableRawPointer!) -> UnsafeMutableRawPointer! + +// BOUNDS-SAFETY-NEXT: func l(_ p: UnsafeMutablePointer!) -> UnsafeMutablePointer! +// BOUNDS-SAFETY-NEXT: func m(_ p: UnsafeMutableRawPointer!) -> UnsafeMutableRawPointer! +// BOUNDS-SAFETY-NEXT: func n(_ p: UnsafeMutablePointer!) -> UnsafeMutablePointer! +// BOUNDS-SAFETY-NEXT: func o(_ p: UnsafeMutableRawPointer!) -> UnsafeMutableRawPointer! + +// C-ONLY-NEXT: func p(_ len: Int{{[0-9]+}}, _ p: UnsafeMutablePointer!) + +// CHECK-NEXT: func q(_ p: UnsafeMutablePointer!, _ len: Int{{[0-9]+}}) +// CHECK-NEXT: func r(_ p: UnsafeMutablePointer?>!, _ len: UnsafeMutablePointer!) +// CHECK-NEXT: func s(_ p: UnsafeMutablePointer?>!) -> UnsafeMutablePointer?>! +// CHECK-NEXT: func t(_ p: UnsafeMutablePointer?>!) -> UnsafeMutablePointer?>! +// CHECK-NEXT: var len1: Int{{[0-9]+}} { get } +// CHECK-NEXT: func u(_ p: UnsafeMutablePointer!) -> UnsafeMutablePointer! +// CHECK-NEXT: var len2: Int{{[0-9]+}} +// CHECK-NEXT: func v(_ p: UnsafeMutablePointer!) -> UnsafeMutablePointer! + + +// RUN: %target-swift-frontend -Xcc -fexperimental-bounds-safety-attributes -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -D C_ONLY +// RUN: %target-swift-frontend -Xcc -fexperimental-bounds-safety-attributes -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -cxx-interoperability-mode=default +// RUN: %target-swift-frontend -Xcc -fbounds-safety -disable-objc-interop -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -D C_ONLY -D BOUNDS_SAFETY + +import BoundsAttributedFunction + +func call(_ mutIntPtr: UnsafeMutablePointer, + _ mutCharPtr: UnsafeMutablePointer, + _ mutRawPtr: UnsafeMutableRawPointer, + _ constCharPtr: UnsafePointer, + _ mutMutIntPtrPtr: UnsafeMutablePointer?>!, + _ mutMutCharPtrPtr: UnsafeMutablePointer?>!, + _ int: CInt, + _ args: CVaListPointer) { + let _ = a(mutIntPtr, int) + let _ = b(mutCharPtr, int) + let _ = c(mutCharPtr, int) + let _ = d(mutRawPtr, int) + let _ = e(mutIntPtr, int) + let _ = f(mutIntPtr, mutIntPtr) + let _ = g(mutRawPtr, mutRawPtr) + let _ = h(mutCharPtr) + let _ = i(constCharPtr) + let _ = j(mutCharPtr) + let _ = k(mutRawPtr) + +#if BOUNDS_SAFETY + let _ = l(mutIntPtr) + let _ = m(mutRawPtr) + let _ = n(mutIntPtr) + let _ = o(mutRawPtr) +#endif + +#if C_ONLY + let _ = p(int, mutIntPtr) +#endif + + let _ = q(mutIntPtr, int) + let _ = r(mutMutIntPtrPtr, mutIntPtr) + let _ = s(mutMutCharPtrPtr) + let _ = t(mutMutCharPtrPtr) + let _ = len1 + let _ = u(mutIntPtr) + let _ = len2 + len2 = 37 + let _ = v(mutIntPtr) + + let _ = w(args) +} diff --git a/test/Interop/C/bounds-safety/import-bounds-attributed-global.swift b/test/Interop/C/bounds-safety/import-bounds-attributed-global.swift new file mode 100644 index 0000000000000..999be225a2bdc --- /dev/null +++ b/test/Interop/C/bounds-safety/import-bounds-attributed-global.swift @@ -0,0 +1,36 @@ +// RUN: %target-swift-ide-test -Xcc -fexperimental-bounds-safety-attributes -print-module -module-to-print=BoundsAttributedGlobal -I %S/Inputs -source-filename=x | %FileCheck %s --check-prefixes=CHECK,C-ONLY +// RUN: %target-swift-ide-test -Xcc -fexperimental-bounds-safety-attributes -print-module -module-to-print=BoundsAttributedGlobal -I %S/Inputs -source-filename=x -cxx-interoperability-mode=swift-6 -Xcc -std=c++20 | %FileCheck %s +// RUN: %target-swift-ide-test -Xcc -fbounds-safety -disable-objc-interop -print-module -module-to-print=BoundsAttributedGlobal -I %S/Inputs -source-filename=x | %FileCheck %s --check-prefixes=CHECK,BOUNDS-SAFETY,C-ONLY + +// This test case checks that ClangImporter can import declarations using various bounds attributes, +// rather than being marked unavailable because of an unknown type. + +// CHECK: var len: Int32 +// CHECK-NEXT: var a: <> +// CHECK-NEXT: var b: UnsafePointer! +// CHECK-NEXT: var c: UnsafeMutablePointer?>! +// BOUNDS-SAFETY-NEXT: var d: UnsafeMutablePointer! + + +// RUN: %target-swift-frontend -Xcc -fexperimental-bounds-safety-attributes -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s +// RUN: %target-swift-frontend -Xcc -fexperimental-bounds-safety-attributes -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -cxx-interoperability-mode=swift-6 +// RUN: %target-swift-frontend -Xcc -fbounds-safety -disable-objc-interop -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -D BOUNDS_SAFETY + +// RUN: %target-swift-frontend -Xcc -fexperimental-bounds-safety-attributes -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -verify -verify-additional-file %S/Inputs/bounds-attributed-global.h -D VERIFY +// RUN: %target-swift-frontend -Xcc -fexperimental-bounds-safety-attributes -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -cxx-interoperability-mode=swift-6 -verify -verify-additional-file %S/Inputs/bounds-attributed-global.h -D VERIFY +// RUN: %target-swift-frontend -Xcc -fbounds-safety -disable-objc-interop -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -verify -verify-additional-file %S/Inputs/bounds-attributed-global.h -D BOUNDS_SAFETY -D VERIFY + +import BoundsAttributedGlobal + +func access() { +#if VERIFY +// rdar://152293598 ([ClangImporter] Importing global array errors on macOS and Linux, but not on Windows) +// XFAIL: OS=windows-msvc + let _ = a // expected-error{{cannot reference invalid declaration 'a'}} rdar://151665752 +#endif + let _ = b.pointee + let _ = c.pointee!.pointee +#if BOUNDS_SAFETY + let _ = d.pointee +#endif +} diff --git a/test/Interop/C/bounds-safety/import-bounds-attributed-struct.swift b/test/Interop/C/bounds-safety/import-bounds-attributed-struct.swift new file mode 100644 index 0000000000000..89e1373b5e9e8 --- /dev/null +++ b/test/Interop/C/bounds-safety/import-bounds-attributed-struct.swift @@ -0,0 +1,153 @@ +// RUN: %target-swift-ide-test -Xcc -fexperimental-bounds-safety-attributes -print-module -module-to-print=BoundsAttributedStruct -I %S/Inputs -source-filename=x | %FileCheck %s +// RUN: %target-swift-ide-test -Xcc -fexperimental-bounds-safety-attributes -print-module -module-to-print=BoundsAttributedStruct -I %S/Inputs -source-filename=x -cxx-interoperability-mode=swift-6 -Xcc -std=c++20 | %FileCheck %s +// RUN: %target-swift-ide-test -Xcc -fbounds-safety -disable-objc-interop -print-module -module-to-print=BoundsAttributedStruct -I %S/Inputs -source-filename=x | %FileCheck %s --check-prefixes=CHECK,BOUNDS-SAFETY + +// This test case checks that ClangImporter can import declarations using various bounds attributes, +// rather than being marked unavailable because of an unknown type. + +// CHECK: struct a { +// CHECK-NEXT: init() +// CHECK-NEXT: init(a: UnsafeMutablePointer!, len: Int{{[0-9]+}}) +// CHECK-NEXT: var a: UnsafeMutablePointer! +// CHECK-NEXT: var len: Int{{[0-9]+}} +// CHECK-NEXT: } +// CHECK-NEXT: func a(_: a) -> UnsafeMutablePointer! +// CHECK-NEXT: struct b { +// CHECK-NEXT: init() +// CHECK-NEXT: init(a: UnsafeMutablePointer!, len: Int{{[0-9]+}}) +// CHECK-NEXT: var a: UnsafeMutablePointer! +// CHECK-NEXT: var len: Int{{[0-9]+}} +// CHECK-NEXT: } +// CHECK-NEXT: func b(_: b) -> UnsafeMutablePointer! +// CHECK-NEXT: struct c { +// CHECK-NEXT: init() +// CHECK-NEXT: init(a: UnsafeMutablePointer!, len: Int{{[0-9]+}}) +// CHECK-NEXT: var a: UnsafeMutablePointer! +// CHECK-NEXT: var len: Int{{[0-9]+}} +// CHECK-NEXT: } +// CHECK-NEXT: func c(_: c) -> UnsafeMutablePointer! +// CHECK-NEXT: struct d { +// CHECK-NEXT: init() +// CHECK-NEXT: init(a: UnsafeMutableRawPointer!, len: Int{{[0-9]+}}) +// CHECK-NEXT: var a: UnsafeMutableRawPointer! +// CHECK-NEXT: var len: Int{{[0-9]+}} +// CHECK-NEXT: } +// CHECK-NEXT: func d(_: d) -> UnsafeMutablePointer! +// CHECK-NEXT: struct e { +// CHECK-NEXT: init() +// CHECK-NEXT: init(a: UnsafeMutableRawPointer!, b: UnsafeMutablePointer!) +// CHECK-NEXT: var a: UnsafeMutableRawPointer! +// CHECK-NEXT: var b: UnsafeMutablePointer! +// CHECK-NEXT: } +// CHECK-NEXT: func e(_: e) -> UnsafeMutablePointer! +// CHECK-NEXT: struct f { +// CHECK-NEXT: init() +// CHECK-NEXT: init(a: UnsafePointer!, b: UnsafeMutablePointer!) +// CHECK-NEXT: var a: UnsafePointer! +// CHECK-NEXT: var b: UnsafeMutablePointer! +// CHECK-NEXT: } +// CHECK-NEXT: func f(_: f) -> UnsafeMutablePointer! + +// BOUNDS-SAFETY-NEXT: struct g { +// BOUNDS-SAFETY-NEXT: init() +// BOUNDS-SAFETY-NEXT: init(a: UnsafeMutableRawPointer!, b: UnsafeMutablePointer!) +// BOUNDS-SAFETY-NEXT: var a: UnsafeMutableRawPointer! +// BOUNDS-SAFETY-NEXT: var b: UnsafeMutablePointer! +// BOUNDS-SAFETY-NEXT: } +// BOUNDS-SAFETY-NEXT: func g(_: g) -> UnsafeMutablePointer! +// BOUNDS-SAFETY-NEXT: struct h { +// BOUNDS-SAFETY-NEXT: init() +// BOUNDS-SAFETY-NEXT: init(a: UnsafeMutableRawPointer!, b: UnsafeMutablePointer!) +// BOUNDS-SAFETY-NEXT: var a: UnsafeMutableRawPointer! +// BOUNDS-SAFETY-NEXT: var b: UnsafeMutablePointer! +// BOUNDS-SAFETY-NEXT: } +// BOUNDS-SAFETY-NEXT: func h(_: h) -> UnsafeMutablePointer! + +// CHECK-NEXT: struct i { +// CHECK-NEXT: init() +// CHECK-NEXT: var len: Int{{[0-9]+}} +// CHECK-NEXT: } +// CHECK-NEXT: func i(_: UnsafeMutablePointer!) -> UnsafeMutablePointer! +// CHECK-NEXT: var len1: Int{{[0-9]+}} { get } +// CHECK-NEXT: struct j { +// CHECK-NEXT: init() +// CHECK-NEXT: init(a: UnsafeMutablePointer!, b: UnsafeMutableRawPointer!) +// CHECK-NEXT: var a: UnsafeMutablePointer! +// CHECK-NEXT: var b: UnsafeMutableRawPointer! +// CHECK-NEXT: } +// CHECK-NEXT: func j(_: j) -> UnsafeMutablePointer! +// CHECK-NEXT: var len2: Int{{[0-9]+}} +// CHECK-NEXT: struct k { +// CHECK-NEXT: init() +// CHECK-NEXT: init(a: UnsafeMutablePointer!, b: UnsafeMutableRawPointer!) +// CHECK-NEXT: var a: UnsafeMutablePointer! +// CHECK-NEXT: var b: UnsafeMutableRawPointer! +// CHECK-NEXT: } +// CHECK-NEXT: func k(_: k) -> UnsafeMutablePointer! + +// RUN: %target-swift-frontend -Xcc -fexperimental-bounds-safety-attributes -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s +// RUN: %target-swift-frontend -Xcc -fexperimental-bounds-safety-attributes -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -cxx-interoperability-mode=swift-6 +// RUN: %target-swift-frontend -Xcc -fbounds-safety -disable-objc-interop -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -D BOUNDS_SAFETY + +// RUN: %target-swift-frontend -Xcc -fexperimental-bounds-safety-attributes -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -verify -verify-additional-file %S/Inputs/bounds-attributed-struct.h -D VERIFY +// RUN: %target-swift-frontend -Xcc -fexperimental-bounds-safety-attributes -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -cxx-interoperability-mode=swift-6 -verify -verify-additional-file %S/Inputs/bounds-attributed-struct.h -D VERIFY +// RUN: %target-swift-frontend -Xcc -fbounds-safety -disable-objc-interop -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs %s -verify -verify-additional-file %S/Inputs/bounds-attributed-struct.h -D BOUNDS_SAFETY -D VERIFY + +import BoundsAttributedStruct + +func call(aa: a, bb: b, cc: c, dd: d, ee: e, ff: f, ii: UnsafeMutablePointer, jj: j, kk: k, ll: l, mm: m) { + let _ = aa.a + let _ = a(aa) + + let _ = bb.a + let _ = b(bb) + + let _ = cc.a + let _ = c(cc) + + let _ = dd.a + let _ = d(dd) + + let _ = ee.a + let _ = e(ee) + + let _ = ff.a + let _ = f(ff) + + let _ = unsafe ii.pointee.len +#if VERIFY + // rdar://152293598 ([ClangImporter] Importing global array errors on macOS and Linux, but not on Windows) + // XFAIL: OS=windows-msvc + // flexible array member not imported rdar://151665752 + let _ = i.a // expected-error{{type 'i' has no member 'a'}} +#endif + let _ = i(ii) + + let _ = jj.a + let _ = jj.b + let _ = j(jj) + + let _ = kk.a + let _ = kk.b + let _ = k(kk) + + let _ = ll.a + let _ = ll.end + let _ = l(ll) + + let _ = mm.a + let _ = mm.end + let _ = m(mm) +} + +#if BOUNDS_SAFETY +func boundsSafe(gg: g, hh: h) { + let _ = gg.a + let _ = gg.b + let _ = g(gg) + + let _ = hh.a + let _ = hh.b + let _ = h(hh) +} +#endif From e2661ca12ef04065e89b5dc6374545735c4a3c9c Mon Sep 17 00:00:00 2001 From: "Henrik G. Olsson" Date: Wed, 4 Jun 2025 21:58:57 -0700 Subject: [PATCH 2/3] update test case for release/6.2 branch --- .../C/bounds-safety/import-bounds-attributed-function.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Interop/C/bounds-safety/import-bounds-attributed-function.swift b/test/Interop/C/bounds-safety/import-bounds-attributed-function.swift index b9b3f26903db1..ed61e7762a675 100644 --- a/test/Interop/C/bounds-safety/import-bounds-attributed-function.swift +++ b/test/Interop/C/bounds-safety/import-bounds-attributed-function.swift @@ -28,7 +28,7 @@ // CHECK-NEXT: func r(_ p: UnsafeMutablePointer?>!, _ len: UnsafeMutablePointer!) // CHECK-NEXT: func s(_ p: UnsafeMutablePointer?>!) -> UnsafeMutablePointer?>! // CHECK-NEXT: func t(_ p: UnsafeMutablePointer?>!) -> UnsafeMutablePointer?>! -// CHECK-NEXT: var len1: Int{{[0-9]+}} { get } +// CHECK-NEXT: let len1: Int{{[0-9]+}} // CHECK-NEXT: func u(_ p: UnsafeMutablePointer!) -> UnsafeMutablePointer! // CHECK-NEXT: var len2: Int{{[0-9]+}} // CHECK-NEXT: func v(_ p: UnsafeMutablePointer!) -> UnsafeMutablePointer! From 1f1cc3bd59d83e413705ab07c61d194c9b9ae931 Mon Sep 17 00:00:00 2001 From: "Henrik G. Olsson" Date: Thu, 5 Jun 2025 01:13:51 -0700 Subject: [PATCH 3/3] update test case for release/6.2 branch --- .../C/bounds-safety/import-bounds-attributed-struct.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Interop/C/bounds-safety/import-bounds-attributed-struct.swift b/test/Interop/C/bounds-safety/import-bounds-attributed-struct.swift index 89e1373b5e9e8..c6f5b3e5ddd92 100644 --- a/test/Interop/C/bounds-safety/import-bounds-attributed-struct.swift +++ b/test/Interop/C/bounds-safety/import-bounds-attributed-struct.swift @@ -68,7 +68,7 @@ // CHECK-NEXT: var len: Int{{[0-9]+}} // CHECK-NEXT: } // CHECK-NEXT: func i(_: UnsafeMutablePointer!) -> UnsafeMutablePointer! -// CHECK-NEXT: var len1: Int{{[0-9]+}} { get } +// CHECK-NEXT: let len1: Int{{[0-9]+}} // CHECK-NEXT: struct j { // CHECK-NEXT: init() // CHECK-NEXT: init(a: UnsafeMutablePointer!, b: UnsafeMutableRawPointer!)