Skip to content

[cxx-interop] Disable rvalue references. We don't support them correc… #65578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/swift/AST/DiagnosticsClangImporter.def
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ NOTE(macro_not_imported, none, "macro '%0' unavailable (cannot import)", (String

NOTE(return_type_not_imported, none, "return type unavailable (cannot import)", ())
NOTE(parameter_type_not_imported, none, "parameter %0 unavailable (cannot import)", (const clang::NamedDecl*))
NOTE(rvalue_ref_params_not_imported, none, "C++ functions with rvalue reference parameters are unavailable in Swift", ())
NOTE(incomplete_interface, none, "interface %0 is incomplete", (const clang::NamedDecl*))
NOTE(incomplete_protocol, none, "protocol %0 is incomplete", (const clang::NamedDecl*))
NOTE(incomplete_record, none, "record '%0' is not defined (incomplete)", (StringRef))
Expand Down
8 changes: 8 additions & 0 deletions include/swift/ClangImporter/ClangImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,14 @@ namespace importer {
/// Returns true if the given module has a 'cplusplus' requirement.
bool requiresCPlusPlus(const clang::Module *module);

/// Returns the pointee type if the given type is a C++ `const`
/// reference type, `None` otherwise.
llvm::Optional<clang::QualType>
getCxxReferencePointeeTypeOrNone(const clang::Type *type);

/// Returns true if the given type is a C++ `const` reference type.
bool isCxxConstReferenceType(const clang::Type *type);

} // namespace importer

struct ClangInvocationFileMapping {
Expand Down
12 changes: 12 additions & 0 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6832,3 +6832,15 @@ bool importer::requiresCPlusPlus(const clang::Module *module) {
return req.first == "cplusplus";
});
}

llvm::Optional<clang::QualType>
importer::getCxxReferencePointeeTypeOrNone(const clang::Type *type) {
if (type->isReferenceType())
return type->getPointeeType();
return {};
}

bool importer::isCxxConstReferenceType(const clang::Type *type) {
auto pointeeType = getCxxReferencePointeeTypeOrNone(type);
return pointeeType && pointeeType->isConstQualified();
}
33 changes: 25 additions & 8 deletions lib/ClangImporter/ImportType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2356,15 +2356,32 @@ ClangImporter::Implementation::importParameterType(
dyn_cast<clang::TemplateTypeParmType>(paramTy)) {
swiftParamTy = findGenericTypeInGenericDecls(
*this, templateParamType, genericParams, attrs, addImportDiagnosticFn);
} else if (auto refType = dyn_cast<clang::ReferenceType>(paramTy)) {
// We don't support reference type to a dependent type, just bail.
if (refType->getPointeeType()->isDependentType()) {
return None;
}
}

paramTy = refType->getPointeeType();
if (!paramTy.isConstQualified())
isInOut = true;
if (!swiftParamTy) {
// C++ reference types are brought in as direct
// types most commonly.
auto refPointeeType =
importer::getCxxReferencePointeeTypeOrNone(paramTy.getTypePtr());
if (refPointeeType) {
// We don't support reference type to a dependent type, just bail.
if ((*refPointeeType)->isDependentType()) {
return None;
}

// We don't support rvalue reference types, just bail.
if (paramTy->isRValueReferenceType()) {
addImportDiagnosticFn(Diagnostic(diag::rvalue_ref_params_not_imported));
return None;
}

// A C++ parameter of type `const <type> &` or `<type> &` becomes `<type>`
// or `inout <type>` in Swift. Note that SILGen will use the indirect
// parameter convention for such a type.
paramTy = *refPointeeType;
if (!paramTy.isConstQualified())
isInOut = true;
}
}

// Special case for NSDictionary's subscript.
Expand Down
5 changes: 2 additions & 3 deletions lib/SIL/IR/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1420,8 +1420,7 @@ static bool isClangTypeMoreIndirectThanSubstType(TypeConverter &TC,
// Pass C++ const reference types indirectly. Right now there's no way to
// express immutable borrowed params, so we have to have this hack.
// Eventually, we should just express these correctly: rdar://89647503
if (clangTy->isReferenceType() &&
clangTy->getPointeeType().isConstQualified())
if (importer::isCxxConstReferenceType(clangTy))
return true;

return false;
Expand Down Expand Up @@ -3109,7 +3108,7 @@ static bool isCFTypedef(const TypeLowering &tl, clang::QualType type) {
static ParameterConvention getIndirectCParameterConvention(clang::QualType type) {
// Non-trivial C++ types would be Indirect_Inout (at least in Itanium).
// A trivial const * parameter in C should be considered @in.
if (type->isReferenceType() && type->getPointeeType().isConstQualified())
if (importer::isCxxConstReferenceType(type.getTypePtr()))
return ParameterConvention::Indirect_In_Guaranteed;
return ParameterConvention::Indirect_In;
}
Expand Down
8 changes: 8 additions & 0 deletions test/Interop/Cxx/reference/Inputs/reference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,11 @@ auto getFuncRvalueRef() -> int (&&)() { return getStaticInt; }
void takeConstRef(const int &value) {
staticInt = value;
}

void setConstStaticIntRefTypealias(ConstIntRefTypealias ref) {
staticInt = ref;
}

void setStaticIntRefTypealias(IntRefTypealias ref) {
staticInt = ref;
}
8 changes: 8 additions & 0 deletions test/Interop/Cxx/reference/Inputs/reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ void setConstStaticIntRvalueRef(const int &&);
auto getFuncRef() -> int (&)();
auto getFuncRvalueRef() -> int (&&)();

using ConstIntRefTypealias = const int &;

void setConstStaticIntRefTypealias(ConstIntRefTypealias ref);

using IntRefTypealias = int &;

void setStaticIntRefTypealias(IntRefTypealias ref);

template<class T>
struct ClassTemplate {};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: not %target-swift-frontend -typecheck -I %t/Inputs %t/test.swift -enable-experimental-cxx-interop 2>&1 | %FileCheck %s

//--- Inputs/module.modulemap
module Test {
header "test.h"
requires cplusplus
}

//--- Inputs/test.h

void acceptRValueRef(int &&);

//--- test.swift

import Test

public func test() {
var x: CInt = 2
acceptRValueRef(x)
// CHECK: note: function 'acceptRValueRef' unavailable (cannot import)
// CHECK: note: C++ functions with rvalue reference parameters are unavailable in Swift
}
16 changes: 0 additions & 16 deletions test/Interop/Cxx/reference/reference-irgen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,3 @@ public func setCxxConstRef() {

// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main14setCxxConstRefyyF"()
// CHECK: call void @{{_Z20setConstStaticIntRefRKi|"\?setConstStaticIntRef@@YAXAEBH@Z"}}(i32* %{{.*}})

public func setCxxRvalueRef() {
var val: CInt = 21
setStaticIntRvalueRef(&val)
}

// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main15setCxxRvalueRefyyF"()
// CHECK: call void @{{_Z21setStaticIntRvalueRefOi|"\?setStaticIntRvalueRef@@YAX\$\$QEAH@Z"}}(i32* %{{.*}})

public func setCxxConstRvalueRef() {
let val: CInt = 21
setConstStaticIntRvalueRef(val)
}

// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20setCxxConstRvalueRefyyF"()
// CHECK: call void @{{_Z26setConstStaticIntRvalueRefOKi|"\?setConstStaticIntRvalueRef@@YAX\$\$QEBH@Z"}}(i32* %{{.*}})
6 changes: 4 additions & 2 deletions test/Interop/Cxx/reference/reference-module-interface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
// CHECK: func getConstStaticIntRvalueRef() -> UnsafePointer<Int32>
// CHECK: func setStaticInt(_: Int32)
// CHECK: func setStaticIntRef(_: inout Int32)
// CHECK: func setStaticIntRvalueRef(_: inout Int32)
// CHECK: func setConstStaticIntRef(_: Int32)
// CHECK: func setConstStaticIntRvalueRef(_: Int32)
// CHECK: func getFuncRef() -> @convention(c) () -> Int32
// CHECK: func getFuncRvalueRef() -> @convention(c) () -> Int32
// CHECK: func setConstStaticIntRefTypealias(_ ref: Int32)
// CHECK: func setStaticIntRefTypealias(_ ref: inout Int32)
// CHECK: func refToTemplate<T>(_ t: inout T) -> UnsafeMutablePointer<T>
// CHECK: func constRefToTemplate<T>(_ t: T) -> UnsafePointer<T>

// CHECK-NOT: refToDependent
// CHECK-NOT: refToDependentParam
// CHECK-NOT: dontImportAtomicRef
// CHECK-NOT: setStaticIntRvalueRef
// CHECK-NOT: setConstStaticIntRvalueRef
24 changes: 12 additions & 12 deletions test/Interop/Cxx/reference/reference-silgen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,20 @@ func setCxxConstRef() {
// CHECK: [[REF:%.*]] = function_ref @{{_Z20setConstStaticIntRefRKi|\?setConstStaticIntRef@@YAXAEBH@Z}} : $@convention(c) (@in_guaranteed Int32) -> ()
// CHECK: apply [[REF]](%{{[0-9]+}}) : $@convention(c) (@in_guaranteed Int32) -> ()

func setCxxRvalueRef() {
var val: CInt = 21
setStaticIntRvalueRef(&val)
func setCxxConstRefTypealias() {
let val: CInt = 21
setConstStaticIntRefTypealias(val)
}

// CHECK: sil hidden @$s4main15setCxxRvalueRefyyF : $@convention(thin) () -> ()
// CHECK: [[REF:%.*]] = function_ref @{{_Z21setStaticIntRvalueRefOi|\?setStaticIntRvalueRef@@YAX\$\$QEAH@Z}} : $@convention(c) (@inout Int32) -> ()
// CHECK: apply [[REF]](%{{[0-9]+}}) : $@convention(c) (@inout Int32) -> ()
// CHECK: sil hidden @$s4main23setCxxConstRefTypealiasyyF : $@convention(thin) () -> ()
// CHECK: [[REF:%.*]] = function_ref @{{_Z29setConstStaticIntRefTypealiasRKi|\?setConstStaticIntRefTypealias@@YAXAEBH@Z}} : $@convention(c) (@in_guaranteed Int32) -> ()
// CHECK: apply [[REF]](%{{[0-9]+}}) : $@convention(c) (@in_guaranteed Int32) -> ()

func setCxxConstRvalueRef() {
let val: CInt = 21
setConstStaticIntRvalueRef(val)
func setStaticIntRefTypealias() {
var val: CInt = 21
setStaticIntRefTypealias(&val)
}

// CHECK: sil hidden @$s4main20setCxxConstRvalueRefyyF : $@convention(thin) () -> ()
// CHECK: [[REF:%.*]] = function_ref @{{_Z26setConstStaticIntRvalueRefOKi|\?setConstStaticIntRvalueRef@@YAX\$\$QEBH@Z}} : $@convention(c) (@in_guaranteed Int32) -> ()
// CHECK: apply [[REF]](%{{[0-9]+}}) : $@convention(c) (@in_guaranteed Int32) -> ()
// CHECK: sil hidden @$s4main24setStaticIntRefTypealiasyyF : $@convention(thin) () -> ()
// CHECK: [[REF:%.*]] = function_ref @{{_Z24setStaticIntRefTypealiasRi|\?setStaticIntRefTypealias@@YAXAEAH@Z}} : $@convention(c) (@inout Int32) -> ()
// CHECK: apply [[REF]](%{{[0-9]+}}) : $@convention(c) (@inout Int32) -> ()
19 changes: 5 additions & 14 deletions test/Interop/Cxx/reference/reference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,18 @@ ReferenceTestSuite.test("pass-lvalue-reference") {
var val: CInt = 21
setStaticIntRef(&val)
expectEqual(21, getStaticInt())
val = 111
setStaticIntRefTypealias(&val)
expectEqual(getStaticInt(), 111)
}

ReferenceTestSuite.test("pass-const-lvalue-reference") {
expectNotEqual(22, getStaticInt())
let val: CInt = 22
setConstStaticIntRef(val)
expectEqual(22, getStaticInt())
}

ReferenceTestSuite.test("pass-rvalue-reference") {
expectNotEqual(52, getStaticInt())
var val: CInt = 52
setStaticIntRvalueRef(&val)
expectEqual(52, getStaticInt())
}

ReferenceTestSuite.test("pass-const-rvalue-reference") {
expectNotEqual(53, getStaticInt())
let val: CInt = 53
setConstStaticIntRvalueRef(val)
expectEqual(53, getStaticInt())
setConstStaticIntRefTypealias(112)
expectEqual(getStaticInt(), 112)
}

ReferenceTestSuite.test("func-reference") {
Expand Down
11 changes: 5 additions & 6 deletions test/Interop/Cxx/stdlib/use-std-vector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,17 @@ StdVectorTestSuite.test("init") {

StdVectorTestSuite.test("push back") {
var v = Vector()
var _42: CInt = 42
v.push_back(&_42)
let _42: CInt = 42
v.push_back(_42)
Comment on lines +22 to +23
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we just inline this literal as we do below?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I can do that in a followup. Also need to disable this for template functions too in a follow up.

expectEqual(v.size(), 1)
expectFalse(v.empty())
expectEqual(v[0], 42)
}

func fill(vector v: inout Vector) {
var _1: CInt = 1, _2: CInt = 2, _3: CInt = 3
v.push_back(&_1)
v.push_back(&_2)
v.push_back(&_3)
v.push_back(1)
v.push_back(2)
v.push_back(CInt(3))
}

// TODO: in some configurations the stdlib emits a "initializeWithCopy" where the arguments
Expand Down