Skip to content

[WIP][ObjC] objc_direct method visibility ABI #76608

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions clang/include/clang/AST/DeclObjC.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,20 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
/// True if the method is tagged as objc_direct
bool isDirectMethod() const;

/// True if method is meant to be visible.
///
/// TODO: For now this is only true for a very narrow case where the method
/// must be direct and must also be explicitly marked as
/// __attribute__((visibility("default"))). In the future it may be possible
/// to assume that all direct (or even both direct and indirect) methods are
/// visible but for the time being it is prudent to provide this default
/// visibility behavior as an opt-in only.
bool hasMethodVisibilityDefault() const {
return isDirectMethod() &&
getExplicitVisibility(VisibilityForValue)
.value_or(HiddenVisibility) == DefaultVisibility;
}

/// True if the method has a parameter that's destroyed in the callee.
bool hasParamDestroyedInCallee() const;

Expand Down
10 changes: 8 additions & 2 deletions clang/lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,16 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
}

// \01+[ContainerName(CategoryName) SelectorName]
// Note: If we are mangling for an objc_direct method with external visibility
// then the standard mangling scheme will not work. We must replace the
// square braces with angle braces so in the case of visible direct objc
// methods it results in: +<ContainerName(CategoryName) SelectorName>
// This will include a prefix _ on Darwin.
if (includePrefixByte) {
OS << '\01';
}
OS << (MD->isInstanceMethod() ? '-' : '+') << '[';
OS << (MD->isInstanceMethod() ? '-' : '+');
OS << (MD->hasMethodVisibilityDefault() ? '<' : '[');
if (const auto *CID = MD->getCategory()) {
OS << CID->getClassInterface()->getName();
if (includeCategoryNamespace) {
Expand All @@ -380,7 +386,7 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
}
OS << ' ';
MD->getSelector().print(OS);
OS << ']';
OS << (MD->hasMethodVisibilityDefault() ? '>' : ']');
}

