Skip to content

Commit c473c55

Browse files
author
Gabor Horvath
committed
[cxx-interop] Fix crash when virtual methods take move-only types
We build forwarding methods to call the virtual methods. The forwarding methods tried to copy move-only types which resulted in a compiler crash. Now we try to detect this scenario and insert the required cast to make sure we get a move instead. rdar://162195228
1 parent 4432378 commit c473c55

File tree

4 files changed

+47
-3
lines changed

4 files changed

+47
-3
lines changed

lib/ClangImporter/SwiftDeclSynthesizer.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,12 +2266,21 @@ clang::CXXMethodDecl *SwiftDeclSynthesizer::synthesizeCXXForwardingMethod(
22662266
clang::Expr *argExpr = new (clangCtx) clang::DeclRefExpr(
22672267
clangCtx, param, false, type.getNonReferenceType(),
22682268
clang::ExprValueKind::VK_LValue, clang::SourceLocation());
2269-
if (type->isRValueReferenceType()) {
2269+
bool isMoveOnly = false;
2270+
if (!type->isReferenceType())
2271+
if (evaluateOrDefault(
2272+
ImporterImpl.SwiftContext.evaluator,
2273+
CxxValueSemantics({type.getTypePtr(), &ImporterImpl}),
2274+
{}) == CxxValueSemanticsKind::MoveOnly)
2275+
isMoveOnly = true;
2276+
if (type->isRValueReferenceType() || isMoveOnly) {
22702277
argExpr = clangSema
22712278
.BuildCXXNamedCast(
22722279
clang::SourceLocation(), clang::tok::kw_static_cast,
2273-
clangCtx.getTrivialTypeSourceInfo(type), argExpr,
2274-
clang::SourceRange(), clang::SourceRange())
2280+
clangCtx.getTrivialTypeSourceInfo(
2281+
isMoveOnly ? clangCtx.getRValueReferenceType(type)
2282+
: type),
2283+
argExpr, clang::SourceRange(), clang::SourceRange())
22752284
.get();
22762285
}
22772286
args.push_back(argExpr);

test/Interop/Cxx/foreign-reference/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ module VirtMethodWithRvalRef {
8383
requires cplusplus
8484
}
8585

86+
module VirtMethodWitMoveOnly {
87+
header "virtual-methods-move-only-type.h"
88+
requires cplusplus
89+
}
90+
8691
module LoggingFrts {
8792
header "logging-frts.h"
8893
requires cplusplus
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#pragma once
2+
3+
#include "swift/bridging"
4+
5+
struct MoveOnly {
6+
MoveOnly() {}
7+
MoveOnly(MoveOnly&&) {}
8+
MoveOnly(const MoveOnly&) = delete;
9+
~MoveOnly() {}
10+
};
11+
12+
class CxxForeignRef;
13+
14+
void retain(CxxForeignRef * obj);
15+
void release(CxxForeignRef * obj);
16+
17+
class CxxForeignRef {
18+
public:
19+
CxxForeignRef(const CxxForeignRef &) = delete;
20+
CxxForeignRef() = default;
21+
22+
virtual void takesMoveOnly(MoveOnly);
23+
} SWIFT_SHARED_REFERENCE(retain, release);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %target-swift-frontend -typecheck -verify -I %S/Inputs -I %swift_src_root/lib/ClangImporter/SwiftBridging %s -cxx-interoperability-mode=default -disable-availability-checking
2+
3+
import VirtMethodWitMoveOnly
4+
5+
func f(_ x: CxxForeignRef, _ y: consuming MoveOnly) {
6+
x.takesMoveOnly(y)
7+
}

0 commit comments

Comments
 (0)