diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 3e06aac7f3ccd..a21385dcb4054 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -1478,10 +1478,14 @@ static bool suppressFactoryMethodAsInit(const clang::ObjCMethodDecl *method, } static void -addEmptyArgNamesForClangFunction(const clang::FunctionDecl *funcDecl, - SmallVectorImpl &argumentNames) { - for (size_t i = 0; i < funcDecl->param_size(); ++i) - argumentNames.push_back(StringRef()); +addDefaultArgNamesForClangFunction(const clang::FunctionDecl *funcDecl, + SmallVectorImpl &argumentNames) { + for (size_t i = 0; i < funcDecl->param_size(); ++i) { + if (funcDecl->getParamDecl(i)->getType()->isRValueReferenceType()) + argumentNames.push_back("consuming"); + else + argumentNames.push_back(StringRef()); + } if (funcDecl->isVariadic()) argumentNames.push_back(StringRef()); } @@ -1863,7 +1867,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, // If we couldn't find a constructor decl, bail. if (!ctor) return ImportedName(); - addEmptyArgNamesForClangFunction(ctor, argumentNames); + addDefaultArgNamesForClangFunction(ctor, argumentNames); break; } @@ -1876,7 +1880,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, if (toType->isBooleanType()) { isFunction = true; baseName = "__convertToBool"; - addEmptyArgNamesForClangFunction(conversionDecl, argumentNames); + addDefaultArgNamesForClangFunction(conversionDecl, argumentNames); break; } return ImportedName(); @@ -1928,7 +1932,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, : clang::getOperatorSpelling(op); baseName = swiftCtx.getIdentifier(operatorName).str(); isFunction = true; - addEmptyArgNamesForClangFunction(functionDecl, argumentNames); + addDefaultArgNamesForClangFunction(functionDecl, argumentNames); if (auto cxxMethod = dyn_cast(functionDecl)) { if (op == clang::OverloadedOperatorKind::OO_Star && cxxMethod->param_empty()) { @@ -1947,7 +1951,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, case clang::OverloadedOperatorKind::OO_Call: baseName = "callAsFunction"; isFunction = true; - addEmptyArgNamesForClangFunction(functionDecl, argumentNames); + addDefaultArgNamesForClangFunction(functionDecl, argumentNames); break; case clang::OverloadedOperatorKind::OO_Subscript: { auto returnType = functionDecl->getReturnType(); @@ -1965,7 +1969,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, result.info.accessorKind = ImportedAccessorKind::SubscriptSetter; } isFunction = true; - addEmptyArgNamesForClangFunction(functionDecl, argumentNames); + addDefaultArgNamesForClangFunction(functionDecl, argumentNames); break; } default: @@ -1996,7 +2000,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, if (auto function = dyn_cast(D)) { isFunction = true; - addEmptyArgNamesForClangFunction(function, argumentNames); + addDefaultArgNamesForClangFunction(function, argumentNames); } break; diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 2fa92b0145b9f..f4dd7eeaee3f8 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -2415,6 +2415,7 @@ ClangImporter::Implementation::importParameterType( auto attrs = getImportTypeAttrs(param, /*isParam=*/true); Type swiftParamTy; bool isInOut = false; + bool isConsuming = false; bool isParamTypeImplicitlyUnwrapped = false; // Sometimes we import unavailable typedefs as enums. If that's the case, @@ -2448,7 +2449,7 @@ ClangImporter::Implementation::importParameterType( return std::nullopt; } else if (isa(paramTy) && isa(paramTy->getPointeeType())) { - // We don't support rvalue reference / universal perfect ref, bail. + // We don't support universal reference, bail. if (paramTy->isRValueReferenceType()) { addImportDiagnosticFn(Diagnostic(diag::rvalue_ref_params_not_imported)); return std::nullopt; @@ -2469,26 +2470,25 @@ ClangImporter::Implementation::importParameterType( if (!swiftParamTy) { // C++ reference types are brought in as direct // types most commonly. - auto refPointeeType = - importer::getCxxReferencePointeeTypeOrNone(paramTy.getTypePtr()); - if (refPointeeType) { + if (auto refPointeeType = + getCxxReferencePointeeTypeOrNone(paramTy.getTypePtr())) { // We don't support reference type to a dependent type, just bail. if ((*refPointeeType)->isDependentType()) { return std::nullopt; } - // We don't support rvalue reference types, just bail. - if (paramTy->isRValueReferenceType()) { - addImportDiagnosticFn(Diagnostic(diag::rvalue_ref_params_not_imported)); - return std::nullopt; - } - + bool isRvalueRef = paramTy->isRValueReferenceType(); // A C++ parameter of type `const &` or ` &` becomes `` - // or `inout ` in Swift. Note that SILGen will use the indirect - // parameter convention for such a type. + // or `inout `. Moreover, `const &&` or ` &&` + // becomes `` or `consuming `. Note that SILGen will use the + // indirect parameter convention for such a type. paramTy = *refPointeeType; - if (!paramTy.isConstQualified()) - isInOut = true; + if (!paramTy.isConstQualified()) { + if (isRvalueRef) + isConsuming = true; + else + isInOut = true; + } } } @@ -2552,7 +2552,7 @@ ClangImporter::Implementation::importParameterType( if (isInOut && isDirectUseOfForeignReferenceType(paramTy, swiftParamTy)) isInOut = false; - return ImportParameterTypeResult{swiftParamTy, isInOut, + return ImportParameterTypeResult{swiftParamTy, isInOut, isConsuming, isParamTypeImplicitlyUnwrapped}; } @@ -2606,7 +2606,7 @@ static ParamDecl *getParameterInfo(ClangImporter::Implementation *impl, const clang::ParmVarDecl *param, const Identifier &name, const swift::Type &swiftParamTy, - const bool isInOut, + const bool isInOut, const bool isConsuming, const bool isParamTypeImplicitlyUnwrapped) { // Figure out the name for this parameter. Identifier bodyName = impl->importFullName(param, impl->CurrentVersion) @@ -2632,10 +2632,12 @@ static ParamDecl *getParameterInfo(ClangImporter::Implementation *impl, // Foreign references are already references so they don't need to be passed // as inout. - paramInfo->setSpecifier(isInOut ? ParamSpecifier::InOut - : (param->getAttr() - ? ParamSpecifier::Borrowing - : ParamSpecifier::Default)); + paramInfo->setSpecifier( + isConsuming ? ParamSpecifier::Consuming + : (isInOut ? ParamSpecifier::InOut + : (param->getAttr() + ? ParamSpecifier::Borrowing + : ParamSpecifier::Default))); paramInfo->setInterfaceType(swiftParamTy); impl->recordImplicitUnwrapForDecl(paramInfo, isParamTypeImplicitlyUnwrapped); @@ -2702,6 +2704,7 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList( } auto swiftParamTy = swiftParamTyOpt->swiftTy; bool isInOut = swiftParamTyOpt->isInOut; + bool isConsuming = swiftParamTyOpt->isConsuming; bool isParamTypeImplicitlyUnwrapped = swiftParamTyOpt->isParamTypeImplicitlyUnwrapped; @@ -2710,8 +2713,9 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList( if (index < argNames.size()) name = argNames[index]; - auto paramInfo = getParameterInfo(this, param, name, swiftParamTy, isInOut, - isParamTypeImplicitlyUnwrapped); + auto paramInfo = + getParameterInfo(this, param, name, swiftParamTy, isInOut, isConsuming, + isParamTypeImplicitlyUnwrapped); parameters.push_back(paramInfo); ++index; } @@ -3296,6 +3300,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( } auto swiftParamTy = swiftParamTyOpt->swiftTy; bool isInOut = swiftParamTyOpt->isInOut; + bool isConsuming = swiftParamTyOpt->isConsuming; bool isParamTypeImplicitlyUnwrapped = swiftParamTyOpt->isParamTypeImplicitlyUnwrapped; @@ -3345,8 +3350,9 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( ++nameIndex; // Set up the parameter info - auto paramInfo = getParameterInfo(this, param, name, swiftParamTy, isInOut, - isParamTypeImplicitlyUnwrapped); + auto paramInfo = + getParameterInfo(this, param, name, swiftParamTy, isInOut, isConsuming, + isParamTypeImplicitlyUnwrapped); // Determine whether we have a default argument. if (kind == SpecialMethodKind::Regular || diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index beffd32cdfbad..71d5d09498e64 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -1445,6 +1445,8 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation swift::Type swiftTy; /// If the parameter is or not inout. bool isInOut; + /// If the parameter should be imported as consuming. + bool isConsuming; /// If the parameter is implicitly unwrapped or not. bool isParamTypeImplicitlyUnwrapped; }; diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp index 99dc17eaa5462..90fe2643c2fdf 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp @@ -3347,6 +3347,9 @@ void MoveOnlyAddressCheckerPImpl::rewriteUses( bool isFinalConsume = consumes.claimConsume(destroyPair.first, bits); // Remove destroys that are not the final consuming use. + // TODO: for C++ types we do not want to remove destroys as the caller is + // still responsible for invoking the dtor for the moved-from object. + // See GH Issue #77894. if (!isFinalConsume) { destroyPair.first->eraseFromParent(); continue; diff --git a/test/Interop/Cxx/class/inheritance/using-base-members-module-interface.swift b/test/Interop/Cxx/class/inheritance/using-base-members-module-interface.swift index b653dd2a50491..d80b2f4ab5172 100644 --- a/test/Interop/Cxx/class/inheritance/using-base-members-module-interface.swift +++ b/test/Interop/Cxx/class/inheritance/using-base-members-module-interface.swift @@ -21,6 +21,7 @@ // CHECK-NEXT: } // CHECK: struct UsingBaseConstructorWithParam { +// CHECK-NEXT: init(consuming _: consuming IntBox) // CHECK-NEXT: init(_: IntBox) // CHECK-NEXT: init(_: UInt32) // CHECK-NEXT: init(_: Int32) @@ -29,6 +30,7 @@ // CHECK: struct UsingBaseConstructorEmpty { // CHECK-NEXT: init() +// CHECK-NEXT: init(consuming _: consuming Empty) // CHECK-NEXT: init(_: Empty) // CHECK-NEXT: var value: Int32 // CHECK-NEXT: } diff --git a/test/Interop/Cxx/operators/member-inline-typechecker.swift b/test/Interop/Cxx/operators/member-inline-typechecker.swift index 6d4d3bc8c55b7..879d02cf4ee85 100644 --- a/test/Interop/Cxx/operators/member-inline-typechecker.swift +++ b/test/Interop/Cxx/operators/member-inline-typechecker.swift @@ -34,13 +34,13 @@ writeOnlyIntArray[2] = 654 let writeOnlyValue = writeOnlyIntArray[2] var readOnlyRvalueParam = ReadOnlyRvalueParam() -let readOnlyRvalueVal = readOnlyRvalueParam[1] // expected-error {{value of type 'ReadOnlyRvalueParam' has no subscripts}} +let readOnlyRvalueVal = readOnlyRvalueParam[consuming: 1] var readWriteRvalueParam = ReadWriteRvalueParam() -let readWriteRvalueVal = readWriteRvalueParam[1] // expected-error {{value of type 'ReadWriteRvalueParam' has no subscripts}} +let readWriteRvalueVal = readWriteRvalueParam[consuming: 1] var readWriteRvalueGetterParam = ReadWriteRvalueGetterParam() -let readWriteRvalueGetterVal = readWriteRvalueGetterParam[1] +let readWriteRvalueGetterVal = readWriteRvalueGetterParam[consuming: 1] var diffTypesArray = DifferentTypesArray() let diffTypesResultInt: Int32 = diffTypesArray[0] diff --git a/test/Interop/Cxx/reference/reference-cannot-import-diagnostic.swift b/test/Interop/Cxx/reference/reference-cannot-import-diagnostic.swift index 803e686dbb4f5..48e1b3e45ef0d 100644 --- a/test/Interop/Cxx/reference/reference-cannot-import-diagnostic.swift +++ b/test/Interop/Cxx/reference/reference-cannot-import-diagnostic.swift @@ -22,9 +22,7 @@ import Test public func test() { var x: CInt = 2 - acceptRValueRef(x) // expected-error {{cannot find 'acceptRValueRef' in scope}} - // CHECK: note: function 'acceptRValueRef' unavailable (cannot import) - // CHECK: note: C++ functions with rvalue reference parameters are unavailable in Swift + acceptRValueRef(consuming: x) notStdMove(x) // expected-error {{cannot find 'notStdMove' in scope}} // CHECK: note: function 'notStdMove' unavailable (cannot import)