[clang] [Clang][Sema] Allow qualified type names in `swift_name` attribute (PR #145947)
Egor Zhdan via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 26 10:57:36 PDT 2025
https://github.com/egorzhdan created https://github.com/llvm/llvm-project/pull/145947
This allows adding `__attribute__((swift_name("MyNamespace.MyType.my_method()")))` on standalone C++ functions to make Swift import them as member functions of a type that is nested in a C++ namespace.
rdar://138934888
>From f6c3959927e724d0746e343b02abfc1f9f948914 Mon Sep 17 00:00:00 2001
From: Egor Zhdan <e_zhdan at apple.com>
Date: Thu, 26 Jun 2025 18:56:23 +0100
Subject: [PATCH] [Clang][Sema] Allow qualified type names in `swift_name`
attribute
This allows adding `__attribute__((swift_name("MyNamespace.MyType.my_method()")))` on standalone C++ functions to make Swift import them as member functions of a type that is nested in a C++ namespace.
rdar://138934888
---
clang/lib/Sema/SemaSwift.cpp | 17 ++++++---
clang/test/SemaObjCXX/attr-swift_name-cxx.mm | 36 ++++++++++++++++++++
2 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Sema/SemaSwift.cpp b/clang/lib/Sema/SemaSwift.cpp
index 4aae855a24b8f..4000beff7dc49 100644
--- a/clang/lib/Sema/SemaSwift.cpp
+++ b/clang/lib/Sema/SemaSwift.cpp
@@ -72,6 +72,15 @@ static bool isValidSwiftErrorResultType(QualType Ty) {
return isValidSwiftContextType(Ty);
}
+static bool isValidSwiftContextName(StringRef ContextName) {
+ // ContextName might be qualified, e.g. 'MyNamespace.MyStruct'.
+ SmallVector<StringRef, 1> ContextNameComponents;
+ ContextName.split(ContextNameComponents, '.');
+ return all_of(ContextNameComponents, [&](StringRef Component) {
+ return isValidAsciiIdentifier(Component);
+ });
+}
+
void SemaSwift::handleAttrAttr(Decl *D, const ParsedAttr &AL) {
if (AL.isInvalid() || AL.isUsedAsTypeAttr())
return;
@@ -356,11 +365,11 @@ static bool validateSwiftFunctionName(Sema &S, const ParsedAttr &AL,
// Split at the first '.', if it exists, which separates the context name
// from the base name.
- std::tie(ContextName, BaseName) = BaseName.split('.');
+ std::tie(ContextName, BaseName) = BaseName.rsplit('.');
if (BaseName.empty()) {
BaseName = ContextName;
ContextName = StringRef();
- } else if (ContextName.empty() || !isValidAsciiIdentifier(ContextName)) {
+ } else if (ContextName.empty() || !isValidSwiftContextName(ContextName)) {
S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier)
<< AL << /*context*/ 1;
return false;
@@ -584,11 +593,11 @@ bool SemaSwift::DiagnoseName(Decl *D, StringRef Name, SourceLocation Loc,
!IsAsync) {
StringRef ContextName, BaseName;
- std::tie(ContextName, BaseName) = Name.split('.');
+ std::tie(ContextName, BaseName) = Name.rsplit('.');
if (BaseName.empty()) {
BaseName = ContextName;
ContextName = StringRef();
- } else if (!isValidAsciiIdentifier(ContextName)) {
+ } else if (!isValidSwiftContextName(ContextName)) {
Diag(Loc, diag::warn_attr_swift_name_invalid_identifier)
<< AL << /*context*/ 1;
return false;
diff --git a/clang/test/SemaObjCXX/attr-swift_name-cxx.mm b/clang/test/SemaObjCXX/attr-swift_name-cxx.mm
index 658dbfff185ca..9e83c63ecf2f8 100644
--- a/clang/test/SemaObjCXX/attr-swift_name-cxx.mm
+++ b/clang/test/SemaObjCXX/attr-swift_name-cxx.mm
@@ -1,7 +1,43 @@
// RUN: %clang_cc1 -verify -fsyntax-only -fobjc-arc -fblocks %s
+#define SWIFT_NAME(name) __attribute__((swift_name(name)))
#define SWIFT_ASYNC_NAME(name) __attribute__((__swift_async_name__(name)))
+namespace MyNS {
+struct NestedStruct {};
+}
+
+void nestedStruct_method(MyNS::NestedStruct) SWIFT_NAME("MyNS.NestedStruct.method(self:)");
+void nestedStruct_methodConstRef(const MyNS::NestedStruct&) SWIFT_NAME("MyNS.NestedStruct.methodConstRef(self:)");
+void nestedStruct_invalidContext1(MyNS::NestedStruct) SWIFT_NAME(".MyNS.NestedStruct.invalidContext1(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the context name}}
+void nestedStruct_invalidContext2(MyNS::NestedStruct) SWIFT_NAME("MyNS::NestedStruct.invalidContext2(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the context name}}
+void nestedStruct_invalidContext3(MyNS::NestedStruct) SWIFT_NAME("::MyNS::NestedStruct.invalidContext3(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the context name}}
+void nestedStruct_invalidContext4(MyNS::NestedStruct) SWIFT_NAME("MyNS..NestedStruct.invalidContext4(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the context name}}
+void nestedStruct_invalidContext5(MyNS::NestedStruct) SWIFT_NAME("MyNS.NestedStruct.invalidContext5.(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the base name}}
+void nestedStruct_invalidContext6(MyNS::NestedStruct) SWIFT_NAME("MyNS.NestedStruct::invalidContext6(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the base name}}
+
+namespace MyNS {
+namespace MyDeepNS {
+struct DeepNestedStruct {};
+}
+}
+
+void deepNestedStruct_method(MyNS::MyDeepNS::DeepNestedStruct) SWIFT_NAME("MyNS.MyDeepNS.DeepNestedStruct.method(self:)");
+void deepNestedStruct_methodConstRef(const MyNS::MyDeepNS::DeepNestedStruct&) SWIFT_NAME("MyNS.MyDeepNS.DeepNestedStruct.methodConstRef(self:)");
+void deepNestedStruct_invalidContext(const MyNS::MyDeepNS::DeepNestedStruct&) SWIFT_NAME("MyNS::MyDeepNS::DeepNestedStruct.methodConstRef(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the context name}}
+
+typedef MyNS::MyDeepNS::DeepNestedStruct DeepNestedStructTypedef;
+
+void deepNestedStructTypedef_method(DeepNestedStructTypedef) SWIFT_NAME("DeepNestedStructTypedef.method(self:)");
+void deepNestedStructTypedef_methodQualName(MyNS::MyDeepNS::DeepNestedStruct) SWIFT_NAME("DeepNestedStructTypedef.method(self:)");
+
+struct TopLevelStruct {
+ struct StructInStruct {};
+};
+
+void structInStruct_method(TopLevelStruct::StructInStruct) SWIFT_NAME("TopLevelStruct.StructInStruct.method(self:)");
+void structInStruct_invalidContext(TopLevelStruct::StructInStruct) SWIFT_NAME("TopLevelStruct::StructInStruct.method(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the context name}}
+
typedef int (^CallbackTy)(void);
class CXXClass {
More information about the cfe-commits
mailing list