Skip to content

Commit 9989e6c

Browse files
authored
Merge pull request #66805 from apple/egorzhdan/5.9-string-append
🍒[cxx-interop] Make `std::string::append` usable from Swift and avoid crashing for substitution failures
2 parents 0a90700 + 96908b5 commit 9989e6c

File tree

7 files changed

+95
-7
lines changed

7 files changed

+95
-7
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,6 +2056,9 @@ ERROR(unable_to_convert_generic_swift_types,none,
20562056
"the following Swift type(s) provided to '%0' could not be "
20572057
"converted: %1",
20582058
(StringRef, StringRef))
2059+
ERROR(unable_to_substitute_cxx_function_template,none,
2060+
"could not substitute parameters for C++ function template '%0': %1",
2061+
(StringRef, StringRef))
20592062

20602063
// Type aliases
20612064
ERROR(type_alias_underlying_type_access,none,

lib/ClangImporter/ClangImporter.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5749,20 +5749,24 @@ clang::FunctionDecl *ClangImporter::instantiateCXXFunctionTemplate(
57495749
std::unique_ptr<TemplateInstantiationError> error =
57505750
ctx.getClangTemplateArguments(func->getTemplateParameters(),
57515751
subst.getReplacementTypes(), templateSubst);
5752-
if (error) {
5753-
std::string failedTypesStr;
5754-
llvm::raw_string_ostream failedTypesStrStream(failedTypesStr);
5755-
llvm::interleaveComma(error->failedTypes, failedTypesStrStream);
57565752

5753+
auto getFuncName = [&]() -> std::string {
57575754
std::string funcName;
57585755
llvm::raw_string_ostream funcNameStream(funcName);
57595756
func->printQualifiedName(funcNameStream);
5757+
return funcName;
5758+
};
5759+
5760+
if (error) {
5761+
std::string failedTypesStr;
5762+
llvm::raw_string_ostream failedTypesStrStream(failedTypesStr);
5763+
llvm::interleaveComma(error->failedTypes, failedTypesStrStream);
57605764

57615765
// TODO: Use the location of the apply here.
57625766
// TODO: This error message should not reference implementation details.
57635767
// See: https://github.com/apple/swift/pull/33053#discussion_r477003350
57645768
ctx.Diags.diagnose(SourceLoc(), diag::unable_to_convert_generic_swift_types,
5765-
funcName, failedTypesStr);
5769+
getFuncName(), failedTypesStr);
57665770
return nullptr;
57675771
}
57685772

@@ -5772,6 +5776,20 @@ clang::FunctionDecl *ClangImporter::instantiateCXXFunctionTemplate(
57725776
auto &sema = getClangInstance().getSema();
57735777
auto *spec = sema.InstantiateFunctionDeclaration(func, templateArgList,
57745778
clang::SourceLocation());
5779+
if (!spec) {
5780+
std::string templateParams;
5781+
llvm::raw_string_ostream templateParamsStream(templateParams);
5782+
llvm::interleaveComma(templateArgList->asArray(), templateParamsStream,
5783+
[&](const clang::TemplateArgument &arg) {
5784+
arg.print(func->getASTContext().getPrintingPolicy(),
5785+
templateParamsStream,
5786+
/*IncludeType*/ true);
5787+
});
5788+
ctx.Diags.diagnose(SourceLoc(),
5789+
diag::unable_to_substitute_cxx_function_template,
5790+
getFuncName(), templateParams);
5791+
return nullptr;
5792+
}
57755793
sema.InstantiateFunctionDefinition(clang::SourceLocation(), spec);
57765794
return spec;
57775795
}

stdlib/public/Cxx/std/String.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,12 @@ extension std.string: Equatable {
7777
}
7878

7979
public static func +=(lhs: inout std.string, rhs: std.string) {
80-
lhs.__appendUnsafe(rhs) // ignore the returned pointer
80+
lhs.append(rhs)
81+
}
82+
83+
@inlinable
84+
public mutating func append(_ other: std.string) {
85+
__appendUnsafe(other) // ignore the returned pointer
8186
}
8287

8388
public static func +(lhs: std.string, rhs: std.string) -> std.string {
@@ -93,7 +98,12 @@ extension std.u16string: Equatable {
9398
}
9499

95100
public static func +=(lhs: inout std.u16string, rhs: std.u16string) {
96-
lhs.__appendUnsafe(rhs) // ignore the returned pointer
101+
lhs.append(rhs)
102+
}
103+
104+
@inlinable
105+
public mutating func append(_ other: std.u16string) {
106+
__appendUnsafe(other) // ignore the returned pointer
97107
}
98108

99109
public static func +(lhs: std.u16string, rhs: std.u16string) -> std.u16string {

test/Interop/Cxx/stdlib/overlay/std-string-overlay.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,20 @@ StdStringOverlayTestSuite.test("std::u16string operators") {
8585
expectTrue(s1 == "something123literal")
8686
}
8787

88+
StdStringOverlayTestSuite.test("std::string::append") {
89+
var s1 = std.string("0123")
90+
let s2 = std.string("abc")
91+
s1.append(s2)
92+
expectEqual(s1, std.string("0123abc"))
93+
}
94+
95+
StdStringOverlayTestSuite.test("std::u16string::append") {
96+
var s1 = std.u16string("0123")
97+
let s2 = std.u16string("abc")
98+
s1.append(s2)
99+
expectEqual(s1, std.u16string("0123abc"))
100+
}
101+
88102
StdStringOverlayTestSuite.test("std::string as Hashable") {
89103
let s0 = std.string()
90104
let h0 = s0.hashValue
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_ENABLE_IF_H
2+
#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_ENABLE_IF_H
3+
4+
template <bool B, class T = void>
5+
struct enable_if {};
6+
7+
template <class T>
8+
struct enable_if<true, T> {
9+
typedef T type;
10+
};
11+
12+
template <class T>
13+
struct is_bool {
14+
static const bool value = false;
15+
};
16+
17+
template <>
18+
struct is_bool<bool> {
19+
static const bool value = true;
20+
};
21+
22+
struct HasMethodWithEnableIf {
23+
template <typename T>
24+
typename enable_if<is_bool<T>::value, bool>::type onlyEnabledForBool(T t) const {
25+
return !t;
26+
}
27+
};
28+
29+
#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_ENABLE_IF_H

test/Interop/Cxx/templates/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ module TemplateTypeParameterNotInSignature {
133133
requires cplusplus
134134
}
135135

136+
module EnableIf {
137+
header "enable-if.h"
138+
requires cplusplus
139+
}
140+
136141
module DefineReferencedInline {
137142
header "define-referenced-inline.h"
138143
requires cplusplus
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: not %target-swift-emit-ir %s -I %S/Inputs -enable-experimental-cxx-interop -enable-objc-interop 2>&1 | %FileCheck %s
2+
// REQUIRES: objc_interop
3+
4+
import StdlibUnittest
5+
import EnableIf
6+
7+
let x = HasMethodWithEnableIf()
8+
x.onlyEnabledForBool("a")
9+
// CHECK: error: could not substitute parameters for C++ function template 'HasMethodWithEnableIf::onlyEnabledForBool': NSString *

0 commit comments

Comments
 (0)