Skip to content

Commit 7214650

Browse files
authored
Merge pull request #62745 from tshortli/has-symbol-clang-decls
Sema/IRGen: Add clang decl support to `#_hasSymbol`
2 parents 29bf82e + 2e8857d commit 7214650

20 files changed

+224
-13
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6730,6 +6730,12 @@ WARNING(has_symbol_decl_must_be_weak,none,
67306730
(DescriptiveDeclKind, DeclName))
67316731
ERROR(has_symbol_invalid_expr,none,
67326732
"'#_hasSymbol' condition must refer to a declaration", ())
6733+
ERROR(has_symbol_invalid_decl_use_responds_to_selector,none,
6734+
"'#_hasSymbol' cannot be used with Objective-C %select{method|property}0 "
6735+
"'%1'; use respondsToSelector() instead",
6736+
(unsigned, StringRef))
6737+
ERROR(has_symbol_invalid_decl,none,
6738+
"'#_hasSymbol' cannot be used with this declaration", ())
67336739

67346740
//------------------------------------------------------------------------------
67356741
// MARK: Type erasure

include/swift/SIL/SILSymbolVisitor.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,14 @@ class SILSymbolVisitor {
128128

129129
template <typename F>
130130
void enumerateFunctionsForHasSymbol(SILModule &M, ValueDecl *D, F Handler) {
131+
// Handle clang decls separately.
132+
if (auto *clangDecl = D->getClangDecl()) {
133+
if (isa<clang::FunctionDecl>(clangDecl))
134+
Handler(SILDeclRef(D).asForeign());
135+
136+
return;
137+
}
138+
131139
class SymbolVisitor : public SILSymbolVisitor {
132140
F Handler;
133141

lib/AST/ASTPrinter.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7126,7 +7126,6 @@ swift::getInheritedForPrinting(
71267126
}
71277127

71287128
// Collect synthesized conformances.
7129-
auto &ctx = decl->getASTContext();
71307129
llvm::SetVector<ProtocolDecl *> protocols;
71317130
llvm::TinyPtrVector<ProtocolDecl *> uncheckedProtocols;
71327131
for (auto attr : decl->getAttrs().getAttributes<SynthesizedProtocolAttr>()) {

lib/IRGen/GenHasSymbol.cpp

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "swift/SIL/SILFunctionBuilder.h"
2222
#include "swift/SIL/SILModule.h"
2323
#include "swift/SIL/SILSymbolVisitor.h"
24+
#include "clang/AST/DeclObjC.h"
25+
#include "clang/AST/GlobalDecl.h"
2426

2527
#include "GenDecl.h"
2628
#include "IRGenFunction.h"
@@ -68,9 +70,8 @@ class HasSymbolIRGenVisitor : public IRSymbolVisitor {
6870
SILFunction *silFn = IGM.getSILModule().lookUpFunction(name);
6971
// Definitions for each SIL function should have been emitted by SILGen.
7072
assert(silFn && "missing SIL function?");
71-
if (silFn) {
73+
if (silFn)
7274
addFunction(silFn);
73-
}
7475
}
7576

7677
public:
@@ -111,6 +112,39 @@ class HasSymbolIRGenVisitor : public IRSymbolVisitor {
111112
}
112113
};
113114

115+
static llvm::Constant *
116+
getAddrOfLLVMVariableForClangDecl(IRGenModule &IGM, ValueDecl *decl,
117+
const clang::Decl *clangDecl) {
118+
if (isa<clang::FunctionDecl>(clangDecl)) {
119+
SILFunction *silFn =
120+
IGM.getSILModule().lookUpFunction(SILDeclRef(decl).asForeign());
121+
assert(silFn && "missing SIL function?");
122+
return silFn ? IGM.getAddrOfSILFunction(silFn, NotForDefinition) : nullptr;
123+
}
124+
125+
if (auto var = dyn_cast<clang::ObjCInterfaceDecl>(clangDecl))
126+
return IGM.getAddrOfObjCClass(cast<ClassDecl>(decl), NotForDefinition);
127+
128+
llvm::report_fatal_error("Unexpected clang decl kind");
129+
}
130+
131+
static void
132+
getSymbolAddrsForDecl(IRGenModule &IGM, ValueDecl *decl,
133+
llvm::SmallVector<llvm::Constant *, 4> &addrs) {
134+
if (auto *clangDecl = decl->getClangDecl()) {
135+
if (auto *addr = getAddrOfLLVMVariableForClangDecl(IGM, decl, clangDecl))
136+
addrs.push_back(addr);
137+
return;
138+
}
139+
140+
SILSymbolVisitorOptions opts;
141+
opts.VisitMembers = false;
142+
auto silCtx = SILSymbolVisitorContext(IGM.getSwiftModule(), opts);
143+
auto linkInfo = UniversalLinkageInfo(IGM);
144+
auto symbolVisitorCtx = IRSymbolVisitorContext(linkInfo, silCtx);
145+
HasSymbolIRGenVisitor(IGM, addrs).visit(decl, symbolVisitorCtx);
146+
}
147+
114148
llvm::Function *IRGenModule::emitHasSymbolFunction(ValueDecl *decl) {
115149

116150
PrettyStackTraceDecl trace("emitting #_hasSymbol query for", decl);
@@ -119,14 +153,9 @@ llvm::Function *IRGenModule::emitHasSymbolFunction(ValueDecl *decl) {
119153
auto func = cast<llvm::Function>(getOrCreateHelperFunction(
120154
mangler.mangleHasSymbolQuery(decl), Int1Ty, {},
121155
[decl, this](IRGenFunction &IGF) {
122-
SILSymbolVisitorOptions opts;
123-
opts.VisitMembers = false;
124-
auto silCtx = SILSymbolVisitorContext(getSwiftModule(), opts);
125-
auto linkInfo = UniversalLinkageInfo(*this);
126-
auto symbolVisitorCtx = IRSymbolVisitorContext(linkInfo, silCtx);
127156
auto &Builder = IGF.Builder;
128157
llvm::SmallVector<llvm::Constant *, 4> addrs;
129-
HasSymbolIRGenVisitor(*this, addrs).visit(decl, symbolVisitorCtx);
158+
getSymbolAddrsForDecl(*this, decl, addrs);
130159

131160
llvm::Value *ret = nullptr;
132161
for (llvm::Constant *addr : addrs) {

lib/Sema/MiscDiagnostics.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "swift/Parse/Parser.h"
3939
#include "swift/Sema/ConstraintSystem.h"
4040
#include "swift/Sema/IDETypeChecking.h"
41+
#include "clang/AST/DeclObjC.h"
4142
#include "llvm/ADT/MapVector.h"
4243
#include "llvm/ADT/StringSwitch.h"
4344
#include "llvm/Support/SaveAndRestore.h"
@@ -4470,6 +4471,35 @@ static bool diagnoseAvailabilityCondition(PoundAvailableInfo *info,
44704471
return false;
44714472
}
44724473

4474+
/// Diagnoses whether the given clang::Decl can be referenced by a
4475+
/// `if #_hasSymbol(...)` condition. Returns true if a diagnostic was emitted.
4476+
static bool diagnoseHasSymbolConditionClangDecl(SourceLoc loc,
4477+
const clang::Decl *clangDecl,
4478+
ASTContext &ctx) {
4479+
if (isa<clang::ObjCInterfaceDecl>(clangDecl) ||
4480+
isa<clang::FunctionDecl>(clangDecl))
4481+
return false;
4482+
4483+
if (auto *method = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) {
4484+
// FIXME: Allow objc_direct methods when supported by IRGen.
4485+
ctx.Diags.diagnose(loc,
4486+
diag::has_symbol_invalid_decl_use_responds_to_selector,
4487+
/*isProperty*/ false, method->getNameAsString());
4488+
return true;
4489+
}
4490+
4491+
if (auto *property = dyn_cast<clang::ObjCPropertyDecl>(clangDecl)) {
4492+
// FIXME: Allow objc_direct properties when supported by IRGen.
4493+
ctx.Diags.diagnose(loc,
4494+
diag::has_symbol_invalid_decl_use_responds_to_selector,
4495+
/*isProperty*/ true, property->getNameAsString());
4496+
return true;
4497+
}
4498+
4499+
ctx.Diags.diagnose(loc, diag::has_symbol_invalid_decl);
4500+
return true;
4501+
}
4502+
44734503
/// Diagnoses a `if #_hasSymbol(...)` condition. Returns true if a diagnostic
44744504
/// was emitted.
44754505
static bool diagnoseHasSymbolCondition(PoundHasSymbolInfo *info,
@@ -4495,6 +4525,12 @@ static bool diagnoseHasSymbolCondition(PoundHasSymbolInfo *info,
44954525
return true;
44964526
}
44974527

4528+
if (auto *clangDecl = decl->getClangDecl()) {
4529+
if (diagnoseHasSymbolConditionClangDecl(symbolExpr->getLoc(), clangDecl,
4530+
ctx))
4531+
return true;
4532+
}
4533+
44984534
if (DC->getFragileFunctionKind().kind == FragileFunctionKind::None &&
44994535
!decl->isWeakImported(DC->getParentModule())) {
45004536
// `if #_hasSymbol(someStronglyLinkedSymbol)` is functionally a no-op
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// NOTE: This header is used on platforms that do not support Obj-C.
2+
3+
extern void clangFunc(int x);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@import Foundation;
2+
3+
@interface ObjCClass : NSObject
4+
@end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module has_symbol_helper_clang {
2+
header "has_symbol_helper_clang.h"
3+
export *
4+
}
5+
6+
module has_symbol_helper_objc {
7+
header "has_symbol_helper_objc.h"
8+
export *
9+
}

test/IRGen/has_symbol.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/has_symbol_helper.swiftmodule -parse-as-library %S/Inputs/has_symbol_helper.swift -enable-library-evolution -disable-availability-checking
3-
// RUN: %target-swift-frontend -emit-irgen %s -I %t -module-name test | %FileCheck %s
2+
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/has_symbol_helper.swiftmodule -parse-as-library %S/Inputs/has_symbol/has_symbol_helper.swift -enable-library-evolution -disable-availability-checking
3+
// RUN: %target-swift-frontend -emit-irgen %s -I %t -I %S/Inputs/has_symbol -module-name test | %FileCheck %s
44

55
// UNSUPPORTED: OS=windows-msvc
66

test/IRGen/has_symbol_async.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/has_symbol_helper.swiftmodule -parse-as-library %S/Inputs/has_symbol_helper.swift -enable-library-evolution -disable-availability-checking -DCONCURRENCY
2+
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/has_symbol_helper.swiftmodule -parse-as-library %S/Inputs/has_symbol/has_symbol_helper.swift -enable-library-evolution -disable-availability-checking -DCONCURRENCY
33
// RUN: %target-swift-frontend -emit-irgen %s -I %t -module-name test | %FileCheck %s
44

55
// REQUIRES: concurrency

test/IRGen/has_symbol_clang.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-irgen %s -I %t -I %S/Inputs/has_symbol -module-name test | %FileCheck %s
3+
4+
// UNSUPPORTED: OS=windows-msvc
5+
6+
@_weakLinked import has_symbol_helper_clang
7+
8+
public func testClangDecls() {
9+
// CHECK: %{{[0-9]+}} = call i1 @"$sSo9clangFuncyys5Int32VFTwS"()
10+
if #_hasSymbol(clangFunc(_:)) {}
11+
}
12+
13+
// --- clangFunc(_:) ---
14+
// CHECK: define linkonce_odr hidden i1 @"$sSo9clangFuncyys5Int32VFTwS"() #1 {
15+
// CHECK: ret i1 icmp ne (void (i32)* @clangFunc, void (i32)* null)

test/IRGen/has_symbol_objc.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-irgen %s -I %t -I %S/Inputs/has_symbol -module-name test | %FileCheck %s
3+
4+
// REQUIRES: objc_interop
5+
6+
@_weakLinked import has_symbol_helper_objc
7+
8+
public func testClassTypes() {
9+
// CHECK: %{{[0-9]+}} = call i1 @"$sSo9ObjCClassCTwS"()
10+
if #_hasSymbol(ObjCClass.self) {}
11+
}
12+
13+
// CHECK: define linkonce_odr hidden i1 @"$sSo9ObjCClassCTwS"()
14+
// CHECK: ret i1 icmp ne (%objc_class* @"OBJC_CLASS_$_ObjCClass", %objc_class* null)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// NOTE: This header is used on platforms that do not support Obj-C.
2+
3+
extern void clangFunc(int x);
4+
extern int clangGlobalVar;
5+
struct ClangStruct {
6+
int x;
7+
};
8+
#define CONSTANT_MACRO 42
9+
enum ClangEnum { ClangEnumMember = 0 };
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
@import Foundation;
2+
3+
extern NSString *const StringConstant;
4+
5+
@interface ObjCClass : NSObject
6+
@property int classMemberProperty;
7+
@property(direct) int directClassMemberProperty;
8+
- (void)classMemberMethod;
9+
- (void)directClassMemberMethod __attribute__((objc_direct));
10+
@end
11+
12+
@protocol ObjCProtocol <NSObject>
13+
@property NSObject *protocolMemberProperty;
14+
- (void)protocolMemberMethod;
15+
@end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module has_symbol_helper_clang {
2+
header "has_symbol_helper_clang.h"
3+
export *
4+
}
5+
6+
module has_symbol_helper_objc {
7+
header "has_symbol_helper_objc.h"
8+
export *
9+
}

test/Sema/has_symbol.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/has_symbol_helper.swiftmodule -parse-as-library %S/Inputs/has_symbol_helper.swift -enable-library-evolution
2+
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/has_symbol_helper.swiftmodule -parse-as-library %S/Inputs/has_symbol/has_symbol_helper.swift -enable-library-evolution
33
// RUN: %target-typecheck-verify-swift -disable-availability-checking -I %t
44
// RUN: %target-typecheck-verify-swift -disable-availability-checking -I %t -enable-experimental-feature ResultBuilderASTTransform
55

test/Sema/has_symbol_clang.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking -I %S/Inputs/has_symbol/
2+
3+
// UNSUPPORTED: OS=windows-msvc
4+
5+
@_weakLinked import has_symbol_helper_clang
6+
7+
func testFunctions() {
8+
if #_hasSymbol(clangFunc) {}
9+
if #_hasSymbol(clangFunc(_:)) {}
10+
}
11+
12+
func testGlobalVars() {
13+
// FIXME: Add support for clang global vars
14+
if #_hasSymbol(clangGlobalVar) {} // expected-error {{'#_hasSymbol' cannot be used with this declaration}}
15+
}
16+
17+
func testTypes() {
18+
if #_hasSymbol(ClangStruct.self) {} // expected-error {{'#_hasSymbol' cannot be used with this declaration}}
19+
if #_hasSymbol(ClangEnum.self) {} // expected-error {{'#_hasSymbol' cannot be used with this declaration}}
20+
}
21+
22+
func testMacros() {
23+
if #_hasSymbol(CONSTANT_MACRO) {} // FIXME: This should be diagnosed
24+
}
25+
26+
func testEnum() {
27+
if #_hasSymbol(ClangEnumMember) {} // expected-error {{'#_hasSymbol' cannot be used with this declaration}}
28+
}
29+
30+
func testStruct(_ s: ClangStruct) {
31+
if #_hasSymbol(s.x) {} // expected-error {{'#_hasSymbol' cannot be used with this declaration}}
32+
}

test/Sema/has_symbol_objc.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking -I %S/Inputs/has_symbol/
2+
3+
// REQUIRES: objc_interop
4+
5+
@_weakLinked import has_symbol_helper_objc
6+
7+
func testTypes() {
8+
if #_hasSymbol(ObjCClass.self) {}
9+
if #_hasSymbol(ObjCProtocol.self) {} // expected-error {{'#_hasSymbol' cannot be used with this declaration}}
10+
}
11+
12+
func testClassMembers(_ c: ObjCClass) {
13+
if #_hasSymbol(c.classMemberProperty) {} // expected-error {{'#_hasSymbol' cannot be used with Objective-C property 'classMemberProperty'; use respondsToSelector() instead}}
14+
if #_hasSymbol(c.classMemberMethod) {} // expected-error {{'#_hasSymbol' cannot be used with Objective-C method 'classMemberMethod'; use respondsToSelector() instead}}
15+
16+
if #_hasSymbol(c.directClassMemberProperty) {} // expected-error {{'#_hasSymbol' cannot be used with Objective-C property 'directClassMemberProperty'; use respondsToSelector() instead}}
17+
if #_hasSymbol(c.directClassMemberMethod) {} // expected-error {{'#_hasSymbol' cannot be used with Objective-C method 'directClassMemberMethod'; use respondsToSelector() instead}}
18+
}
19+
20+
func testProtocolMembers(_ p: ObjCProtocol) {
21+
if #_hasSymbol(p.protocolMemberProperty) {} // expected-error {{'#_hasSymbol' cannot be used with Objective-C property 'protocolMemberProperty'; use respondsToSelector() instead}}
22+
if #_hasSymbol(p.protocolMemberMethod) {} // expected-error {{'#_hasSymbol' cannot be used with Objective-C method 'protocolMemberMethod'; use respondsToSelector() instead}}
23+
}

0 commit comments

Comments
 (0)