From dedfb9e0ab0570b7cbb6b59dbd3cfc7344542167 Mon Sep 17 00:00:00 2001 From: Hiroshi Yamauchi Date: Thu, 19 Sep 2024 16:00:15 -0700 Subject: [PATCH] Ensure that bridged types are indirectly returned on Windows ARM64 On Windows ARM64, how a struct value type is returned is sensitive to conditions including whether a user-defined constructor exists, etc. See https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#return-values That caused a calling convention mismatch between the non-USED_IN_CPP_SOURCE (Swift) side and the USE_IN_CPP_SOURCE (C++) side and a crash. Following https://github.com/swiftlang/swift/pull/76433 add constructors to several bridged C++ struct/class types so that the calling convention matches. This is a partial fix for https://github.com/swiftlang/swift/issues/74866 --- include/swift/AST/ASTBridging.h | 24 ++++++++++ include/swift/Basic/BasicBridging.h | 13 +++++ include/swift/Parse/ParseBridging.h | 4 ++ include/swift/SIL/SILBridging.h | 48 +++++++++++++++++++ .../swift/SILOptimizer/OptimizerBridging.h | 4 ++ 5 files changed, 93 insertions(+) diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 0e946c8531ab1..6ba501bf74358 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -81,6 +81,10 @@ class BridgedDeclBaseName { BridgedIdentifier Ident; public: + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedDeclBaseName() : Ident() {} + #ifdef USED_IN_CPP_SOURCE BridgedDeclBaseName(swift::DeclBaseName baseName) : Ident(baseName.Ident) {} @@ -107,6 +111,10 @@ class BridgedDeclNameRef { void *_Nonnull opaque; public: + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedDeclNameRef() : opaque() {} + #ifdef USED_IN_CPP_SOURCE BridgedDeclNameRef(swift::DeclNameRef name) : opaque(name.getOpaqueValue()) {} @@ -163,6 +171,10 @@ class BridgedASTContext { swift::ASTContext * _Nonnull Ctx; public: + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedASTContext() : Ctx() {} + #ifdef USED_IN_CPP_SOURCE SWIFT_UNAVAILABLE("Use init(raw:) instead") BridgedASTContext(swift::ASTContext &ctx) : Ctx(&ctx) {} @@ -390,6 +402,10 @@ class BridgedDiagnosticArgument { int64_t storage[3]; public: + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedDiagnosticArgument() {} + #ifdef USED_IN_CPP_SOURCE BridgedDiagnosticArgument(const swift::DiagnosticArgument &arg) { *reinterpret_cast(&storage) = arg; @@ -407,6 +423,10 @@ class BridgedDiagnosticFixIt { int64_t storage[7]; public: + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedDiagnosticFixIt() {} + #ifdef USED_IN_CPP_SOURCE BridgedDiagnosticFixIt(const swift::DiagnosticInfo::FixIt &fixit){ *reinterpret_cast(&storage) = fixit; @@ -1406,6 +1426,10 @@ class BridgedStmtConditionElement { void *_Nonnull Raw; public: + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedStmtConditionElement() {} + #ifdef USED_IN_CPP_SOURCE BridgedStmtConditionElement(swift::StmtConditionElement elem) : Raw(elem.getOpaqueValue()) {} diff --git a/include/swift/Basic/BasicBridging.h b/include/swift/Basic/BasicBridging.h index 046b72b71239b..63f10fc24a327 100644 --- a/include/swift/Basic/BasicBridging.h +++ b/include/swift/Basic/BasicBridging.h @@ -23,6 +23,15 @@ // Pure bridging mode does not permit including any C++/llvm/swift headers. // See also the comments for `BRIDGING_MODE` in the top-level CMakeLists.txt file. // +// +// Note: On Windows ARM64, how a C++ struct/class value type is +// returned is sensitive to conditions including whether a +// user-defined constructor exists, etc. See +// https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#return-values +// So, if a C++ struct/class type is returned as a value between Swift +// and C++, we need to be careful to match the return convention +// matches between the non-USED_IN_CPP_SOURCE (Swift) side and the +// USE_IN_CPP_SOURCE (C++) side. #include "swift/Basic/BridgedSwiftObject.h" #include "swift/Basic/Compiler.h" @@ -227,6 +236,10 @@ class BridgedOwnedString { size_t Length; public: + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedOwnedString() {} + #ifdef USED_IN_CPP_SOURCE BridgedOwnedString(const std::string &stringToCopy); diff --git a/include/swift/Parse/ParseBridging.h b/include/swift/Parse/ParseBridging.h index fb48fc8be49b5..e18fcf2a780ca 100644 --- a/include/swift/Parse/ParseBridging.h +++ b/include/swift/Parse/ParseBridging.h @@ -30,6 +30,10 @@ class BridgedLegacyParser { swift::Parser *_Nonnull const handle; public: + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedLegacyParser() : handle(nullptr) {} + #ifdef USED_IN_CPP_SOURCE BridgedLegacyParser(swift::Parser &P) : handle(&P) {} diff --git a/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h index ccad1a58aa0a6..f8be3a9845796 100644 --- a/include/swift/SIL/SILBridging.h +++ b/include/swift/SIL/SILBridging.h @@ -83,6 +83,10 @@ struct BridgedResultInfo { swift::TypeBase * _Nonnull type; BridgedResultConvention convention; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedResultInfo() {} + #ifdef USED_IN_CPP_SOURCE inline static BridgedResultConvention castToResultConvention(swift::ResultConvention convention) { @@ -100,6 +104,10 @@ struct OptionalBridgedResultInfo { swift::TypeBase * _Nullable type = nullptr; BridgedResultConvention convention = BridgedResultConvention::Indirect; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + OptionalBridgedResultInfo() {} + #ifdef USED_IN_CPP_SOURCE OptionalBridgedResultInfo(std::optional resultInfo) { if (resultInfo) { @@ -114,6 +122,10 @@ struct OptionalBridgedResultInfo { struct BridgedResultInfoArray { BridgedArrayRef resultInfoArray; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedResultInfoArray() {} + #ifdef USED_IN_CPP_SOURCE BridgedResultInfoArray(llvm::ArrayRef results) : resultInfoArray(results) {} @@ -217,6 +229,10 @@ struct BridgedParameterInfo { struct BridgedParameterInfoArray { BridgedArrayRef parameterInfoArray; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedParameterInfoArray() {} + #ifdef USED_IN_CPP_SOURCE BridgedParameterInfoArray(llvm::ArrayRef parameters) : parameterInfoArray(parameters) {} @@ -235,6 +251,10 @@ struct BridgedParameterInfoArray { struct BridgedYieldInfoArray { BridgedArrayRef yieldInfoArray; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedYieldInfoArray() {} + #ifdef USED_IN_CPP_SOURCE BridgedYieldInfoArray(llvm::ArrayRef yields) : yieldInfoArray(yields) {} @@ -255,6 +275,10 @@ struct BridgedLifetimeDependenceInfo { SwiftUInt targetIndex; bool immortal; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedLifetimeDependenceInfo() {} + #ifdef USED_IN_CPP_SOURCE BridgedLifetimeDependenceInfo(swift::LifetimeDependenceInfo info) : inheritLifetimeParamIndices(info.getInheritIndices()), @@ -273,6 +297,10 @@ struct BridgedLifetimeDependenceInfo { struct BridgedLifetimeDependenceInfoArray { BridgedArrayRef lifetimeDependenceInfoArray; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedLifetimeDependenceInfoArray() {} + #ifdef USED_IN_CPP_SOURCE BridgedLifetimeDependenceInfoArray( llvm::ArrayRef lifetimeDependenceInfo) @@ -373,6 +401,10 @@ struct BridgedType { struct EnumElementIterator { uint64_t storage[4]; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + EnumElementIterator() {} + #ifdef USED_IN_CPP_SOURCE EnumElementIterator(swift::EnumDecl::ElementRange::iterator i) { static_assert(sizeof(EnumElementIterator) >= sizeof(swift::EnumDecl::ElementRange::iterator)); @@ -386,6 +418,10 @@ struct BridgedType { SWIFT_IMPORT_UNSAFE BRIDGED_INLINE EnumElementIterator getNext() const; }; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedType() {} + #ifdef USED_IN_CPP_SOURCE BridgedType(swift::SILType t) : opaqueValue(t.getOpaqueValue()) {} @@ -573,6 +609,10 @@ enum class BridgedMemoryBehavior { struct BridgedLocation { uint64_t storage[3]; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedLocation() {} + #ifdef USED_IN_CPP_SOURCE BridgedLocation(const swift::SILDebugLocation &loc) { *reinterpret_cast(&storage) = loc; @@ -804,6 +844,10 @@ struct BridgedTypeArray { struct BridgedSILTypeArray { BridgedArrayRef typeArray; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + BridgedSILTypeArray() {} + #ifdef USED_IN_CPP_SOURCE BridgedSILTypeArray(llvm::ArrayRef silTypes) : typeArray(silTypes) {} @@ -826,6 +870,10 @@ struct BridgedGenericSpecializationInformation { struct OptionalBridgedSILDebugVariable { uint64_t storage[16]; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + OptionalBridgedSILDebugVariable() {} + #ifdef USED_IN_CPP_SOURCE using OptionalSILDebugVariable = std::optional; diff --git a/include/swift/SILOptimizer/OptimizerBridging.h b/include/swift/SILOptimizer/OptimizerBridging.h index 5d451cd7e5315..759327bad8c99 100644 --- a/include/swift/SILOptimizer/OptimizerBridging.h +++ b/include/swift/SILOptimizer/OptimizerBridging.h @@ -94,6 +94,10 @@ struct BridgedCalleeAnalysis { struct CalleeList { uint64_t storage[3]; + // Ensure that this struct value type will be indirectly returned on + // Windows ARM64 + CalleeList() {} + #ifdef USED_IN_CPP_SOURCE CalleeList(swift::CalleeList list) { *reinterpret_cast(&storage) = list;