Skip to content

Commit 1507bcd

Browse files
Merge pull request #82193 from hnrklssn/skip-bounds-safety-types2-6.2
Cherry-pick [ClangImporter] Look through bounds attributes for template matching #82076
2 parents 18f74f5 + 96f0ab2 commit 1507bcd

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,6 +2254,7 @@ ImportedType ClangImporter::Implementation::importFunctionReturnType(
22542254
}
22552255

22562256
clang::QualType returnType = desugarIfElaborated(clangDecl->getReturnType());
2257+
returnType = desugarIfBoundsAttributed(returnType);
22572258
// In C interop mode, the return type of library builtin functions
22582259
// like 'memcpy' from headers like 'string.h' drops
22592260
// any nullability specifiers from their return type, and preserves it on the
@@ -2364,6 +2365,7 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType(
23642365
ImportDiagnosticAdder addDiag(*this, clangDecl,
23652366
clangDecl->getSourceRange().getBegin());
23662367
clang::QualType returnType = desugarIfElaborated(clangDecl->getReturnType());
2368+
returnType = desugarIfBoundsAttributed(returnType);
23672369

23682370
ImportedType importedType = importer::findOptionSetEnum(returnType, *this);
23692371

@@ -2430,6 +2432,7 @@ ClangImporter::Implementation::importParameterType(
24302432
ArrayRef<GenericTypeParamDecl *> genericParams,
24312433
llvm::function_ref<void(Diagnostic &&)> addImportDiagnosticFn) {
24322434
auto paramTy = desugarIfElaborated(param->getType());
2435+
paramTy = desugarIfBoundsAttributed(paramTy);
24332436

24342437
ImportTypeKind importKind = paramIsCompletionHandler
24352438
? ImportTypeKind::CompletionHandlerParameter

lib/ClangImporter/ImporterImpl.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,6 +2094,22 @@ inline clang::QualType desugarIfElaborated(clang::QualType type) {
20942094
return type;
20952095
}
20962096

2097+
inline clang::QualType desugarIfBoundsAttributed(clang::QualType type) {
2098+
if (auto BAT = dyn_cast<clang::BoundsAttributedType>(type))
2099+
return BAT->desugar();
2100+
if (auto VT = dyn_cast<clang::ValueTerminatedType>(type))
2101+
return VT->desugar();
2102+
if (auto AT = dyn_cast<clang::AttributedType>(type))
2103+
switch (AT->getAttrKind()) {
2104+
case clang::attr::PtrUnsafeIndexable:
2105+
case clang::attr::PtrSingle:
2106+
return AT->desugar();
2107+
default:
2108+
break;
2109+
}
2110+
return type;
2111+
}
2112+
20972113
/// Option set enums are sometimes imported as typedefs which assign a name to
20982114
/// the type, but are unavailable in Swift.
20992115
///
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// REQUIRES: swift_feature_SafeInteropWrappers
2+
3+
// RUN: rm -rf %t
4+
// RUN: split-file %s %t
5+
// RUN: %target-swift-frontend -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=default -enable-experimental-feature SafeInteropWrappers %t/template.swift -dump-macro-expansions -emit-ir -o %t/out -verify
6+
// RUN: %target-swift-ide-test -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=default -enable-experimental-feature SafeInteropWrappers -print-module -module-to-print=Template -source-filename=x | %FileCheck %s
7+
8+
// CHECK: func cb_template<T>(_ p: UnsafePointer<T>, _ size: Int{{.*}}) -> UnsafePointer<T>
9+
// CHECK: func eb_template<T>(_ p: UnsafePointer<T>, _ end: UnsafePointer<T>) -> UnsafePointer<T>
10+
// CHECK: func s_template<T>(_ p: UnsafePointer<T>) -> UnsafePointer<T>
11+
// CHECK: func ui_template<T>(_ p: UnsafePointer<T>) -> UnsafePointer<T>
12+
13+
//--- Inputs/module.modulemap
14+
module Template {
15+
header "template.h"
16+
requires cplusplus
17+
}
18+
19+
//--- Inputs/template.h
20+
#include <ptrcheck.h>
21+
#include <lifetimebound.h>
22+
23+
template <class T>
24+
inline const T* __counted_by(size) cb_template(const T* __counted_by(size) p __noescape, int size) { return p; }
25+
26+
template <class T>
27+
inline const T* __ended_by(end) eb_template(const T* __ended_by(end) p __noescape, const T* end) { return p; }
28+
29+
template <class T>
30+
inline const T* __single s_template(const T* __single p) { return p; }
31+
32+
template <class T>
33+
inline const T* __unsafe_indexable ui_template(const T* __unsafe_indexable p) { return p; }
34+
35+
// FIXME: parse null_terminated in templated contexts
36+
// template <class T>
37+
// inline const T* __null_terminated nt_template(const T* __null_terminated p) {}
38+
39+
//--- template.swift
40+
import Template
41+
42+
// make sure the original functions are still available when parsing bounds attributes
43+
func testOriginalCB(p: UnsafePointer<CInt>, len: CInt) {
44+
let _ = cb_template(p, len)
45+
}
46+
func testOriginalEB(p: UnsafePointer<CInt>, end: UnsafePointer<CInt>) {
47+
let _ = eb_template(p, end)
48+
}
49+
func testOriginalS(s: UnsafePointer<CInt>) {
50+
let _ = s_template(s)
51+
}
52+
func testOriginalUI(s: UnsafePointer<CInt>) {
53+
let _ = ui_template(s)
54+
}
55+
56+
// FIXME: generate safe overloads for templated functions (rdar://151481042)
57+
func testSafeOverloadCB(s: Span<CInt>) {
58+
// expected-error@+3{{generic parameter 'T' could not be inferred}}
59+
// expected-error@+2{{cannot convert value of type 'Span<CInt>'}}
60+
// expected-error@+1{{missing argument for parameter #2 in call}}
61+
cb_template(s)
62+
}
63+
func testSafeOverloadEB(s: Span<CInt>) {
64+
// expected-error@+3{{generic parameter 'T' could not be inferred}}
65+
// expected-error@+2{{cannot convert value of type 'Span<CInt>'}}
66+
// expected-error@+1{{missing argument for parameter #2 in call}}
67+
eb_template(s)
68+
}

0 commit comments

Comments
 (0)