From 9fafb642ba840001096b513f6bbe77db87bc7112 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Fri, 12 Dec 2025 12:03:36 +0000 Subject: [PATCH] [cxx-interop] Import operators renamed via `swift_name` consistently Normally Swift imports `T& operator*` as `var pointee: T`. However, when the C++ operator has `swift_name` attribute attached to it, the importing was inconsistent: the renamed function was marked as deprecated, and an additional undesired overload was created. For instance: ``` const std::string& operator*() const SWIFT_NAME(dereference()); ``` was imported as an unavailable/deprecated `func dereference()`, and an additional overload of `func *(_:)` was created. rdar://163500978 --- lib/ClangImporter/ImportDecl.cpp | 5 +++++ .../Cxx/operators/Inputs/module.modulemap | 5 +++++ .../Cxx/operators/Inputs/renamed-operators.h | 16 ++++++++++++++++ .../renamed-operators-module-interface.swift | 11 +++++++++++ .../renamed-operators-typechecker.swift | 9 +++++++++ 5 files changed, 46 insertions(+) create mode 100644 test/Interop/Cxx/operators/Inputs/renamed-operators.h create mode 100644 test/Interop/Cxx/operators/renamed-operators-module-interface.swift create mode 100644 test/Interop/Cxx/operators/renamed-operators-typechecker.swift diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 0bbcc47820825..8ee5a421681b2 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3727,6 +3727,11 @@ namespace { clang::OverloadedOperatorKind cxxOperatorKind) { if (cxxOperatorKind == clang::OverloadedOperatorKind::OO_None) return true; + // If this operator was renamed via swift_name attribute, the imported + // Swift function already has the specified name. Do not apply any special + // handling to it. + if (importedName.hasCustomName()) + return true; auto dc = func->getDeclContext(); auto typeDecl = dc->getSelfNominalTypeDecl(); diff --git a/test/Interop/Cxx/operators/Inputs/module.modulemap b/test/Interop/Cxx/operators/Inputs/module.modulemap index 5863fbb4abba2..36515f4023af6 100644 --- a/test/Interop/Cxx/operators/Inputs/module.modulemap +++ b/test/Interop/Cxx/operators/Inputs/module.modulemap @@ -17,3 +17,8 @@ module NonMemberOutOfLine { header "non-member-out-of-line.h" requires cplusplus } + +module RenamedOperators { + header "renamed-operators.h" + requires cplusplus +} diff --git a/test/Interop/Cxx/operators/Inputs/renamed-operators.h b/test/Interop/Cxx/operators/Inputs/renamed-operators.h new file mode 100644 index 0000000000000..9a2dc77a37707 --- /dev/null +++ b/test/Interop/Cxx/operators/Inputs/renamed-operators.h @@ -0,0 +1,16 @@ +struct HasRenamedOperatorStar { + int value; + + const int &operator*() const __attribute__((swift_name("dereference()"))) { + return value; + } +}; + +struct HasRenamedOperatorPlusPlus { + int value; + + HasRenamedOperatorPlusPlus &operator++() __attribute__((swift_name("plusPlus()"))) { + value++; + return *this; + } +}; diff --git a/test/Interop/Cxx/operators/renamed-operators-module-interface.swift b/test/Interop/Cxx/operators/renamed-operators-module-interface.swift new file mode 100644 index 0000000000000..3c3dfb44b29eb --- /dev/null +++ b/test/Interop/Cxx/operators/renamed-operators-module-interface.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=RenamedOperators -I %S/Inputs -source-filename=x -cxx-interoperability-mode=upcoming-swift | %FileCheck %s + +// CHECK: struct HasRenamedOperatorStar { +// CHECK-NOT: prefix static func * (lhs: HasRenamedOperatorStar) +// CHECK: func dereference() -> UnsafePointer +// CHECK: } + +// CHECK: struct HasRenamedOperatorPlusPlus { +// CHECK-NOT: prefix static func ++ (lhs: HasRenamedOperatorPlusPlus) +// CHECK: mutating func plusPlus() -> UnsafeMutablePointer +// CHECK: } diff --git a/test/Interop/Cxx/operators/renamed-operators-typechecker.swift b/test/Interop/Cxx/operators/renamed-operators-typechecker.swift new file mode 100644 index 0000000000000..0b92576e1a2f1 --- /dev/null +++ b/test/Interop/Cxx/operators/renamed-operators-typechecker.swift @@ -0,0 +1,9 @@ +// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=default + +import RenamedOperators + +let star = HasRenamedOperatorStar(value: 123) +_ = *star // expected-error {{'*' is not a prefix unary operator}} + +let plusPlus = HasRenamedOperatorStar(value: 123) +plusPlus++ // expected-error {{cannot find operator '++' in scope; did you mean '+= 1'?}}