void MangleContext::mangleObjCMethodNameAsSourceName(const ObjCMethodDecl *MD,
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/CodeGen/CGObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,9 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,

const CGFunctionInfo &FI = CGM.getTypes().arrangeObjCMethodDeclaration(OMD);
if (OMD->isDirectMethod()) {
Fn->setVisibility(llvm::Function::HiddenVisibility);
Fn->setVisibility(OMD->hasMethodVisibilityDefault()
? llvm::Function::DefaultVisibility
: llvm::Function::HiddenVisibility);
CGM.SetLLVMFunctionAttributes(OMD, FI, Fn, /*IsThunk=*/false);
CGM.SetLLVMFunctionAttributesForDefinition(OMD, Fn);
} else {
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/CodeGen/CGObjCRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,9 @@ std::string CGObjCRuntime::getSymbolNameForMethod(const ObjCMethodDecl *OMD,
bool includeCategoryName) {
std::string buffer;
llvm::raw_string_ostream out(buffer);
CGM.getCXXABI().getMangleContext().mangleObjCMethodName(OMD, out,
/*includePrefixByte=*/true,
includeCategoryName);
CGM.getCXXABI().getMangleContext().mangleObjCMethodName(
OMD, out,
/*includePrefixByte=*/
!OMD->hasMethodVisibilityDefault(), includeCategoryName);
return buffer;
}
86 changes: 86 additions & 0 deletions clang/test/CodeGenObjC/objc-direct-wrapper.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// RUN: %clang -fobjc-arc -Wno-objc-root-class -ObjC -fobjc-runtime=ios -FFoundation \
// RUN: -DENABLE_VISIBLE_OBJC_DIRECT=1 \
// RUN: -target x86_64-apple-macosx10.15.0 -c -o - %s | \
// RUN: llvm-nm - | FileCheck -check-prefix=CHECK-WRAPPER %s

// RUN: %clang -fobjc-arc -Wno-objc-root-class \
// RUN: -target x86_64-apple-macosx10.15.0 \
// RUN: -ObjC -fobjc-runtime=ios -FFoundation -c -o - %s | llvm-nm - | \
// RUN: FileCheck -check-prefix=CHECK-DEFAULT %s

// RUN: %clang -fobjc-arc -Wno-objc-root-class \
// RUN: -DENABLE_VISIBLE_OBJC_DIRECT=1 \
// RUN: -target x86_64-apple-macosx10.15.0 \
// RUN: -ObjC -fobjc-runtime=ios -FFoundation -c -o - %s -S -emit-llvm | \
// RUN: FileCheck -check-prefix=CHECK-WRAPPER-IR-DEF %s

// RUN: %clang -fobjc-arc -Wno-objc-root-class -DNO_OBJC_IMPL \
// RUN: -DENABLE_VISIBLE_OBJC_DIRECT=1 \
// RUN: -target x86_64-apple-macosx10.15.0 \
// RUN: -ObjC -fobjc-runtime=ios -FFoundation -c -o - %s -S -emit-llvm | \
// RUN: FileCheck -check-prefix=CHECK-WRAPPER-IR-DECLARE %s

// RUN: not %clang -fobjc-arc -Wno-objc-root-class -DENABLE_PROTOCOL_DIRECT_FAIL \
// RUN: -DENABLE_VISIBLE_OBJC_DIRECT=1 \
// RUN: -target x86_64-apple-macosx10.15.0 \
// RUN: -ObjC -fobjc-runtime=ios -FFoundation -c -o - %s -S -emit-llvm 2>&1 | \
// RUN: FileCheck -check-prefix=CHECK-PROTOCOL-DIRECT-FAIL %s

////////////////////////////////////////////////////////////////////////////////

// RUN: %clang -fobjc-arc -Wno-objc-root-class -ObjC -fobjc-runtime=ios -FFoundation \
// RUN: -DENABLE_VISIBLE_OBJC_DIRECT=0 \
// RUN: -target x86_64-apple-macosx10.15.0 -c -o - %s | \
// RUN: llvm-nm - | FileCheck -check-prefix=CHECK-WRAPPER-INDIRECT %s

// RUN: %clang -fobjc-arc -Wno-objc-root-class \
// RUN: -DENABLE_VISIBLE_OBJC_DIRECT=0 \
// RUN: -target x86_64-apple-macosx10.15.0 \
// RUN: -ObjC -fobjc-runtime=ios -FFoundation -c -o - %s -S -emit-llvm | \
// RUN: FileCheck -check-prefix=CHECK-WRAPPER-IR-DEF-INDIRECT %s

// RUN: %clang -fobjc-arc -Wno-objc-root-class -DNO_OBJC_IMPL \
// RUN: -DENABLE_VISIBLE_OBJC_DIRECT=0 \
// RUN: -target x86_64-apple-macosx10.15.0 \
// RUN: -ObjC -fobjc-runtime=ios -FFoundation -c -o - %s -S -emit-llvm | \
// RUN: FileCheck -check-prefix=CHECK-WRAPPER-IR-DECLARE-INDIRECT %s

// CHECK-WRAPPER: T _-<C testMethod:bar:>
// TODO: Fix this
// CHECK-DEFAULT: t -[C testMethod:bar:]
// CHECK-WRAPPER-IR-DEF: define {{(dso_local )?}}void @"-<C testMethod:bar:>"
// CHECK-WRAPPER-IR-DECLARE: declare {{(dso_local )?}}void @"-<C testMethod:bar:>"
// CHECK-PROTOCOL-DIRECT-FAIL: error: 'objc_direct' attribute cannot be applied to methods declared in an Objective-C protocol

// CHECK-WRAPPER-INDIRECT-NOT: T _-<C testMethod:bar:>
// CHECK-WRAPPER-IR-DEF-INDIRECT-NOT: define {{(dso_local )?}}void @"-<C testMethod:bar:>"
// CHECK-WRAPPER-IR-DECLARE-INDIRECT-NOT: declare {{(dso_local )?}}void @"-<C testMethod:bar:>"

#if ENABLE_VISIBLE_OBJC_DIRECT
#define OBJC_DIRECT __attribute__((objc_direct)) __attribute__((visibility("default")))
#else
#define OBJC_DIRECT
#endif

@interface C
- (void)testMethod:(int)arg1 bar:(float)arg2 OBJC_DIRECT;
@end

#ifndef NO_OBJC_IMPL
@implementation C
- (void)testMethod:(int)arg1 bar:(float)arg2 OBJC_DIRECT {
}
@end
#endif

#ifdef ENABLE_PROTOCOL_DIRECT_FAIL
@protocol ProtoDirectVisibleFail
- (void)protoMethod OBJC_DIRECT; // expected-error {{'objc_direct' attribute cannot be applied to methods declared in an Objective-C protocol}}
@end
#endif

C *c;

void f() {
[c testMethod:1 bar:1.0];
}