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 {


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to