Skip to content

Commit 8449b21

Browse files
committed
[cxx-interop][windows] additional fix for indirect return in methods for MSVC ABI
Fixes #67685
1 parent aa397c7 commit 8449b21

File tree

4 files changed

+63
-16
lines changed

4 files changed

+63
-16
lines changed

lib/IRGen/GenCall.cpp

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,22 +1424,7 @@ void SignatureExpansion::expandExternalSignatureTypes() {
14241424
attrKindForExtending(signExt));
14251425
}
14261426

1427-
// If we return indirectly, that is the first parameter type.
1428-
if (returnInfo.isIndirect()) {
1429-
addIndirectResult();
1430-
}
1431-
1432-
size_t firstParamToLowerNormally = 0;
1433-
1434-
// Use a special IR type for passing block pointers.
1435-
if (FnType->getRepresentation() == SILFunctionTypeRepresentation::Block) {
1436-
assert(FI.arg_begin()[0].info.isDirect() &&
1437-
"block pointer not passed directly?");
1438-
ParamIRTypes.push_back(IGM.ObjCBlockPtrTy);
1439-
firstParamToLowerNormally = 1;
1440-
}
1441-
1442-
for (auto i : indices(paramTys).slice(firstParamToLowerNormally)) {
1427+
auto emitArg = [&](size_t i) {
14431428
auto &AI = FI.arg_begin()[i].info;
14441429

14451430
// Add a padding argument if required.
@@ -1528,8 +1513,35 @@ void SignatureExpansion::expandExternalSignatureTypes() {
15281513
case clang::CodeGen::ABIArgInfo::InAlloca:
15291514
llvm_unreachable("Need to handle InAlloca during signature expansion");
15301515
}
1516+
};
1517+
1518+
size_t firstParamToLowerNormally = 0;
1519+
1520+
// If we return indirectly, that is the first parameter type.
1521+
if (returnInfo.isIndirect()) {
1522+
if (IGM.Triple.isWindowsMSVCEnvironment() &&
1523+
FnType->getRepresentation() ==
1524+
SILFunctionTypeRepresentation::CXXMethod) {
1525+
// Windows ABI places `this` before the
1526+
// returned indirect values.
1527+
emitArg(0);
1528+
firstParamToLowerNormally = 1;
1529+
addIndirectResult();
1530+
} else
1531+
addIndirectResult();
15311532
}
15321533

1534+
// Use a special IR type for passing block pointers.
1535+
if (FnType->getRepresentation() == SILFunctionTypeRepresentation::Block) {
1536+
assert(FI.arg_begin()[0].info.isDirect() &&
1537+
"block pointer not passed directly?");
1538+
ParamIRTypes.push_back(IGM.ObjCBlockPtrTy);
1539+
firstParamToLowerNormally = 1;
1540+
}
1541+
1542+
for (auto i : indices(paramTys).slice(firstParamToLowerNormally))
1543+
emitArg(i);
1544+
15331545
if (returnInfo.isIndirect() || returnInfo.isIgnore()) {
15341546
ResultIRType = IGM.VoidTy;
15351547
} else {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,9 @@ module StdPair {
2222
header "std-pair.h"
2323
requires cplusplus
2424
}
25+
26+
module MsvcUseVecIt {
27+
header "msvc-std-vector-it.h"
28+
requires cplusplus
29+
export *
30+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#pragma once
2+
3+
#include <vector>
4+
#include <string>
5+
6+
struct FetchProvidersResult {
7+
std::vector<std::string> providers;
8+
};
9+
10+
inline FetchProvidersResult *f() noexcept {
11+
return new FetchProvidersResult();
12+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-swift-emit-irgen -I %S/Inputs -enable-experimental-cxx-interop -Xcc -std=c++17 %s | %FileCheck %s
2+
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -std=c++17)
3+
4+
// REQUIRES: OS=windows-msvc
5+
6+
import MsvcUseVecIt
7+
8+
// CHECK: call void @"?begin@?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@QEBA?AV?$_Vector_const_iterator@V?$_Vector_val@U?$_Simple_types@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@std@@@std@@@2@XZ"(ptr {{.*}}, ptr noalias nocapture sret
9+
10+
func test() -> Bool {
11+
let result = f()
12+
let begin = result.pointee.providers.__beginUnsafe()
13+
let end = result.pointee.providers.__endUnsafe()
14+
return begin != end
15+
}
16+
17+
let _ = test()

0 commit comments

Comments
 (0)