Skip to content

Commit 0a487a5

Browse files
committed
Sema: Diagnose unsupported clang decls for #_hasSymbol.
Progress towards rdar://103408651.
1 parent 8880f20 commit 0a487a5

File tree

9 files changed

+131
-1
lines changed

9 files changed

+131
-1
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

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: 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+
// UNSUPPORTED: OS=windows-msvc
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)