[clang] d8ca77e - [Clang][Sema] Allow qualified type names in `swift_name` attribute
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 27 05:21:40 PDT 2025
Author: Egor Zhdan
Date: 2025-06-27T13:21:37+01:00
New Revision: d8ca77e2b96e60f2e2b770bf8e0341e9153fc6bb
URL: https://github.com/llvm/llvm-project/commit/d8ca77e2b96e60f2e2b770bf8e0341e9153fc6bb
DIFF: https://github.com/llvm/llvm-project/commit/d8ca77e2b96e60f2e2b770bf8e0341e9153fc6bb.diff
LOG: [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
Added:
Modified:
clang/lib/Sema/SemaSwift.cpp
clang/test/SemaObjCXX/attr-swift_name-cxx.mm
Removed:
################################################################################
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