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