From 5fc2525e800424b124b854fc953ae8de838ccb10 Mon Sep 17 00:00:00 2001 From: silvanshade Date: Sun, 5 Feb 2023 08:06:27 -0700 Subject: [PATCH 1/2] Fix errors in test-assembly --- Cargo.lock | 7 - .../crates/test_out_parameters/Cargo.toml | 25 - .../expected/apple-aarch64.s | 246 -------- .../expected/apple-armv7.s | 227 -------- .../expected/apple-armv7s.s | 235 -------- .../test_out_parameters/expected/apple-x86.s | 386 ------------ .../expected/apple-x86_64.s | 287 --------- .../expected/gnustep-x86.s | 551 ------------------ .../expected/gnustep-x86_64.s | 416 ------------- .../crates/test_out_parameters/lib.rs | 87 --- 10 files changed, 2467 deletions(-) delete mode 100644 crates/test-assembly/crates/test_out_parameters/Cargo.toml delete mode 100644 crates/test-assembly/crates/test_out_parameters/expected/apple-aarch64.s delete mode 100644 crates/test-assembly/crates/test_out_parameters/expected/apple-armv7.s delete mode 100644 crates/test-assembly/crates/test_out_parameters/expected/apple-armv7s.s delete mode 100644 crates/test-assembly/crates/test_out_parameters/expected/apple-x86.s delete mode 100644 crates/test-assembly/crates/test_out_parameters/expected/apple-x86_64.s delete mode 100644 crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86.s delete mode 100644 crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86_64.s delete mode 100644 crates/test-assembly/crates/test_out_parameters/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 10e994a48..1822c957f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -474,13 +474,6 @@ dependencies = [ "icrate", ] -[[package]] -name = "test_out_parameters" -version = "0.1.0" -dependencies = [ - "objc2", -] - [[package]] name = "test_retain_autoreleased" version = "0.1.0" diff --git a/crates/test-assembly/crates/test_out_parameters/Cargo.toml b/crates/test-assembly/crates/test_out_parameters/Cargo.toml deleted file mode 100644 index 73dda7dcb..000000000 --- a/crates/test-assembly/crates/test_out_parameters/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "test_out_parameters" -version = "0.1.0" -edition = "2021" -publish = false - -[lib] -path = "lib.rs" - -[dependencies] -objc2 = { path = "../../../objc2", default-features = false } - -[features] -default = ["apple", "std"] -std = ["objc2/std"] -# Runtime -apple = ["objc2/apple"] -gnustep-1-7 = ["objc2/gnustep-1-7"] -gnustep-1-8 = ["gnustep-1-7", "objc2/gnustep-1-8"] -gnustep-1-9 = ["gnustep-1-8", "objc2/gnustep-1-9"] -gnustep-2-0 = ["gnustep-1-9", "objc2/gnustep-2-0"] -gnustep-2-1 = ["gnustep-2-0", "objc2/gnustep-2-1"] - -# Hack -assembly-features = [] diff --git a/crates/test-assembly/crates/test_out_parameters/expected/apple-aarch64.s b/crates/test-assembly/crates/test_out_parameters/expected/apple-aarch64.s deleted file mode 100644 index 0b77cf062..000000000 --- a/crates/test-assembly/crates/test_out_parameters/expected/apple-aarch64.s +++ /dev/null @@ -1,246 +0,0 @@ - .section __TEXT,__text,regular,pure_instructions - .globl _nonnull_nonnull - .p2align 2 -_nonnull_nonnull: - stp x22, x21, [sp, #-48]! - stp x20, x19, [sp, #16] - stp x29, x30, [sp, #32] - add x29, sp, #32 - mov x19, x2 - ldr x20, [x2] - bl _objc_msgSend - mov x21, x0 - ldr x0, [x19] - bl _objc_retain - mov x0, x20 - bl _objc_release - mov x0, x21 - ldp x29, x30, [sp, #32] - ldp x20, x19, [sp, #16] - ldp x22, x21, [sp], #48 - ret - - .globl _null_nonnull - .p2align 2 -_null_nonnull: - cbz x2, LBB1_2 - stp x22, x21, [sp, #-48]! - stp x20, x19, [sp, #16] - stp x29, x30, [sp, #32] - add x29, sp, #32 - mov x19, x2 - ldr x20, [x2] - bl _objc_msgSend - mov x21, x0 - ldr x0, [x19] - bl _objc_retain - mov x0, x20 - bl _objc_release - mov x0, x21 - ldp x29, x30, [sp, #32] - ldp x20, x19, [sp, #16] - ldp x22, x21, [sp], #48 - ret -LBB1_2: - b _objc_msgSend - - .globl _nonnull_null - .p2align 2 -_nonnull_null: - stp x22, x21, [sp, #-48]! - stp x20, x19, [sp, #16] - stp x29, x30, [sp, #32] - add x29, sp, #32 - mov x21, x2 - ldr x19, [x2] - bl _objc_msgSend - mov x20, x0 - ldr x0, [x21] - bl _objc_retain - cbz x19, LBB2_2 - mov x0, x19 - bl _objc_release -LBB2_2: - mov x0, x20 - ldp x29, x30, [sp, #32] - ldp x20, x19, [sp, #16] - ldp x22, x21, [sp], #48 - ret - - .globl _null_null - .p2align 2 -_null_null: - cbz x2, LBB3_4 - stp x22, x21, [sp, #-48]! - stp x20, x19, [sp, #16] - stp x29, x30, [sp, #32] - add x29, sp, #32 - mov x21, x2 - ldr x19, [x2] - bl _objc_msgSend - mov x20, x0 - ldr x0, [x21] - bl _objc_retain - cbz x19, LBB3_3 - mov x0, x19 - bl _objc_release -LBB3_3: - mov x0, x20 - ldp x29, x30, [sp, #32] - ldp x20, x19, [sp, #16] - ldp x22, x21, [sp], #48 - ret -LBB3_4: - b _objc_msgSend - - .globl _two_nonnull_nonnull - .p2align 2 -_two_nonnull_nonnull: - stp x24, x23, [sp, #-64]! - stp x22, x21, [sp, #16] - stp x20, x19, [sp, #32] - stp x29, x30, [sp, #48] - add x29, sp, #48 - mov x19, x3 - mov x20, x2 - ldr x21, [x2] - ldr x22, [x3] - bl _objc_msgSend - mov x23, x0 - ldr x0, [x20] - bl _objc_retain - mov x0, x21 - bl _objc_release - ldr x0, [x19] - bl _objc_retain - mov x0, x22 - bl _objc_release - mov x0, x23 - ldp x29, x30, [sp, #48] - ldp x20, x19, [sp, #32] - ldp x22, x21, [sp, #16] - ldp x24, x23, [sp], #64 - ret - - .globl _call_with_none1 - .p2align 2 -_call_with_none1: - mov x2, #0 - b _objc_msgSend - - .globl _call_with_none2 - .p2align 2 -_call_with_none2: - mov x2, #0 - b _objc_msgSend - - .globl _call_with_none3 - .p2align 2 -_call_with_none3: - sub sp, sp, #48 - stp x20, x19, [sp, #16] - stp x29, x30, [sp, #32] - add x29, sp, #32 - str xzr, [sp, #8] - add x2, sp, #8 - bl _objc_msgSend - mov x19, x0 - ldr x0, [sp, #8] - bl _objc_retain - ldr x1, [sp, #8] - mov x0, x19 - ldp x29, x30, [sp, #32] - ldp x20, x19, [sp, #16] - add sp, sp, #48 - ret - - .globl _call_with_none4 - .p2align 2 -_call_with_none4: - sub sp, sp, #48 - stp x20, x19, [sp, #16] - stp x29, x30, [sp, #32] - add x29, sp, #32 - str xzr, [sp, #8] - add x2, sp, #8 - bl _objc_msgSend - mov x19, x0 - ldr x0, [sp, #8] - bl _objc_retain - ldr x1, [sp, #8] - mov x0, x19 - ldp x29, x30, [sp, #32] - ldp x20, x19, [sp, #16] - add sp, sp, #48 - ret - - .globl _call_with_some1 - .p2align 2 -_call_with_some1: - sub sp, sp, #48 - stp x20, x19, [sp, #16] - stp x29, x30, [sp, #32] - add x29, sp, #32 - mov x19, x2 - str x2, [sp, #8] - add x2, sp, #8 - bl _objc_msgSend - mov x20, x0 - ldr x0, [sp, #8] - bl _objc_retain - mov x0, x19 - bl _objc_release - ldr x1, [sp, #8] - mov x0, x20 - ldp x29, x30, [sp, #32] - ldp x20, x19, [sp, #16] - add sp, sp, #48 - ret - - .globl _call_with_some2 - .p2align 2 -_call_with_some2: - sub sp, sp, #48 - stp x20, x19, [sp, #16] - stp x29, x30, [sp, #32] - add x29, sp, #32 - mov x19, x2 - str x2, [sp, #8] - add x2, sp, #8 - bl _objc_msgSend - mov x20, x0 - ldr x0, [sp, #8] - bl _objc_retain - mov x0, x19 - bl _objc_release - ldr x1, [sp, #8] - mov x0, x20 - ldp x29, x30, [sp, #32] - ldp x20, x19, [sp, #16] - add sp, sp, #48 - ret - - .globl _call_with_some3 - .p2align 2 -_call_with_some3: - sub sp, sp, #48 - stp x20, x19, [sp, #16] - stp x29, x30, [sp, #32] - add x29, sp, #32 - mov x19, x2 - str x2, [sp, #8] - add x2, sp, #8 - bl _objc_msgSend - mov x20, x0 - ldr x0, [sp, #8] - bl _objc_retain - mov x0, x19 - bl _objc_release - ldr x1, [sp, #8] - mov x0, x20 - ldp x29, x30, [sp, #32] - ldp x20, x19, [sp, #16] - add sp, sp, #48 - ret - -.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_out_parameters/expected/apple-armv7.s b/crates/test-assembly/crates/test_out_parameters/expected/apple-armv7.s deleted file mode 100644 index 4388893c3..000000000 --- a/crates/test-assembly/crates/test_out_parameters/expected/apple-armv7.s +++ /dev/null @@ -1,227 +0,0 @@ - .section __TEXT,__text,regular,pure_instructions - .syntax unified - .globl _nonnull_nonnull - .p2align 2 - .code 32 -_nonnull_nonnull: - push {r4, r5, r6, r7, lr} - add r7, sp, #12 - mov r4, r2 - ldr r5, [r2] - bl _objc_msgSend - mov r6, r0 - ldr r0, [r4] - bl _objc_retain - mov r0, r5 - bl _objc_release - mov r0, r6 - pop {r4, r5, r6, r7, pc} - - .globl _null_nonnull - .p2align 2 - .code 32 -_null_nonnull: - cmp r2, #0 - beq LBB1_2 - push {r4, r5, r6, r7, lr} - add r7, sp, #12 - mov r4, r2 - ldr r5, [r2] - bl _objc_msgSend - mov r6, r0 - ldr r0, [r4] - bl _objc_retain - mov r0, r5 - bl _objc_release - mov r0, r6 - pop {r4, r5, r6, r7, pc} -LBB1_2: - mov r2, #0 - b _objc_msgSend - - .globl _nonnull_null - .p2align 2 - .code 32 -_nonnull_null: - push {r4, r5, r6, r7, lr} - add r7, sp, #12 - mov r6, r2 - ldr r4, [r2] - bl _objc_msgSend - mov r5, r0 - ldr r0, [r6] - bl _objc_retain - cmp r4, #0 - beq LBB2_2 - mov r0, r4 - bl _objc_release -LBB2_2: - mov r0, r5 - pop {r4, r5, r6, r7, pc} - - .globl _null_null - .p2align 2 - .code 32 -_null_null: - cmp r2, #0 - beq LBB3_4 - push {r4, r5, r6, r7, lr} - add r7, sp, #12 - mov r6, r2 - ldr r4, [r2] - bl _objc_msgSend - mov r5, r0 - ldr r0, [r6] - bl _objc_retain - cmp r4, #0 - beq LBB3_3 - mov r0, r4 - bl _objc_release -LBB3_3: - mov r0, r5 - pop {r4, r5, r6, r7, pc} -LBB3_4: - mov r2, #0 - b _objc_msgSend - - .globl _two_nonnull_nonnull - .p2align 2 - .code 32 -_two_nonnull_nonnull: - push {r4, r5, r6, r7, lr} - add r7, sp, #12 - push {r8, r10} - mov r4, r3 - mov r5, r2 - ldr r8, [r3] - ldr r6, [r2] - bl _objc_msgSend - mov r10, r0 - ldr r0, [r5] - bl _objc_retain - mov r0, r6 - bl _objc_release - ldr r0, [r4] - bl _objc_retain - mov r0, r8 - bl _objc_release - mov r0, r10 - pop {r8, r10} - pop {r4, r5, r6, r7, pc} - - .globl _call_with_none1 - .p2align 2 - .code 32 -_call_with_none1: - mov r2, #0 - b _objc_msgSend - - .globl _call_with_none2 - .p2align 2 - .code 32 -_call_with_none2: - mov r2, #0 - b _objc_msgSend - - .globl _call_with_none3 - .p2align 2 - .code 32 -_call_with_none3: - push {r4, r7, lr} - add r7, sp, #4 - sub sp, sp, #4 - mov r2, #0 - str r2, [sp] - mov r2, sp - bl _objc_msgSend - mov r4, r0 - ldr r0, [sp] - bl _objc_retain - ldr r1, [sp] - mov r0, r4 - sub sp, r7, #4 - pop {r4, r7, pc} - - .globl _call_with_none4 - .p2align 2 - .code 32 -_call_with_none4: - push {r4, r7, lr} - add r7, sp, #4 - sub sp, sp, #4 - mov r2, #0 - str r2, [sp] - mov r2, sp - bl _objc_msgSend - mov r4, r0 - ldr r0, [sp] - bl _objc_retain - ldr r1, [sp] - mov r0, r4 - sub sp, r7, #4 - pop {r4, r7, pc} - - .globl _call_with_some1 - .p2align 2 - .code 32 -_call_with_some1: - push {r4, r5, r7, lr} - add r7, sp, #8 - sub sp, sp, #4 - mov r4, r2 - str r2, [sp] - mov r2, sp - bl _objc_msgSend - mov r5, r0 - ldr r0, [sp] - bl _objc_retain - mov r0, r4 - bl _objc_release - ldr r1, [sp] - mov r0, r5 - sub sp, r7, #8 - pop {r4, r5, r7, pc} - - .globl _call_with_some2 - .p2align 2 - .code 32 -_call_with_some2: - push {r4, r5, r7, lr} - add r7, sp, #8 - sub sp, sp, #4 - mov r4, r2 - str r2, [sp] - mov r2, sp - bl _objc_msgSend - mov r5, r0 - ldr r0, [sp] - bl _objc_retain - mov r0, r4 - bl _objc_release - ldr r1, [sp] - mov r0, r5 - sub sp, r7, #8 - pop {r4, r5, r7, pc} - - .globl _call_with_some3 - .p2align 2 - .code 32 -_call_with_some3: - push {r4, r5, r7, lr} - add r7, sp, #8 - sub sp, sp, #4 - mov r4, r2 - str r2, [sp] - mov r2, sp - bl _objc_msgSend - mov r5, r0 - ldr r0, [sp] - bl _objc_retain - mov r0, r4 - bl _objc_release - ldr r1, [sp] - mov r0, r5 - sub sp, r7, #8 - pop {r4, r5, r7, pc} - -.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_out_parameters/expected/apple-armv7s.s b/crates/test-assembly/crates/test_out_parameters/expected/apple-armv7s.s deleted file mode 100644 index 684e06419..000000000 --- a/crates/test-assembly/crates/test_out_parameters/expected/apple-armv7s.s +++ /dev/null @@ -1,235 +0,0 @@ - .section __TEXT,__text,regular,pure_instructions - .syntax unified - .globl _nonnull_nonnull - .p2align 2 - .code 32 -_nonnull_nonnull: - push {r4, r5, r6, r7, lr} - add r7, sp, #12 - mov r4, r2 - ldr r5, [r2] - bl _objc_msgSend - mov r6, r0 - ldr r0, [r4] - bl _objc_retain - mov r0, r5 - bl _objc_release - mov r0, r6 - pop {r4, r5, r6, r7, pc} - - .globl _null_nonnull - .p2align 2 - .code 32 -_null_nonnull: - push {r4, r5, r6, r7, lr} - add r7, sp, #12 - cmp r2, #0 - beq LBB1_2 - mov r5, r2 - ldr r6, [r2] - bl _objc_msgSend - mov r4, r0 - ldr r0, [r5] - bl _objc_retain - mov r0, r6 - bl _objc_release - mov r0, r4 - pop {r4, r5, r6, r7, pc} -LBB1_2: - mov r2, #0 - bl _objc_msgSend - pop {r4, r5, r6, r7, pc} - - .globl _nonnull_null - .p2align 2 - .code 32 -_nonnull_null: - push {r4, r5, r6, r7, lr} - add r7, sp, #12 - mov r6, r2 - ldr r4, [r2] - bl _objc_msgSend - mov r5, r0 - ldr r0, [r6] - bl _objc_retain - cmp r4, #0 - beq LBB2_2 - mov r0, r4 - bl _objc_release -LBB2_2: - mov r0, r5 - pop {r4, r5, r6, r7, pc} - - .globl _null_null - .p2align 2 - .code 32 -_null_null: - push {r4, r5, r6, r7, lr} - add r7, sp, #12 - cmp r2, #0 - beq LBB3_4 - mov r6, r2 - ldr r5, [r2] - bl _objc_msgSend - mov r4, r0 - ldr r0, [r6] - bl _objc_retain - cmp r5, #0 - beq LBB3_3 - mov r0, r5 - bl _objc_release -LBB3_3: - mov r0, r4 - pop {r4, r5, r6, r7, pc} -LBB3_4: - mov r2, #0 - bl _objc_msgSend - pop {r4, r5, r6, r7, pc} - - .globl _two_nonnull_nonnull - .p2align 2 - .code 32 -_two_nonnull_nonnull: - push {r4, r5, r6, r7, lr} - add r7, sp, #12 - push {r8, r10} - mov r4, r3 - mov r5, r2 - ldr r8, [r3] - ldr r6, [r2] - bl _objc_msgSend - mov r10, r0 - ldr r0, [r5] - bl _objc_retain - mov r0, r6 - bl _objc_release - ldr r0, [r4] - bl _objc_retain - mov r0, r8 - bl _objc_release - mov r0, r10 - pop {r8, r10} - pop {r4, r5, r6, r7, pc} - - .globl _call_with_none1 - .p2align 2 - .code 32 -_call_with_none1: - push {r7, lr} - mov r7, sp - mov r2, #0 - bl _objc_msgSend - pop {r7, pc} - - .globl _call_with_none2 - .p2align 2 - .code 32 -_call_with_none2: - push {r7, lr} - mov r7, sp - mov r2, #0 - bl _objc_msgSend - pop {r7, pc} - - .globl _call_with_none3 - .p2align 2 - .code 32 -_call_with_none3: - push {r4, r7, lr} - add r7, sp, #4 - sub sp, sp, #4 - mov r2, #0 - str r2, [sp] - mov r2, sp - bl _objc_msgSend - mov r4, r0 - ldr r0, [sp] - bl _objc_retain - ldr r1, [sp] - mov r0, r4 - sub sp, r7, #4 - pop {r4, r7, pc} - - .globl _call_with_none4 - .p2align 2 - .code 32 -_call_with_none4: - push {r4, r7, lr} - add r7, sp, #4 - sub sp, sp, #4 - mov r2, #0 - str r2, [sp] - mov r2, sp - bl _objc_msgSend - mov r4, r0 - ldr r0, [sp] - bl _objc_retain - ldr r1, [sp] - mov r0, r4 - sub sp, r7, #4 - pop {r4, r7, pc} - - .globl _call_with_some1 - .p2align 2 - .code 32 -_call_with_some1: - push {r4, r5, r7, lr} - add r7, sp, #8 - sub sp, sp, #4 - mov r4, r2 - str r2, [sp] - mov r2, sp - bl _objc_msgSend - mov r5, r0 - ldr r0, [sp] - bl _objc_retain - mov r0, r4 - bl _objc_release - ldr r1, [sp] - mov r0, r5 - sub sp, r7, #8 - pop {r4, r5, r7, pc} - - .globl _call_with_some2 - .p2align 2 - .code 32 -_call_with_some2: - push {r4, r5, r7, lr} - add r7, sp, #8 - sub sp, sp, #4 - mov r4, r2 - str r2, [sp] - mov r2, sp - bl _objc_msgSend - mov r5, r0 - ldr r0, [sp] - bl _objc_retain - mov r0, r4 - bl _objc_release - ldr r1, [sp] - mov r0, r5 - sub sp, r7, #8 - pop {r4, r5, r7, pc} - - .globl _call_with_some3 - .p2align 2 - .code 32 -_call_with_some3: - push {r4, r5, r7, lr} - add r7, sp, #8 - sub sp, sp, #4 - mov r4, r2 - str r2, [sp] - mov r2, sp - bl _objc_msgSend - mov r5, r0 - ldr r0, [sp] - bl _objc_retain - mov r0, r4 - bl _objc_release - ldr r1, [sp] - mov r0, r5 - sub sp, r7, #8 - pop {r4, r5, r7, pc} - -.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_out_parameters/expected/apple-x86.s b/crates/test-assembly/crates/test_out_parameters/expected/apple-x86.s deleted file mode 100644 index 5b060aa7a..000000000 --- a/crates/test-assembly/crates/test_out_parameters/expected/apple-x86.s +++ /dev/null @@ -1,386 +0,0 @@ - .section __TEXT,__text,regular,pure_instructions - .intel_syntax noprefix - .globl _nonnull_nonnull - .p2align 4, 0x90 -_nonnull_nonnull: - push ebp - mov ebp, esp - push ebx - push edi - push esi - sub esp, 12 - mov eax, dword ptr [ebp + 8] - mov ecx, dword ptr [ebp + 12] - mov ebx, dword ptr [ebp + 16] - mov edi, dword ptr [ebx] - mov dword ptr [esp + 8], ebx - mov dword ptr [esp + 4], ecx - mov dword ptr [esp], eax - call _objc_msgSend - mov esi, eax - mov eax, dword ptr [ebx] - mov dword ptr [esp], eax - call _objc_retain - mov dword ptr [esp], edi - call _objc_release - mov eax, esi - add esp, 12 - pop esi - pop edi - pop ebx - pop ebp - ret - - .globl _null_nonnull - .p2align 4, 0x90 -_null_nonnull: - push ebp - mov ebp, esp - push ebx - push edi - push esi - sub esp, 12 - mov edi, dword ptr [ebp + 16] - mov ecx, dword ptr [ebp + 12] - mov eax, dword ptr [ebp + 8] - test edi, edi - je LBB1_1 - mov ebx, dword ptr [edi] - sub esp, 4 - push edi - push ecx - push eax - call _objc_msgSend - add esp, 16 - mov esi, eax - sub esp, 12 - push dword ptr [edi] - call _objc_retain - add esp, 4 - push ebx - call _objc_release - add esp, 16 - mov eax, esi - add esp, 12 - jmp LBB1_2 -LBB1_1: - sub esp, 4 - push 0 - push ecx - push eax - call _objc_msgSend - add esp, 28 -LBB1_2: - pop esi - pop edi - pop ebx - pop ebp - ret - - .globl _nonnull_null - .p2align 4, 0x90 -_nonnull_null: - push ebp - mov ebp, esp - push ebx - push edi - push esi - sub esp, 12 - mov eax, dword ptr [ebp + 8] - mov ecx, dword ptr [ebp + 12] - mov ebx, dword ptr [ebp + 16] - mov edi, dword ptr [ebx] - mov dword ptr [esp + 8], ebx - mov dword ptr [esp + 4], ecx - mov dword ptr [esp], eax - call _objc_msgSend - mov esi, eax - mov eax, dword ptr [ebx] - mov dword ptr [esp], eax - call _objc_retain - test edi, edi - je LBB2_2 - mov dword ptr [esp], edi - call _objc_release -LBB2_2: - mov eax, esi - add esp, 12 - pop esi - pop edi - pop ebx - pop ebp - ret - - .globl _null_null - .p2align 4, 0x90 -_null_null: - push ebp - mov ebp, esp - push ebx - push edi - push esi - sub esp, 12 - mov ebx, dword ptr [ebp + 16] - mov ecx, dword ptr [ebp + 12] - mov eax, dword ptr [ebp + 8] - test ebx, ebx - je LBB3_1 - mov edi, dword ptr [ebx] - sub esp, 4 - push ebx - push ecx - push eax - call _objc_msgSend - add esp, 16 - mov esi, eax - sub esp, 12 - push dword ptr [ebx] - call _objc_retain - add esp, 16 - test edi, edi - je LBB3_4 - sub esp, 12 - push edi - call _objc_release - add esp, 16 -LBB3_4: - mov eax, esi - add esp, 12 - jmp LBB3_5 -LBB3_1: - sub esp, 4 - push 0 - push ecx - push eax - call _objc_msgSend - add esp, 28 -LBB3_5: - pop esi - pop edi - pop ebx - pop ebp - ret - - .globl _two_nonnull_nonnull - .p2align 4, 0x90 -_two_nonnull_nonnull: - push ebp - mov ebp, esp - push ebx - push edi - push esi - sub esp, 28 - mov eax, dword ptr [ebp + 8] - mov ecx, dword ptr [ebp + 12] - mov esi, dword ptr [ebp + 20] - mov ebx, dword ptr [ebp + 16] - mov edi, dword ptr [ebx] - mov edx, dword ptr [esi] - mov dword ptr [ebp - 16], edx - mov dword ptr [esp + 12], esi - mov dword ptr [esp + 8], ebx - mov dword ptr [esp + 4], ecx - mov dword ptr [esp], eax - call _objc_msgSend - mov esi, eax - mov eax, dword ptr [ebx] - mov dword ptr [esp], eax - call _objc_retain - mov dword ptr [esp], edi - call _objc_release - mov eax, dword ptr [ebp + 20] - mov eax, dword ptr [eax] - mov dword ptr [esp], eax - call _objc_retain - mov eax, dword ptr [ebp - 16] - mov dword ptr [esp], eax - call _objc_release - mov eax, esi - add esp, 28 - pop esi - pop edi - pop ebx - pop ebp - ret - - .globl _call_with_none1 - .p2align 4, 0x90 -_call_with_none1: - push ebp - mov ebp, esp - sub esp, 8 - sub esp, 4 - push 0 - push dword ptr [ebp + 12] - push dword ptr [ebp + 8] - call _objc_msgSend - add esp, 24 - pop ebp - ret - - .globl _call_with_none2 - .p2align 4, 0x90 -_call_with_none2: - push ebp - mov ebp, esp - sub esp, 8 - sub esp, 4 - push 0 - push dword ptr [ebp + 12] - push dword ptr [ebp + 8] - call _objc_msgSend - add esp, 24 - pop ebp - ret - - .globl _call_with_none3 - .p2align 4, 0x90 -_call_with_none3: - push ebp - mov ebp, esp - push esi - push eax - mov eax, dword ptr [ebp + 8] - mov ecx, dword ptr [ebp + 12] - mov dword ptr [ebp - 8], 0 - sub esp, 4 - lea edx, [ebp - 8] - push edx - push ecx - push eax - call _objc_msgSend - add esp, 16 - mov esi, eax - sub esp, 12 - push dword ptr [ebp - 8] - call _objc_retain - add esp, 16 - mov edx, dword ptr [ebp - 8] - mov eax, esi - add esp, 4 - pop esi - pop ebp - ret - - .globl _call_with_none4 - .p2align 4, 0x90 -_call_with_none4: - push ebp - mov ebp, esp - push esi - push eax - mov eax, dword ptr [ebp + 8] - mov ecx, dword ptr [ebp + 12] - mov dword ptr [ebp - 8], 0 - sub esp, 4 - lea edx, [ebp - 8] - push edx - push ecx - push eax - call _objc_msgSend - add esp, 16 - mov esi, eax - sub esp, 12 - push dword ptr [ebp - 8] - call _objc_retain - add esp, 16 - mov edx, dword ptr [ebp - 8] - mov eax, esi - add esp, 4 - pop esi - pop ebp - ret - - .globl _call_with_some1 - .p2align 4, 0x90 -_call_with_some1: - push ebp - mov ebp, esp - push edi - push esi - sub esp, 16 - mov edi, dword ptr [ebp + 16] - mov eax, dword ptr [ebp + 8] - mov ecx, dword ptr [ebp + 12] - lea edx, [ebp + 16] - mov dword ptr [esp + 8], edx - mov dword ptr [esp + 4], ecx - mov dword ptr [esp], eax - call _objc_msgSend - mov esi, eax - mov eax, dword ptr [ebp + 16] - mov dword ptr [esp], eax - call _objc_retain - mov dword ptr [esp], edi - call _objc_release - mov edx, dword ptr [ebp + 16] - mov eax, esi - add esp, 16 - pop esi - pop edi - pop ebp - ret - - .globl _call_with_some2 - .p2align 4, 0x90 -_call_with_some2: - push ebp - mov ebp, esp - push edi - push esi - sub esp, 16 - mov eax, dword ptr [ebp + 8] - mov ecx, dword ptr [ebp + 12] - mov edi, dword ptr [ebp + 16] - mov dword ptr [ebp - 12], edi - lea edx, [ebp - 12] - mov dword ptr [esp + 8], edx - mov dword ptr [esp + 4], ecx - mov dword ptr [esp], eax - call _objc_msgSend - mov esi, eax - mov eax, dword ptr [ebp - 12] - mov dword ptr [esp], eax - call _objc_retain - mov dword ptr [esp], edi - call _objc_release - mov edx, dword ptr [ebp - 12] - mov eax, esi - add esp, 16 - pop esi - pop edi - pop ebp - ret - - .globl _call_with_some3 - .p2align 4, 0x90 -_call_with_some3: - push ebp - mov ebp, esp - push edi - push esi - sub esp, 16 - mov eax, dword ptr [ebp + 8] - mov ecx, dword ptr [ebp + 12] - mov edi, dword ptr [ebp + 16] - mov dword ptr [ebp - 12], edi - lea edx, [ebp - 12] - mov dword ptr [esp + 8], edx - mov dword ptr [esp + 4], ecx - mov dword ptr [esp], eax - call _objc_msgSend - mov esi, eax - mov eax, dword ptr [ebp - 12] - mov dword ptr [esp], eax - call _objc_retain - mov dword ptr [esp], edi - call _objc_release - mov edx, dword ptr [ebp - 12] - mov eax, esi - add esp, 16 - pop esi - pop edi - pop ebp - ret - -.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_out_parameters/expected/apple-x86_64.s b/crates/test-assembly/crates/test_out_parameters/expected/apple-x86_64.s deleted file mode 100644 index 11fcf2390..000000000 --- a/crates/test-assembly/crates/test_out_parameters/expected/apple-x86_64.s +++ /dev/null @@ -1,287 +0,0 @@ - .section __TEXT,__text,regular,pure_instructions - .intel_syntax noprefix - .globl _nonnull_nonnull - .p2align 4, 0x90 -_nonnull_nonnull: - push rbp - mov rbp, rsp - push r15 - push r14 - push rbx - push rax - mov rbx, rdx - mov r14, qword ptr [rdx] - call _objc_msgSend - mov r15, rax - mov rdi, qword ptr [rbx] - call _objc_retain - mov rdi, r14 - call _objc_release - mov rax, r15 - add rsp, 8 - pop rbx - pop r14 - pop r15 - pop rbp - ret - - .globl _null_nonnull - .p2align 4, 0x90 -_null_nonnull: - test rdx, rdx - je LBB1_2 - push rbp - mov rbp, rsp - push r15 - push r14 - push rbx - push rax - mov rbx, rdx - mov r14, qword ptr [rdx] - call _objc_msgSend - mov r15, rax - mov rdi, qword ptr [rbx] - call _objc_retain - mov rdi, r14 - call _objc_release - mov rax, r15 - add rsp, 8 - pop rbx - pop r14 - pop r15 - pop rbp - ret -LBB1_2: - xor edx, edx - jmp _objc_msgSend - - .globl _nonnull_null - .p2align 4, 0x90 -_nonnull_null: - push rbp - mov rbp, rsp - push r15 - push r14 - push rbx - push rax - mov rbx, rdx - mov r15, qword ptr [rdx] - call _objc_msgSend - mov r14, rax - mov rdi, qword ptr [rbx] - call _objc_retain - test r15, r15 - je LBB2_2 - mov rdi, r15 - call _objc_release -LBB2_2: - mov rax, r14 - add rsp, 8 - pop rbx - pop r14 - pop r15 - pop rbp - ret - - .globl _null_null - .p2align 4, 0x90 -_null_null: - test rdx, rdx - je LBB3_4 - push rbp - mov rbp, rsp - push r15 - push r14 - push rbx - push rax - mov rbx, rdx - mov r15, qword ptr [rdx] - call _objc_msgSend - mov r14, rax - mov rdi, qword ptr [rbx] - call _objc_retain - test r15, r15 - je LBB3_3 - mov rdi, r15 - call _objc_release -LBB3_3: - mov rax, r14 - add rsp, 8 - pop rbx - pop r14 - pop r15 - pop rbp - ret -LBB3_4: - xor edx, edx - jmp _objc_msgSend - - .globl _two_nonnull_nonnull - .p2align 4, 0x90 -_two_nonnull_nonnull: - push rbp - mov rbp, rsp - push r15 - push r14 - push r13 - push r12 - push rbx - push rax - mov r14, rcx - mov rbx, rdx - mov r15, qword ptr [rdx] - mov r12, qword ptr [rcx] - call _objc_msgSend - mov r13, rax - mov rdi, qword ptr [rbx] - call _objc_retain - mov rdi, r15 - call _objc_release - mov rdi, qword ptr [r14] - call _objc_retain - mov rdi, r12 - call _objc_release - mov rax, r13 - add rsp, 8 - pop rbx - pop r12 - pop r13 - pop r14 - pop r15 - pop rbp - ret - - .globl _call_with_none1 - .p2align 4, 0x90 -_call_with_none1: - push rbp - mov rbp, rsp - xor edx, edx - pop rbp - jmp _objc_msgSend - - .globl _call_with_none2 - .p2align 4, 0x90 -_call_with_none2: - push rbp - mov rbp, rsp - xor edx, edx - pop rbp - jmp _objc_msgSend - - .globl _call_with_none3 - .p2align 4, 0x90 -_call_with_none3: - push rbp - mov rbp, rsp - push rbx - push rax - mov qword ptr [rbp - 16], 0 - lea rdx, [rbp - 16] - call _objc_msgSend - mov rbx, rax - mov rdi, qword ptr [rbp - 16] - call _objc_retain - mov rdx, qword ptr [rbp - 16] - mov rax, rbx - add rsp, 8 - pop rbx - pop rbp - ret - - .globl _call_with_none4 - .p2align 4, 0x90 -_call_with_none4: - push rbp - mov rbp, rsp - push rbx - push rax - mov qword ptr [rbp - 16], 0 - lea rdx, [rbp - 16] - call _objc_msgSend - mov rbx, rax - mov rdi, qword ptr [rbp - 16] - call _objc_retain - mov rdx, qword ptr [rbp - 16] - mov rax, rbx - add rsp, 8 - pop rbx - pop rbp - ret - - .globl _call_with_some1 - .p2align 4, 0x90 -_call_with_some1: - push rbp - mov rbp, rsp - push r14 - push rbx - sub rsp, 16 - mov rbx, rdx - mov qword ptr [rbp - 24], rdx - lea rdx, [rbp - 24] - call _objc_msgSend - mov r14, rax - mov rdi, qword ptr [rbp - 24] - call _objc_retain - mov rdi, rbx - call _objc_release - mov rdx, qword ptr [rbp - 24] - mov rax, r14 - add rsp, 16 - pop rbx - pop r14 - pop rbp - ret - - .globl _call_with_some2 - .p2align 4, 0x90 -_call_with_some2: - push rbp - mov rbp, rsp - push r14 - push rbx - sub rsp, 16 - mov rbx, rdx - mov qword ptr [rbp - 24], rdx - lea rdx, [rbp - 24] - call _objc_msgSend - mov r14, rax - mov rdi, qword ptr [rbp - 24] - call _objc_retain - mov rdi, rbx - call _objc_release - mov rdx, qword ptr [rbp - 24] - mov rax, r14 - add rsp, 16 - pop rbx - pop r14 - pop rbp - ret - - .globl _call_with_some3 - .p2align 4, 0x90 -_call_with_some3: - push rbp - mov rbp, rsp - push r14 - push rbx - sub rsp, 16 - mov rbx, rdx - mov qword ptr [rbp - 24], rdx - lea rdx, [rbp - 24] - call _objc_msgSend - mov r14, rax - mov rdi, qword ptr [rbp - 24] - call _objc_retain - mov rdi, rbx - call _objc_release - mov rdx, qword ptr [rbp - 24] - mov rax, r14 - add rsp, 16 - pop rbx - pop r14 - pop rbp - ret - -.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86.s b/crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86.s deleted file mode 100644 index 8444e9cc4..000000000 --- a/crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86.s +++ /dev/null @@ -1,551 +0,0 @@ - .text - .intel_syntax noprefix - .section .text.nonnull_nonnull,"ax",@progbits - .globl nonnull_nonnull - .p2align 4, 0x90 - .type nonnull_nonnull,@function -nonnull_nonnull: - push ebp - push ebx - push edi - push esi - sub esp, 12 - mov eax, dword ptr [esp + 32] - mov esi, dword ptr [esp + 36] - mov edi, dword ptr [esp + 40] - call .L0$pb -.L0$pb: - pop ebx -.Ltmp0: - add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp0-.L0$pb) - mov dword ptr [esp + 4], esi - mov dword ptr [esp], eax - call objc_msg_lookup@PLT - mov ecx, dword ptr [esp + 32] - mov ebp, dword ptr [edi] - mov dword ptr [esp + 8], edi - mov dword ptr [esp + 4], esi - mov dword ptr [esp], ecx - call eax - mov esi, eax - mov eax, dword ptr [edi] - mov dword ptr [esp], eax - call objc_retain@PLT - mov dword ptr [esp], ebp - call objc_release@PLT - mov eax, esi - add esp, 12 - pop esi - pop edi - pop ebx - pop ebp - ret -.Lfunc_end0: - .size nonnull_nonnull, .Lfunc_end0-nonnull_nonnull - - .section .text.null_nonnull,"ax",@progbits - .globl null_nonnull - .p2align 4, 0x90 - .type null_nonnull,@function -null_nonnull: - push ebp - push ebx - push edi - push esi - sub esp, 12 - mov edi, dword ptr [esp + 40] - mov ebp, dword ptr [esp + 36] - mov esi, dword ptr [esp + 32] - call .L1$pb -.L1$pb: - pop ebx -.Ltmp1: - add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp1-.L1$pb) - sub esp, 8 - push ebp - push esi - call objc_msg_lookup@PLT - add esp, 16 - test edi, edi - je .LBB1_1 - mov ecx, dword ptr [edi] - mov dword ptr [esp + 8], ecx - sub esp, 4 - push edi - push ebp - push esi - call eax - add esp, 16 - mov esi, eax - sub esp, 12 - push dword ptr [edi] - call objc_retain@PLT - add esp, 4 - push dword ptr [esp + 20] - call objc_release@PLT - add esp, 16 - mov eax, esi - add esp, 12 - jmp .LBB1_2 -.LBB1_1: - sub esp, 4 - push 0 - push ebp - push esi - call eax - add esp, 28 -.LBB1_2: - pop esi - pop edi - pop ebx - pop ebp - ret -.Lfunc_end1: - .size null_nonnull, .Lfunc_end1-null_nonnull - - .section .text.nonnull_null,"ax",@progbits - .globl nonnull_null - .p2align 4, 0x90 - .type nonnull_null,@function -nonnull_null: - push ebp - push ebx - push edi - push esi - sub esp, 12 - mov eax, dword ptr [esp + 32] - mov esi, dword ptr [esp + 36] - mov ebp, dword ptr [esp + 40] - call .L2$pb -.L2$pb: - pop ebx -.Ltmp2: - add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp2-.L2$pb) - mov dword ptr [esp + 4], esi - mov dword ptr [esp], eax - call objc_msg_lookup@PLT - mov ecx, dword ptr [esp + 32] - mov edi, dword ptr [ebp] - mov dword ptr [esp + 8], ebp - mov dword ptr [esp + 4], esi - mov dword ptr [esp], ecx - call eax - mov esi, eax - mov eax, dword ptr [ebp] - mov dword ptr [esp], eax - call objc_retain@PLT - test edi, edi - je .LBB2_2 - mov dword ptr [esp], edi - call objc_release@PLT -.LBB2_2: - mov eax, esi - add esp, 12 - pop esi - pop edi - pop ebx - pop ebp - ret -.Lfunc_end2: - .size nonnull_null, .Lfunc_end2-nonnull_null - - .section .text.null_null,"ax",@progbits - .globl null_null - .p2align 4, 0x90 - .type null_null,@function -null_null: - push ebp - push ebx - push edi - push esi - sub esp, 12 - mov edi, dword ptr [esp + 40] - mov ebp, dword ptr [esp + 36] - mov esi, dword ptr [esp + 32] - call .L3$pb -.L3$pb: - pop ebx -.Ltmp3: - add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp3-.L3$pb) - sub esp, 8 - push ebp - push esi - call objc_msg_lookup@PLT - add esp, 16 - test edi, edi - je .LBB3_1 - mov ecx, esi - mov esi, dword ptr [edi] - sub esp, 4 - push edi - push ebp - push ecx - call eax - add esp, 16 - mov ebp, eax - sub esp, 12 - push dword ptr [edi] - call objc_retain@PLT - add esp, 16 - test esi, esi - je .LBB3_4 - sub esp, 12 - push esi - call objc_release@PLT - add esp, 16 -.LBB3_4: - mov eax, ebp - add esp, 12 - jmp .LBB3_5 -.LBB3_1: - sub esp, 4 - push 0 - push ebp - push esi - call eax - add esp, 28 -.LBB3_5: - pop esi - pop edi - pop ebx - pop ebp - ret -.Lfunc_end3: - .size null_null, .Lfunc_end3-null_null - - .section .text.two_nonnull_nonnull,"ax",@progbits - .globl two_nonnull_nonnull - .p2align 4, 0x90 - .type two_nonnull_nonnull,@function -two_nonnull_nonnull: - push ebp - push ebx - push edi - push esi - sub esp, 28 - mov eax, dword ptr [esp + 48] - mov esi, dword ptr [esp + 52] - mov edi, dword ptr [esp + 56] - call .L4$pb -.L4$pb: - pop ebx -.Ltmp4: - add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp4-.L4$pb) - mov dword ptr [esp + 4], esi - mov dword ptr [esp], eax - call objc_msg_lookup@PLT - mov ecx, dword ptr [esp + 60] - mov ebp, dword ptr [edi] - mov dword ptr [esp + 8], edi - mov dword ptr [esp + 4], esi - mov edx, dword ptr [ecx] - mov dword ptr [esp + 12], ecx - mov ecx, dword ptr [esp + 48] - mov dword ptr [esp + 24], edx - mov dword ptr [esp], ecx - call eax - mov esi, eax - mov eax, dword ptr [edi] - mov dword ptr [esp], eax - call objc_retain@PLT - mov dword ptr [esp], ebp - call objc_release@PLT - mov eax, dword ptr [esp + 60] - mov eax, dword ptr [eax] - mov dword ptr [esp], eax - call objc_retain@PLT - mov eax, dword ptr [esp + 24] - mov dword ptr [esp], eax - call objc_release@PLT - mov eax, esi - add esp, 28 - pop esi - pop edi - pop ebx - pop ebp - ret -.Lfunc_end4: - .size two_nonnull_nonnull, .Lfunc_end4-two_nonnull_nonnull - - .section .text.call_with_none1,"ax",@progbits - .globl call_with_none1 - .p2align 4, 0x90 - .type call_with_none1,@function -call_with_none1: - push ebx - push edi - push esi - mov esi, dword ptr [esp + 16] - mov edi, dword ptr [esp + 20] - call .L5$pb -.L5$pb: - pop ebx -.Ltmp5: - add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp5-.L5$pb) - sub esp, 8 - push edi - push esi - call objc_msg_lookup@PLT - add esp, 12 - push 0 - push edi - push esi - call eax - add esp, 16 - pop esi - pop edi - pop ebx - ret -.Lfunc_end5: - .size call_with_none1, .Lfunc_end5-call_with_none1 - - .section .text.call_with_none2,"ax",@progbits - .globl call_with_none2 - .p2align 4, 0x90 - .type call_with_none2,@function -call_with_none2: - push ebx - push edi - push esi - mov esi, dword ptr [esp + 16] - mov edi, dword ptr [esp + 20] - call .L6$pb -.L6$pb: - pop ebx -.Ltmp6: - add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp6-.L6$pb) - sub esp, 8 - push edi - push esi - call objc_msg_lookup@PLT - add esp, 12 - push 0 - push edi - push esi - call eax - add esp, 16 - pop esi - pop edi - pop ebx - ret -.Lfunc_end6: - .size call_with_none2, .Lfunc_end6-call_with_none2 - - .section .text.call_with_none3,"ax",@progbits - .globl call_with_none3 - .p2align 4, 0x90 - .type call_with_none3,@function -call_with_none3: - push ebx - push edi - push esi - sub esp, 16 - mov esi, dword ptr [esp + 32] - mov edi, dword ptr [esp + 36] - call .L7$pb -.L7$pb: - pop ebx - mov dword ptr [esp + 12], 0 -.Ltmp7: - add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp7-.L7$pb) - sub esp, 8 - push edi - push esi - call objc_msg_lookup@PLT - add esp, 12 - lea ecx, [esp + 16] - push ecx - push edi - push esi - call eax - add esp, 16 - mov esi, eax - sub esp, 12 - push dword ptr [esp + 24] - call objc_retain@PLT - add esp, 16 - mov edx, dword ptr [esp + 12] - mov eax, esi - add esp, 16 - pop esi - pop edi - pop ebx - ret -.Lfunc_end7: - .size call_with_none3, .Lfunc_end7-call_with_none3 - - .section .text.call_with_none4,"ax",@progbits - .globl call_with_none4 - .p2align 4, 0x90 - .type call_with_none4,@function -call_with_none4: - push ebx - push edi - push esi - sub esp, 16 - mov esi, dword ptr [esp + 32] - mov edi, dword ptr [esp + 36] - call .L8$pb -.L8$pb: - pop ebx - mov dword ptr [esp + 12], 0 -.Ltmp8: - add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp8-.L8$pb) - sub esp, 8 - push edi - push esi - call objc_msg_lookup@PLT - add esp, 12 - lea ecx, [esp + 16] - push ecx - push edi - push esi - call eax - add esp, 16 - mov esi, eax - sub esp, 12 - push dword ptr [esp + 24] - call objc_retain@PLT - add esp, 16 - mov edx, dword ptr [esp + 12] - mov eax, esi - add esp, 16 - pop esi - pop edi - pop ebx - ret -.Lfunc_end8: - .size call_with_none4, .Lfunc_end8-call_with_none4 - - .section .text.call_with_some1,"ax",@progbits - .globl call_with_some1 - .p2align 4, 0x90 - .type call_with_some1,@function -call_with_some1: - push ebp - push ebx - push edi - push esi - sub esp, 12 - mov esi, dword ptr [esp + 32] - mov ebp, dword ptr [esp + 36] - mov edi, dword ptr [esp + 40] - call .L9$pb -.L9$pb: - pop ebx -.Ltmp9: - add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp9-.L9$pb) - mov dword ptr [esp + 4], ebp - mov dword ptr [esp], esi - call objc_msg_lookup@PLT - lea ecx, [esp + 40] - mov dword ptr [esp + 4], ebp - mov dword ptr [esp], esi - mov dword ptr [esp + 8], ecx - call eax - mov esi, eax - mov eax, dword ptr [esp + 40] - mov dword ptr [esp], eax - call objc_retain@PLT - mov dword ptr [esp], edi - call objc_release@PLT - mov edx, dword ptr [esp + 40] - mov eax, esi - add esp, 12 - pop esi - pop edi - pop ebx - pop ebp - ret -.Lfunc_end9: - .size call_with_some1, .Lfunc_end9-call_with_some1 - - .section .text.call_with_some2,"ax",@progbits - .globl call_with_some2 - .p2align 4, 0x90 - .type call_with_some2,@function -call_with_some2: - push ebp - push ebx - push edi - push esi - sub esp, 28 - mov esi, dword ptr [esp + 48] - mov ebp, dword ptr [esp + 52] - mov edi, dword ptr [esp + 56] - call .L10$pb -.L10$pb: - pop ebx -.Ltmp10: - add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp10-.L10$pb) - mov dword ptr [esp + 24], edi - mov dword ptr [esp + 4], ebp - mov dword ptr [esp], esi - call objc_msg_lookup@PLT - lea ecx, [esp + 24] - mov dword ptr [esp + 4], ebp - mov dword ptr [esp], esi - mov dword ptr [esp + 8], ecx - call eax - mov esi, eax - mov eax, dword ptr [esp + 24] - mov dword ptr [esp], eax - call objc_retain@PLT - mov dword ptr [esp], edi - call objc_release@PLT - mov edx, dword ptr [esp + 24] - mov eax, esi - add esp, 28 - pop esi - pop edi - pop ebx - pop ebp - ret -.Lfunc_end10: - .size call_with_some2, .Lfunc_end10-call_with_some2 - - .section .text.call_with_some3,"ax",@progbits - .globl call_with_some3 - .p2align 4, 0x90 - .type call_with_some3,@function -call_with_some3: - push ebp - push ebx - push edi - push esi - sub esp, 28 - mov esi, dword ptr [esp + 48] - mov ebp, dword ptr [esp + 52] - mov edi, dword ptr [esp + 56] - call .L11$pb -.L11$pb: - pop ebx -.Ltmp11: - add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp11-.L11$pb) - mov dword ptr [esp + 24], edi - mov dword ptr [esp + 4], ebp - mov dword ptr [esp], esi - call objc_msg_lookup@PLT - lea ecx, [esp + 24] - mov dword ptr [esp + 4], ebp - mov dword ptr [esp], esi - mov dword ptr [esp + 8], ecx - call eax - mov esi, eax - mov eax, dword ptr [esp + 24] - mov dword ptr [esp], eax - call objc_retain@PLT - mov dword ptr [esp], edi - call objc_release@PLT - mov edx, dword ptr [esp + 24] - mov eax, esi - add esp, 28 - pop esi - pop edi - pop ebx - pop ebp - ret -.Lfunc_end11: - .size call_with_some3, .Lfunc_end11-call_with_some3 - - .section ".note.GNU-stack","",@progbits diff --git a/crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86_64.s b/crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86_64.s deleted file mode 100644 index 7a11089cb..000000000 --- a/crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86_64.s +++ /dev/null @@ -1,416 +0,0 @@ - .text - .intel_syntax noprefix - .section .text.nonnull_nonnull,"ax",@progbits - .globl nonnull_nonnull - .p2align 4, 0x90 - .type nonnull_nonnull,@function -nonnull_nonnull: - push r15 - push r14 - push r12 - push rbx - push rax - mov rbx, rdx - mov r14, rsi - mov r15, rdi - call qword ptr [rip + objc_msg_lookup@GOTPCREL] - mov r12, qword ptr [rbx] - mov rdi, r15 - mov rsi, r14 - mov rdx, rbx - call rax - mov r14, rax - mov rdi, qword ptr [rbx] - call qword ptr [rip + objc_retain@GOTPCREL] - mov rdi, r12 - call qword ptr [rip + objc_release@GOTPCREL] - mov rax, r14 - add rsp, 8 - pop rbx - pop r12 - pop r14 - pop r15 - ret -.Lfunc_end0: - .size nonnull_nonnull, .Lfunc_end0-nonnull_nonnull - - .section .text.null_nonnull,"ax",@progbits - .globl null_nonnull - .p2align 4, 0x90 - .type null_nonnull,@function -null_nonnull: - push r15 - push r14 - push r12 - push rbx - push rax - mov rbx, rdx - mov r14, rsi - mov r15, rdi - call qword ptr [rip + objc_msg_lookup@GOTPCREL] - mov rcx, rax - test rbx, rbx - je .LBB1_2 - mov r12, qword ptr [rbx] - mov rdi, r15 - mov rsi, r14 - mov rdx, rbx - call rcx - mov r14, rax - mov rdi, qword ptr [rbx] - call qword ptr [rip + objc_retain@GOTPCREL] - mov rdi, r12 - call qword ptr [rip + objc_release@GOTPCREL] - mov rax, r14 - add rsp, 8 - pop rbx - pop r12 - pop r14 - pop r15 - ret -.LBB1_2: - mov rdi, r15 - mov rsi, r14 - xor edx, edx - add rsp, 8 - pop rbx - pop r12 - pop r14 - pop r15 - jmp rcx -.Lfunc_end1: - .size null_nonnull, .Lfunc_end1-null_nonnull - - .section .text.nonnull_null,"ax",@progbits - .globl nonnull_null - .p2align 4, 0x90 - .type nonnull_null,@function -nonnull_null: - push r15 - push r14 - push r12 - push rbx - push rax - mov rbx, rdx - mov r14, rsi - mov r12, rdi - call qword ptr [rip + objc_msg_lookup@GOTPCREL] - mov r15, qword ptr [rbx] - mov rdi, r12 - mov rsi, r14 - mov rdx, rbx - call rax - mov r14, rax - mov rdi, qword ptr [rbx] - call qword ptr [rip + objc_retain@GOTPCREL] - test r15, r15 - je .LBB2_2 - mov rdi, r15 - call qword ptr [rip + objc_release@GOTPCREL] -.LBB2_2: - mov rax, r14 - add rsp, 8 - pop rbx - pop r12 - pop r14 - pop r15 - ret -.Lfunc_end2: - .size nonnull_null, .Lfunc_end2-nonnull_null - - .section .text.null_null,"ax",@progbits - .globl null_null - .p2align 4, 0x90 - .type null_null,@function -null_null: - push r15 - push r14 - push r12 - push rbx - push rax - mov rbx, rdx - mov r14, rsi - mov r12, rdi - call qword ptr [rip + objc_msg_lookup@GOTPCREL] - mov rcx, rax - test rbx, rbx - je .LBB3_4 - mov r15, qword ptr [rbx] - mov rdi, r12 - mov rsi, r14 - mov rdx, rbx - call rcx - mov r14, rax - mov rdi, qword ptr [rbx] - call qword ptr [rip + objc_retain@GOTPCREL] - test r15, r15 - je .LBB3_3 - mov rdi, r15 - call qword ptr [rip + objc_release@GOTPCREL] -.LBB3_3: - mov rax, r14 - add rsp, 8 - pop rbx - pop r12 - pop r14 - pop r15 - ret -.LBB3_4: - mov rdi, r12 - mov rsi, r14 - xor edx, edx - add rsp, 8 - pop rbx - pop r12 - pop r14 - pop r15 - jmp rcx -.Lfunc_end3: - .size null_null, .Lfunc_end3-null_null - - .section .text.two_nonnull_nonnull,"ax",@progbits - .globl two_nonnull_nonnull - .p2align 4, 0x90 - .type two_nonnull_nonnull,@function -two_nonnull_nonnull: - push rbp - push r15 - push r14 - push r13 - push r12 - push rbx - push rax - mov r14, rcx - mov rbx, rdx - mov r15, rsi - mov r12, rdi - call qword ptr [rip + objc_msg_lookup@GOTPCREL] - mov r13, qword ptr [rbx] - mov rcx, qword ptr [r14] - mov qword ptr [rsp], rcx - mov rdi, r12 - mov rsi, r15 - mov rdx, rbx - mov rcx, r14 - call rax - mov rbp, rax - mov rdi, qword ptr [rbx] - mov r15, qword ptr [rip + objc_retain@GOTPCREL] - call r15 - mov rbx, qword ptr [rip + objc_release@GOTPCREL] - mov rdi, r13 - call rbx - mov rdi, qword ptr [r14] - call r15 - mov rdi, qword ptr [rsp] - call rbx - mov rax, rbp - add rsp, 8 - pop rbx - pop r12 - pop r13 - pop r14 - pop r15 - pop rbp - ret -.Lfunc_end4: - .size two_nonnull_nonnull, .Lfunc_end4-two_nonnull_nonnull - - .section .text.call_with_none1,"ax",@progbits - .globl call_with_none1 - .p2align 4, 0x90 - .type call_with_none1,@function -call_with_none1: - push r14 - push rbx - push rax - mov r14, rsi - mov rbx, rdi - call qword ptr [rip + objc_msg_lookup@GOTPCREL] - mov rdi, rbx - mov rsi, r14 - xor edx, edx - add rsp, 8 - pop rbx - pop r14 - jmp rax -.Lfunc_end5: - .size call_with_none1, .Lfunc_end5-call_with_none1 - - .section .text.call_with_none2,"ax",@progbits - .globl call_with_none2 - .p2align 4, 0x90 - .type call_with_none2,@function -call_with_none2: - push r14 - push rbx - push rax - mov r14, rsi - mov rbx, rdi - call qword ptr [rip + objc_msg_lookup@GOTPCREL] - mov rdi, rbx - mov rsi, r14 - xor edx, edx - add rsp, 8 - pop rbx - pop r14 - jmp rax -.Lfunc_end6: - .size call_with_none2, .Lfunc_end6-call_with_none2 - - .section .text.call_with_none3,"ax",@progbits - .globl call_with_none3 - .p2align 4, 0x90 - .type call_with_none3,@function -call_with_none3: - push r14 - push rbx - push rax - mov r14, rsi - mov rbx, rdi - mov qword ptr [rsp], 0 - call qword ptr [rip + objc_msg_lookup@GOTPCREL] - mov rdx, rsp - mov rdi, rbx - mov rsi, r14 - call rax - mov rbx, rax - mov rdi, qword ptr [rsp] - call qword ptr [rip + objc_retain@GOTPCREL] - mov rdx, qword ptr [rsp] - mov rax, rbx - add rsp, 8 - pop rbx - pop r14 - ret -.Lfunc_end7: - .size call_with_none3, .Lfunc_end7-call_with_none3 - - .section .text.call_with_none4,"ax",@progbits - .globl call_with_none4 - .p2align 4, 0x90 - .type call_with_none4,@function -call_with_none4: - push r14 - push rbx - push rax - mov r14, rsi - mov rbx, rdi - mov qword ptr [rsp], 0 - call qword ptr [rip + objc_msg_lookup@GOTPCREL] - mov rdx, rsp - mov rdi, rbx - mov rsi, r14 - call rax - mov rbx, rax - mov rdi, qword ptr [rsp] - call qword ptr [rip + objc_retain@GOTPCREL] - mov rdx, qword ptr [rsp] - mov rax, rbx - add rsp, 8 - pop rbx - pop r14 - ret -.Lfunc_end8: - .size call_with_none4, .Lfunc_end8-call_with_none4 - - .section .text.call_with_some1,"ax",@progbits - .globl call_with_some1 - .p2align 4, 0x90 - .type call_with_some1,@function -call_with_some1: - push r15 - push r14 - push rbx - sub rsp, 16 - mov r14, rdx - mov r15, rsi - mov rbx, rdi - mov qword ptr [rsp + 8], rdx - call qword ptr [rip + objc_msg_lookup@GOTPCREL] - lea rdx, [rsp + 8] - mov rdi, rbx - mov rsi, r15 - call rax - mov rbx, rax - mov rdi, qword ptr [rsp + 8] - call qword ptr [rip + objc_retain@GOTPCREL] - mov rdi, r14 - call qword ptr [rip + objc_release@GOTPCREL] - mov rdx, qword ptr [rsp + 8] - mov rax, rbx - add rsp, 16 - pop rbx - pop r14 - pop r15 - ret -.Lfunc_end9: - .size call_with_some1, .Lfunc_end9-call_with_some1 - - .section .text.call_with_some2,"ax",@progbits - .globl call_with_some2 - .p2align 4, 0x90 - .type call_with_some2,@function -call_with_some2: - push r15 - push r14 - push rbx - sub rsp, 16 - mov r14, rdx - mov r15, rsi - mov rbx, rdi - mov qword ptr [rsp + 8], rdx - call qword ptr [rip + objc_msg_lookup@GOTPCREL] - lea rdx, [rsp + 8] - mov rdi, rbx - mov rsi, r15 - call rax - mov rbx, rax - mov rdi, qword ptr [rsp + 8] - call qword ptr [rip + objc_retain@GOTPCREL] - mov rdi, r14 - call qword ptr [rip + objc_release@GOTPCREL] - mov rdx, qword ptr [rsp + 8] - mov rax, rbx - add rsp, 16 - pop rbx - pop r14 - pop r15 - ret -.Lfunc_end10: - .size call_with_some2, .Lfunc_end10-call_with_some2 - - .section .text.call_with_some3,"ax",@progbits - .globl call_with_some3 - .p2align 4, 0x90 - .type call_with_some3,@function -call_with_some3: - push r15 - push r14 - push rbx - sub rsp, 16 - mov r14, rdx - mov r15, rsi - mov rbx, rdi - mov qword ptr [rsp + 8], rdx - call qword ptr [rip + objc_msg_lookup@GOTPCREL] - lea rdx, [rsp + 8] - mov rdi, rbx - mov rsi, r15 - call rax - mov rbx, rax - mov rdi, qword ptr [rsp + 8] - call qword ptr [rip + objc_retain@GOTPCREL] - mov rdi, r14 - call qword ptr [rip + objc_release@GOTPCREL] - mov rdx, qword ptr [rsp + 8] - mov rax, rbx - add rsp, 16 - pop rbx - pop r14 - pop r15 - ret -.Lfunc_end11: - .size call_with_some3, .Lfunc_end11-call_with_some3 - - .section ".note.GNU-stack","",@progbits diff --git a/crates/test-assembly/crates/test_out_parameters/lib.rs b/crates/test-assembly/crates/test_out_parameters/lib.rs deleted file mode 100644 index c2cf19cd2..000000000 --- a/crates/test-assembly/crates/test_out_parameters/lib.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Test that out parameters are handled correctly. -use objc2::rc::{Id, Owned}; -use objc2::runtime::{Object, Sel}; -use objc2::MessageReceiver; - -#[no_mangle] -unsafe fn nonnull_nonnull(obj: &Object, sel: Sel, param: &mut Id) -> usize { - MessageReceiver::send_message(obj, sel, (param,)) -} - -#[no_mangle] -unsafe fn null_nonnull(obj: &Object, sel: Sel, param: Option<&mut Id>) -> usize { - MessageReceiver::send_message(obj, sel, (param,)) -} - -#[no_mangle] -unsafe fn nonnull_null(obj: &Object, sel: Sel, param: &mut Option>) -> usize { - MessageReceiver::send_message(obj, sel, (param,)) -} - -#[no_mangle] -unsafe fn null_null( - obj: &Object, - sel: Sel, - param: Option<&mut Option>>, -) -> usize { - MessageReceiver::send_message(obj, sel, (param,)) -} - -#[no_mangle] -unsafe fn two_nonnull_nonnull( - obj: &Object, - sel: Sel, - param1: &mut Id, - param2: &mut Id, -) -> usize { - MessageReceiver::send_message(obj, sel, (param1, param2)) -} - -// -// Calling in specific ways that the optimizer should be able to recognize -// - -// These should fully avoid any extra `retain/release` -#[no_mangle] -unsafe fn call_with_none1(obj: &Object, sel: Sel) -> usize { - null_nonnull(obj, sel, None) -} -#[no_mangle] -unsafe fn call_with_none2(obj: &Object, sel: Sel) -> usize { - null_null(obj, sel, None) -} - -type Res = (usize, Option>); - -// These should only need a `retain` -#[no_mangle] -unsafe fn call_with_none3(obj: &Object, sel: Sel) -> Res { - let mut param = None; - let res = nonnull_null(obj, sel, &mut param); - (res, param) -} -#[no_mangle] -unsafe fn call_with_none4(obj: &Object, sel: Sel) -> Res { - let mut param = None; - let res = null_null(obj, sel, Some(&mut param)); - (res, param) -} - -// These should need `retain/release`, but not have any branches -#[no_mangle] -unsafe fn call_with_some1(obj: &Object, sel: Sel, mut param: Id) -> Res { - let res = null_nonnull(obj, sel, Some(&mut param)); - (res, Some(param)) -} -#[no_mangle] -unsafe fn call_with_some2(obj: &Object, sel: Sel, param: Id) -> Res { - let mut param = Some(param); - let res = nonnull_null(obj, sel, &mut param); - (res, param) -} -#[no_mangle] -unsafe fn call_with_some3(obj: &Object, sel: Sel, param: Id) -> Res { - let mut param = Some(param); - let res = null_null(obj, sel, Some(&mut param)); - (res, param) -} From 02650431cd12491f15620bb2b7b30cb5ceb6d809 Mon Sep 17 00:00:00 2001 From: silvanshade Date: Sun, 29 Jan 2023 20:14:32 -0700 Subject: [PATCH 2/2] Start work on proc macros --- Cargo.lock | 168 ++++++ crates/icrate/src/generated | 2 +- crates/objc2-proc-macros/Cargo.toml | 7 + crates/objc2-proc-macros/src/class.rs | 281 ++++++++++ crates/objc2-proc-macros/src/lib.rs | 17 + crates/objc2-proc-macros/src/method.rs | 664 +++++++++++++++++++++++ crates/objc2-proc-macros/src/objc.rs | 329 +++++++++++ crates/objc2-proc-macros/src/protocol.rs | 14 + 8 files changed, 1481 insertions(+), 1 deletion(-) create mode 100644 crates/objc2-proc-macros/src/class.rs create mode 100644 crates/objc2-proc-macros/src/method.rs create mode 100644 crates/objc2-proc-macros/src/objc.rs create mode 100644 crates/objc2-proc-macros/src/protocol.rs diff --git a/Cargo.lock b/Cargo.lock index 1822c957f..8d510d20f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,6 +123,19 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "generator" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d266041a359dfa931b370ef684cceb84b166beb14f7f0421f4a6a3d0c446d12e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows", +] + [[package]] name = "glob" version = "0.3.1" @@ -215,6 +228,20 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "pin-utils", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + [[package]] name = "malloc_buf" version = "1.0.0" @@ -224,6 +251,15 @@ dependencies = [ "libc", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "memchr" version = "2.5.0" @@ -265,6 +301,13 @@ version = "2.0.0-pre.3" [[package]] name = "objc2-proc-macros" version = "0.1.0" +dependencies = [ + "oneshot", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] [[package]] name = "once_cell" @@ -272,6 +315,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +[[package]] +name = "oneshot" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc22d22931513428ea6cc089e942d38600e3d00976eef8c86de6b8a3aadec6eb" +dependencies = [ + "loom", +] + [[package]] name = "overload" version = "0.1.1" @@ -290,6 +342,36 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.50" @@ -319,6 +401,15 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + [[package]] name = "regex-syntax" version = "0.6.28" @@ -331,12 +422,24 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +[[package]] +name = "rustversion" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" + [[package]] name = "ryu" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "semver" version = "1.0.16" @@ -554,9 +657,21 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.30" @@ -584,10 +699,14 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] @@ -631,6 +750,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "winapi" version = "0.3.9" @@ -661,3 +786,46 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" + +[[package]] +name = "windows_i686_gnu" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" + +[[package]] +name = "windows_i686_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" diff --git a/crates/icrate/src/generated b/crates/icrate/src/generated index 33587b88b..d59e0a6b8 160000 --- a/crates/icrate/src/generated +++ b/crates/icrate/src/generated @@ -1 +1 @@ -Subproject commit 33587b88b1d03e21580cf249892be0dd55e3561b +Subproject commit d59e0a6b88addce7aa0997b2f389b1d10e657449 diff --git a/crates/objc2-proc-macros/Cargo.toml b/crates/objc2-proc-macros/Cargo.toml index 8d39a85b7..6c26e4354 100644 --- a/crates/objc2-proc-macros/Cargo.toml +++ b/crates/objc2-proc-macros/Cargo.toml @@ -33,3 +33,10 @@ gnustep-2-1 = ["gnustep-2-0"] [package.metadata.docs.rs] default-target = "x86_64-apple-darwin" + +[dependencies] +oneshot = "0.1" +proc-macro2 = "1.0" +proc-macro-error = "1.0" +quote = "1.0" +syn = { version = "1.0", features = ["extra-traits", "full"] } diff --git a/crates/objc2-proc-macros/src/class.rs b/crates/objc2-proc-macros/src/class.rs new file mode 100644 index 000000000..6e260a547 --- /dev/null +++ b/crates/objc2-proc-macros/src/class.rs @@ -0,0 +1,281 @@ +use crate::method::MethodContext; +use proc_macro2::TokenStream; +use quote::{format_ident, quote, ToTokens, TokenStreamExt}; +use syn::{ + parse::{Parse, ParseStream, Parser}, + punctuated::Punctuated, + spanned::Spanned, + GenericArgument, PathArguments, Type, +}; + +enum FieldKind { + IvarBool, + IvarDrop, + IvarEncode, + PhantomData, +} + +trait FieldExt { + fn field_kind(&self) -> Option; +} + +impl FieldExt for syn::Field { + fn field_kind(&self) -> Option { + if let syn::Type::Path(type_path) = &self.ty { + if let Some(segment) = type_path.path.segments.last() { + if segment.ident == "IvarBool" { + return Some(FieldKind::IvarBool); + } + if segment.ident == "IvarDrop" { + return Some(FieldKind::IvarDrop); + } + if segment.ident == "IvarEncode" { + return Some(FieldKind::IvarEncode); + } + if segment.ident == "PhantomData" { + return Some(FieldKind::PhantomData); + } + } + } + None + } +} + +#[derive(Debug)] +struct ClassMacroInput { + superclass: syn::Ident, + inherits: Option>, +} + +impl Parse for ClassMacroInput { + fn parse(input: ParseStream<'_>) -> syn::Result { + mod keyword { + syn::custom_keyword!(inherits); + } + + let mut superclass = None; + let mut inherits = None; + + loop { + let lookahead = input.lookahead1(); + if superclass.is_none() && lookahead.peek(syn::Token![super]) { + input.parse::()?; + input.parse::()?; + superclass = Some(input.parse()?); + } else if inherits.is_none() && lookahead.peek(keyword::inherits) { + input.parse::()?; + input.parse::()?; + inherits = { + let content; + let bracket = syn::bracketed!(content in input); + let idents = Punctuated::parse_terminated(&content)?; + if idents.is_empty() { + let span = bracket.span; + let message = "#[objc]: `inherits` expects a non-empty list"; + return Err(syn::Error::new(span, message)); + } else { + Some(idents) + } + }; + } + input.parse::>()?; + if input.is_empty() { + break; + } else if true + && (!superclass.is_none() || !input.peek(syn::Token![super])) + && (!inherits.is_none() || !input.peek(keyword::inherits)) + { + let span = input.span(); + let message = "#[objc]: duplicate or unexpected argument"; + return Err(syn::Error::new(span, message)); + } + } + + if let Some(superclass) = superclass { + Ok(ClassMacroInput { + superclass, + inherits, + }) + } else { + let span = input.span(); + let message = "#[objc]: `super` argument is required"; + return Err(syn::Error::new(span, message)); + } + } +} + +struct ClassCandidate<'a> { + ident: &'a syn::Ident, + superclass: syn::Ident, + inherits: Option>, + item_struct: Option<&'a syn::ItemStruct>, +} + +// #[objc] impl T { ... } + +pub fn item_impl(attr: TokenStream, mut item_impl: syn::ItemImpl) -> syn::Result { + if !attr.is_empty() { + let span = attr.span(); + let message = format!("#[objc]: unexpected arguments: `{attr}`"); + return Err(syn::Error::new(span, message)); + } + if item_impl.trait_.is_none() && item_impl.unsafety.is_some() { + // NOTE: inherent impls cannot be unsafe + item_impl.unsafety = None; + } + let mut tokens = TokenStream::new(); + for attr in item_impl.attrs.iter() { + if let syn::AttrStyle::Outer = attr.style { + attr.to_tokens(&mut tokens); + } + } + item_impl.defaultness.to_tokens(&mut tokens); + item_impl.unsafety.to_tokens(&mut tokens); + item_impl.impl_token.to_tokens(&mut tokens); + item_impl.generics.to_tokens(&mut tokens); + if let Some((polarity, path, for_token)) = item_impl.trait_ { + polarity.to_tokens(&mut tokens); + path.to_tokens(&mut tokens); + for_token.to_tokens(&mut tokens); + } + item_impl.self_ty.to_tokens(&mut tokens); + item_impl.generics.where_clause.to_tokens(&mut tokens); + let (tx, rx) = oneshot::channel(); + item_impl.brace_token.surround(&mut tokens, |tokens| { + for attr in item_impl.attrs.iter() { + if let syn::AttrStyle::Inner(_) = attr.style { + attr.to_tokens(tokens); + } + } + for item in item_impl.items.into_iter() { + if let syn::ImplItem::Method(method) = item { + match crate::method::rewrite_method(MethodContext::Impl, method) { + Ok(method) => { + tokens.append_all(method); + } + Err(err) => { + tx.send(Err(err)).unwrap(); + return; + } + } + } + } + tx.send(Ok(())).unwrap(); + }); + rx.recv().unwrap()?; + Ok(tokens.into()) +} + +// #[objc] struct T { ... } + +pub fn item_struct(attr: TokenStream, item_struct: syn::ItemStruct) -> syn::Result { + let ClassMacroInput { + superclass, + inherits, + } = Parser::parse2(ClassMacroInput::parse, attr)?; + + let syn::ItemStruct { ident, .. } = &item_struct; + + let mut tokens = TokenStream::new(); + + for attr in item_struct.attrs.iter() { + if let syn::AttrStyle::Outer = attr.style { + attr.to_tokens(&mut tokens); + } + } + + tokens.append_all(quote!(#[repr(C)])); + + item_struct.vis.to_tokens(&mut tokens); + item_struct.struct_token.to_tokens(&mut tokens); + item_struct.ident.to_tokens(&mut tokens); + item_struct.generics.to_tokens(&mut tokens); + + if let syn::Fields::Named(fields) = &item_struct.fields { + item_struct.generics.where_clause.to_tokens(&mut tokens); + + // FIXME: accumulate ivars helper stuff + let (tx, rx) = oneshot::channel(); + fields.brace_token.surround(&mut tokens, |tokens| { + let manually_drop = { + let superclass = format_ident!("{}", superclass); + quote!(__inner: objc2::__macro_helpers::ManuallyDrop<#superclass>) + }; + tokens.append_all(manually_drop); + + let mut ivars_helper_mod_items = TokenStream::new(); + let mut ivars_declare_fn_block = TokenStream::new(); + + ivars_helper_mod_items.append_all(quote!(use super::*;)); + + for pair in fields.named.pairs() { + if let Some(field) = pair.value().field_kind() { + match field { + FieldKind::IvarBool => { + todo!(); + } + FieldKind::IvarDrop => { + todo!(); + } + FieldKind::IvarEncode => { + todo!(); + } + FieldKind::PhantomData => { + todo!(); + } + } + } else { + let span = pair.value().span(); + let message = "#[obj]: all fields must be of type: `IvarBool`, `IvarDrop`, `IvarEncode`, or `PhantomData`"; + tx.send(Err(syn::Error::new(span, message))).unwrap(); + return; + } + } + + let ivars_helper_mod = quote!( + mod ivars { + #ivars_helper_mod_items + pub(super) fn __objc2_declare_ivars(__objc2_builder: &mut objc2::declare::ClassBuilder) { + #ivars_declare_fn_block + } + } + ); + + tx.send(Ok(ivars_helper_mod)).unwrap(); + }); + let ivars_helper_mod = rx.recv().unwrap()?; + } else { + let span = item_struct.fields.span(); + let message = "#[objc]: class structs must be defined using named fields"; + return Err(syn::Error::new(span, message)); + } + + Ok(tokens) +} + +// #[objc] type T; + +pub fn item_type(attr: TokenStream, item_type: crate::objc::ItemType) -> syn::Result { + let ClassMacroInput { + superclass, + inherits, + } = Parser::parse2(ClassMacroInput::parse, attr)?; + + let crate::objc::ItemType { ident, .. } = &item_type; + + todo!() +} + +struct TokensOrDefault<'a, T: 'a>(&'a Option); + +impl<'a, T> ToTokens for TokensOrDefault<'a, T> +where + T: ToTokens + Default, +{ + fn to_tokens(&self, tokens: &mut TokenStream) { + match self.0 { + Some(t) => t.to_tokens(tokens), + None => T::default().to_tokens(tokens), + } + } +} diff --git a/crates/objc2-proc-macros/src/lib.rs b/crates/objc2-proc-macros/src/lib.rs index 94300be0f..019b9d2c5 100644 --- a/crates/objc2-proc-macros/src/lib.rs +++ b/crates/objc2-proc-macros/src/lib.rs @@ -17,6 +17,11 @@ #[doc = include_str!("../README.md")] extern "C" {} +mod class; +mod method; +mod objc; +mod protocol; + use core::hash::{Hash, Hasher}; use proc_macro::Ident; @@ -72,3 +77,15 @@ pub fn __hash_idents(input: TokenStream) -> TokenStream { let s = format!("{:016x}", hasher.finish()); TokenTree::Literal(Literal::string(&s)).into() } + +#[allow(missing_docs)] +#[proc_macro_attribute] +pub fn objc(attr: TokenStream, item: TokenStream) -> TokenStream { + let attr = attr.into(); + let item = item.into(); + let result = crate::objc::objc(attr, item); + match result { + Ok(output) => output.into(), + Err(error) => error.to_compile_error().into(), + } +} diff --git a/crates/objc2-proc-macros/src/method.rs b/crates/objc2-proc-macros/src/method.rs new file mode 100644 index 000000000..29d940704 --- /dev/null +++ b/crates/objc2-proc-macros/src/method.rs @@ -0,0 +1,664 @@ +use proc_macro2::{Span, TokenStream}; +use quote::{quote, ToTokens, TokenStreamExt}; +use std::collections::BTreeSet; +use syn::spanned::Spanned; + +// Specifies whether the method (signature) is within a `trait` or `impl` block +#[derive(Debug)] +pub enum MethodContext { + Impl, + Trait, +} + +// Rewrite a method (signature) within a `trait` or `impl` block for objc interop +pub fn rewrite_method( + context: MethodContext, + mut item_method: syn::ImplItemMethod, +) -> syn::Result { + let mut tokens = TokenStream::new(); + for attr in item_method.attrs.iter() { + if let syn::AttrStyle::Outer = attr.style { + if attr.path.is_ident("objc") { + continue; + } + attr.to_tokens(&mut tokens); + } + } + item_method.vis.to_tokens(&mut tokens); + item_method.defaultness.to_tokens(&mut tokens); + item_method.sig.to_tokens(&mut tokens); + let (tx, rx) = oneshot::channel(); + item_method + .block + .brace_token + .surround(&mut tokens, |tokens| { + for attr in item_method.attrs.iter() { + if let syn::AttrStyle::Inner(_) = attr.style { + attr.to_tokens(tokens); + } + } + if item_method.block.stmts.len() == 1 { + if let syn::Stmt::Item(syn::Item::Verbatim(verbatim)) = &item_method.block.stmts[0] + { + if verbatim.to_string() == ";" { + match rewrite_method_block(context, &item_method) { + Ok(block) => { + tokens.append_all(block); + } + Err(err) => { + tx.send(Err(err)).unwrap(); + return; + } + } + } + } + } else { + tokens.append_all(&item_method.block.stmts); + } + tx.send(Ok(())).unwrap(); + }); + rx.recv().unwrap()?; + Ok(tokens.into()) +} + +// Rewrite a method block within a `trait` or `impl` block for objc interop +fn rewrite_method_block( + context: MethodContext, + item_method: &syn::ImplItemMethod, +) -> syn::Result { + // TODO: handle `optional` + let MethodSpecification { + item_method, + mut selector, + receiver, + semantics, + .. + } = elaborate_method(context, item_method)?; + + // null-terminate the selector string + selector.push('\u{0}'); + + // construct the selector caching block syntax fragment + let cached_sel = quote!({ + static __CACHED_SEL: objc2::__macro_helpers::CachedSel = objc2::__macro_helpers::CachedSel::new(); + __CACHED_SEL.get(#selector) + }); + + // construct the receiver syntax fragment + let receiver = match receiver { + MethodReceiver::Class => quote!(::class()), + MethodReceiver::SelfType { .. } => quote!(&self), + MethodReceiver::This { .. } => quote!(this), + }; + + // extract the method args + let args = item_method.get_args().filter_map(|arg| { + if let syn::FnArg::Typed(ty) = arg { + Some(&*ty.pat) + } else { + None + } + }); + + // handle the managed method case (returns `Id`) + if let Some(semantics) = semantics { + // compute the semantics syntax fragment + let semantics = if let MethodSemantics::Unspecified = semantics { + quote!(RetainSemantics<{objc2::__macro_helpers::retain_semantics(#selector)}>) + } else { + quote::format_ident!("{semantics}").into_token_stream() + }; + // compute the block syntax fragment + let block = quote!( + #[allow(unused_unsafe)] + unsafe { + >::send_message_id( + #receiver, + #cached_sel, + (#(#args,)*), + ) + } + ); + return Ok(block); + } + + // handle the non-managed method case + let block = quote!( + #[allow(unused_unsafe)] + unsafe { + objc2::MessageReceiver::send_message::<_, _>( + #receiver, + #cached_sel, + (#(#args,)*), + ) + } + ); + Ok(block) +} + +// A candidate method for objc interop rewriting (prior to elaboration) +#[derive(Debug)] +struct MethodCandidate<'a> { + context: MethodContext, + item_method: &'a syn::ImplItemMethod, + meta: Option, +} + +// A fully elaborated method suitable for objc interop +struct MethodSpecification<'a> { + context: MethodContext, + item_method: &'a syn::ImplItemMethod, + selector: String, + receiver: MethodReceiver<'a>, + semantics: Option, + out_params: BTreeSet, + optional: bool, +} + +// Try to elaborate a candidate method into a full method specification +impl<'a> TryFrom> for MethodSpecification<'a> { + type Error = syn::Error; + + fn try_from(candidate: MethodCandidate<'a>) -> Result { + use syn::{Lit, Meta, MetaList, NestedMeta}; + + let MethodCandidate { + context, + item_method, + meta, + } = candidate; + let mut selector = String::new(); + let receiver = get_method_receiver(&item_method.sig); + let mut method_return = None; + let mut semantics = None::; + let mut out_params = BTreeSet::new(); + let mut optional = false; + + if let Some(meta) = &meta { + match meta { + // TODO:: maybe warn about being redundant (with no arguments) + Meta::Path(path) => { + debug_assert!(path.is_ident("objc")); + } + Meta::List(MetaList { path, nested, .. }) => { + debug_assert!(path.is_ident("objc")); + + let mut processor = crate::objc::MetaProcessor::new(); + + for nested_meta in nested { + if let NestedMeta::Meta(meta) = nested_meta { + match meta { + // handle `sel = ` argument + Meta::NameValue(name_value) if name_value.path.is_ident("sel") => { + processor.ensure_unique(&name_value.path)?; + // check that `` is a string + if let Lit::Str(str) = &name_value.lit { + // parse `` + selector = Selector::from(str).into(); + } else { + let span = name_value.lit.span(); + let key = "sel"; + let r#type = "a string"; + return Err(crate::objc::error_invalid_value_type( + span, key, r#type, + )); + } + } + // handle `managed = ` argument + Meta::NameValue(name_value) + if name_value.path.is_ident("managed") => + { + processor.ensure_unique(&name_value.path)?; + // ensure we only parse `managed` once + if semantics.is_some() { + let span = name_value.span(); + let message = + "#[objc]: argument `managed` already specified"; + return Err(syn::Error::new(span, message)); + } + // analyze the method return type (if not already done) + match method_return + .get_or_insert_with(|| item_method.get_return()) + { + // check for allowed return types for `managed` + MethodReturn::Managed { .. } + | MethodReturn::Result { + ownership: Some(_), .. + } => { + // okay + } + _ => { + let span = item_method.sig.output.span(); + let message = "#[objc]: return must be `Id` or `Result, _>` for `managed`"; + return Err(syn::Error::new(span, message)); + } + } + // check that `` is a string + if let Lit::Str(str) = &name_value.lit { + // parse `` + semantics = Some(str.try_into()?); + } else { + let span = name_value.lit.span(); + let key = "managed"; + let r#type = "a string"; + return Err(crate::objc::error_invalid_value_type( + span, key, r#type, + )); + } + } + // handle `managed` (no value) argument + Meta::Path(path) if path.is_ident("managed") => { + processor.ensure_unique(&path)?; + // ensure we only parse `managed` once + if semantics.is_some() { + let span = path.span(); + let message = + "#[objc]: argument `managed` already specified"; + return Err(syn::Error::new(span, message)); + } + // analyze the method return type (if not already done) + match method_return + .get_or_insert_with(|| item_method.get_return()) + { + // check for allowed return types for `managed` + MethodReturn::Managed { .. } + | MethodReturn::Result { + ownership: Some(_), .. + } => { + // okay + } + _ => { + let span = item_method.sig.output.span(); + let message = "#[objc]: return must be `Id` or `Result, _>` for `managed`"; + return Err(syn::Error::new(span, message)); + } + } + // use `unspecified` for semantics since no value was given + semantics = Some(MethodSemantics::Unspecified); + } + // handle `optional` argument + Meta::Path(path) if path.is_ident("optional") => { + processor.ensure_unique(&path)?; + // check that method context is a trait (protocol) + if let MethodContext::Trait = context { + optional = true; + } else { + let span = meta.span(); + let message = "#[objc]: `optional` is only allowed for trait (protocol) methods"; + return Err(syn::Error::new(span, message)); + } + } + // FIXME: have `catch` as a special case (just for `NSError`) + // handle `out` argument + Meta::Path(path) if path.is_ident("out") => { + // analyze the method return type (if not already done) + match method_return + .get_or_insert_with(|| item_method.get_return()) + { + // check for allowed return types for `catch` + MethodReturn::Result { .. } => { + // TODO: generalize + let last_arg = item_method.sig.inputs.len() - 1; + out_params.insert(last_arg); + } + _ => { + let span = item_method.sig.output.span(); + let message = "#[objc]: return must be `Result>` for `out`"; + return Err(syn::Error::new(span, message)); + } + } + } + _ => { + let span = meta.span(); + return Err(crate::objc::error_invalid_argument(span)); + } + } + } else { + let span = nested_meta.span(); + return Err(crate::objc::error_invalid_argument(span)); + } + } + } + _ => { + let span = meta.span(); + return Err(crate::objc::error_invalid_argument(span)); + } + } + } + + // synthesize selector if not specified by attribute + if selector.is_empty() { + let receiver = &receiver; + let sig = &item_method.sig; + let candidate = SelectorCandidate { receiver, sig }; + selector = Selector::try_from(candidate)?.into(); + } + + // synthesize semantics if not specified by attribute + if semantics.is_none() { + // analyze the method return type (if not already done) + match method_return.get_or_insert_with(|| item_method.get_return()) { + MethodReturn::Managed { .. } + | MethodReturn::Result { + ownership: Some(_), .. + } => { + semantics = Some(MethodSemantics::Unspecified); + } + _ => {} + } + } + + Ok(MethodSpecification { + context, + item_method, + selector, + receiver, + semantics, + out_params, + optional, + }) + } +} + +// The method receiver type +#[derive(Debug)] +enum MethodReceiver<'a> { + Class, + SelfType { arg: &'a syn::FnArg }, + This { arg: &'a syn::FnArg }, +} + +struct SelectorCandidate<'a> { + receiver: &'a MethodReceiver<'a>, + sig: &'a syn::Signature, +} + +// Wrapper struct for selector (for impls) +struct Selector(String); + +// Create a selector for a string +impl From<&syn::LitStr> for Selector { + fn from(str: &syn::LitStr) -> Self { + Selector(str.value()) + } +} + +// Synthesize a selector from a method signature +impl<'a> TryFrom> for Selector { + type Error = syn::Error; + + fn try_from(candidate: SelectorCandidate<'_>) -> Result { + use MethodReceiver::*; + let mut count = 0usize; + let mut prev_was_underscore = false; + let mut sel = String::new(); + for c in candidate.sig.ident.to_string().chars() { + if c == '_' { + if prev_was_underscore { + let span = candidate.sig.ident.span(); + let message = "#[objc]: subsequent underscores in `fn` name disallowed; specify selector if this is needed"; + return Err(syn::Error::new(span, message)); + } + sel.push(':'); + count += 1; + prev_was_underscore = true; + } else { + sel.push(c); + prev_was_underscore = false; + } + } + let arg_count = match candidate.receiver { + SelfType { .. } | This { .. } => candidate.sig.inputs.len() - 1, + Class => 0, + }; + if arg_count == count + 1 { + sel.push(':'); + } else if 0 < arg_count || 0 < count { + let span = candidate.sig.span(); + let message = "#[objc]: number of `_` and argument count disagree"; + return Err(syn::Error::new(span, message)); + } + Ok(Selector(sel)) + } +} + +impl From for String { + fn from(sel: Selector) -> Self { + sel.0 + } +} + +// Retain semantics for a method +#[derive(Debug)] +enum MethodSemantics { + Init, + New, + Other, + Unspecified, +} + +impl std::fmt::Display for MethodSemantics { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(self, f) + } +} + +impl TryFrom<&syn::LitStr> for MethodSemantics { + type Error = syn::Error; + + fn try_from(str: &syn::LitStr) -> Result { + let value = str.value(); + match value.as_str() { + "init" => Ok(MethodSemantics::Init), + "new" => Ok(MethodSemantics::New), + "other" => Ok(MethodSemantics::Other), + _ => { + let value = value.to_ascii_lowercase(); + if ["init", "new", "other"].contains(&value.as_str()) { + let span = str.span(); + let message = r#"`managed` value must be a lowercase string"#; + Err(syn::Error::new(span, message)) + } else { + let span = str.span(); + let message = r#"`managed` value must be one of { "init", "new", "other" }"#; + Err(syn::Error::new(span, message)) + } + } + } + } +} + +// Ownership for the `Id` type +#[derive(Debug)] +enum ObjectOwnership { + Owned, + Shared, +} + +// The form of the method return type +#[derive(Debug)] +enum MethodReturn<'a> { + // no explicit return type (implict `()`) + Default, + // return type of `Id` + Managed { + r#type: &'a syn::Type, + ownership: ObjectOwnership, + }, + // return type of `Result>` + Result { + r#type: &'a syn::Type, + ownership: Option, + }, + // any other return type `T` + Typical { + r#type: &'a syn::Type, + }, +} + +trait ItemMethodExt { + fn get_return(&self) -> MethodReturn<'_>; + fn get_receiver(&self) -> MethodReceiver<'_>; + fn get_args(&self) -> Box + '_>; +} + +impl ItemMethodExt for syn::TraitItemMethod { + fn get_return(&self) -> MethodReturn<'_> { + get_method_return(&self.sig) + } + + fn get_receiver(&self) -> MethodReceiver<'_> { + get_method_receiver(&self.sig) + } + + fn get_args(&self) -> Box + '_> { + let iter = self.sig.inputs.iter(); + if self.sig.receiver().is_some() { + Box::new(iter.skip(1)) + } else { + Box::new(iter) + } + } +} + +impl ItemMethodExt for syn::ImplItemMethod { + fn get_return(&self) -> MethodReturn<'_> { + get_method_return(&self.sig) + } + + fn get_receiver(&self) -> MethodReceiver<'_> { + get_method_receiver(&self.sig) + } + + fn get_args(&self) -> Box + '_> { + let iter = self.sig.inputs.iter(); + if self.sig.receiver().is_some() { + Box::new(iter.skip(1)) + } else { + Box::new(iter) + } + } +} + +// Compute the return type from a method signature +fn get_method_return(sig: &syn::Signature) -> MethodReturn<'_> { + use syn::ReturnType; + match &sig.output { + ReturnType::Default => MethodReturn::Default, + ReturnType::Type(_, ty) => get_method_return_from_type(ty), + } +} + +// Compute a method return type from a given type +fn get_method_return_from_type(r#type: &syn::Type) -> MethodReturn<'_> { + use syn::{GenericArgument, PathArguments, Type}; + if let Type::Path(type_path) = r#type { + if let Some(segment) = type_path.path.segments.last() { + // check for `Result` + if segment.ident == "Result" { + if let PathArguments::AngleBracketed(args) = &segment.arguments { + if let Some(GenericArgument::Type(ty)) = args.args.last() { + // check that `E = Id` + // FIXME: should we check for `Shared` here too? + if let MethodReturn::Managed { r#type: error, .. } = + get_method_return_from_type(ty) + { + if let Type::Path(type_path) = error { + if let Some(segment) = type_path.path.segments.last() { + // check that `T = NSError` + if segment.ident == "NSError" { + if let Some(GenericArgument::Type(r#type)) = + args.args.first() + { + if let MethodReturn::Managed { r#type, ownership } = + get_method_return_from_type(r#type) + { + // handle the case where `S = Id<_, _>` case + let ownership = ownership.into(); + return MethodReturn::Result { r#type, ownership }; + } else { + // handle the case where `S` is any other type + let ownership = None; + return MethodReturn::Result { r#type, ownership }; + } + } + } + } + } + } + } + } + } + // check for `Id` + if segment.ident == "Id" { + if let PathArguments::AngleBracketed(args) = &segment.arguments { + if let Some(GenericArgument::Type(ty)) = args.args.last() { + if let Type::Path(type_path) = &*ty { + if let Some(segment) = type_path.path.segments.last() { + // check for `O = Owned` + if segment.ident == "Owned" { + if let Some(GenericArgument::Type(ty)) = args.args.first() { + let r#type = ty; + let ownership = ObjectOwnership::Owned; + return MethodReturn::Managed { r#type, ownership }; + } + } + // check for `O = Shared` + if segment.ident == "Shared" { + if let Some(GenericArgument::Type(ty)) = args.args.first() { + let r#type = ty; + let ownership = ObjectOwnership::Shared; + return MethodReturn::Managed { r#type, ownership }; + } + } + } + } + } + } + } + } + } + MethodReturn::Typical { r#type } +} + +// Compute the receiver from a method signature +fn get_method_receiver(sig: &syn::Signature) -> MethodReceiver<'_> { + use syn::{FnArg, Pat, PatIdent, PatType}; + if let Some(arg) = sig.inputs.first() { + match arg { + FnArg::Receiver(_) => { + return MethodReceiver::SelfType { arg }; + } + FnArg::Typed(PatType { pat, .. }) => { + if let Pat::Ident(PatIdent { ident, .. }) = &**pat { + if ident == "self" { + return MethodReceiver::SelfType { arg }; + } + if ident == "this" { + return MethodReceiver::This { arg }; + } + } + } + } + } + MethodReceiver::Class +} + +// Elaborate a method candidate into a method specification +fn elaborate_method( + context: MethodContext, + item_method: &syn::ImplItemMethod, +) -> syn::Result> { + let meta = item_method + .attrs + .iter() + .find(|attr| attr.path.is_ident("objc")) + .map(|attr| attr.parse_meta()) + .transpose()?; + let candidate = MethodCandidate { + context, + item_method, + meta, + }; + candidate.try_into() +} diff --git a/crates/objc2-proc-macros/src/objc.rs b/crates/objc2-proc-macros/src/objc.rs new file mode 100644 index 000000000..4e771a56e --- /dev/null +++ b/crates/objc2-proc-macros/src/objc.rs @@ -0,0 +1,329 @@ +use proc_macro2::{Span, TokenStream}; +use std::collections::HashSet; +use syn::{ + parse::{Parse, ParseStream}, + spanned::Spanned, +}; + +pub struct ItemType { + pub attrs: Vec, + pub vis: syn::Visibility, + pub type_token: syn::Token![type], + pub ident: syn::Ident, + pub generics: syn::Generics, + pub semi_token: syn::Token![;], +} + +pub enum ItemObjC { + ItemImpl(syn::ItemImpl), + ItemStruct(syn::ItemStruct), + ItemTrait(syn::ItemTrait), + ItemType(ItemType), +} + +// NOTE: definition from syn crate +fn data_struct( + input: ParseStream<'_>, +) -> syn::Result<( + Option, + syn::Fields, + Option, +)> { + let mut lookahead = input.lookahead1(); + let mut where_clause = None; + if lookahead.peek(syn::Token![where]) { + where_clause = Some(input.parse()?); + lookahead = input.lookahead1(); + } + + if where_clause.is_none() && lookahead.peek(syn::token::Paren) { + let fields = input.parse()?; + + lookahead = input.lookahead1(); + if lookahead.peek(syn::Token![where]) { + where_clause = Some(input.parse()?); + lookahead = input.lookahead1(); + } + + if lookahead.peek(syn::Token![;]) { + let semi = input.parse()?; + Ok((where_clause, syn::Fields::Unnamed(fields), Some(semi))) + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(syn::token::Brace) { + let fields = input.parse()?; + Ok((where_clause, syn::Fields::Named(fields), None)) + } else if lookahead.peek(syn::Token![;]) { + let semi = input.parse()?; + Ok((where_clause, syn::Fields::Unit, Some(semi))) + } else { + Err(lookahead.error()) + } +} + +fn parse_rest_of_impl( + input: ParseStream<'_>, + mut attrs: Vec, + unsafety: Option, +) -> syn::Result { + let impl_token = input.parse::()?; + + let has_generics = input.peek(syn::Token![<]) + && (input.peek2(syn::Token![>]) + || input.peek2(syn::Token![#]) + || (input.peek2(syn::Ident) || input.peek2(syn::Lifetime)) + && (input.peek3(syn::Token![:]) + || input.peek3(syn::Token![,]) + || input.peek3(syn::Token![>]) + || input.peek3(syn::Token![=])) + || input.peek2(syn::Token![const])); + let mut generics: syn::Generics = if has_generics { + input.parse()? + } else { + syn::Generics::default() + }; + + let polarity = None::; + let first_ty_span = input.span(); + let mut first_ty: syn::Type = input.parse()?; + let self_ty: syn::Type; + let trait_; + + let is_impl_for = input.peek(syn::Token![for]); + if is_impl_for { + let for_token: syn::Token![for] = input.parse()?; + let mut first_ty_ref = &first_ty; + while let syn::Type::Group(ty) = first_ty_ref { + first_ty_ref = &ty.elem; + } + if let syn::Type::Path(syn::TypePath { qself: None, .. }) = first_ty_ref { + while let syn::Type::Group(ty) = first_ty { + first_ty = *ty.elem; + } + if let syn::Type::Path(syn::TypePath { qself: None, path }) = first_ty { + trait_ = Some((polarity, path, for_token)); + } else { + unreachable!(); + } + } else { + return Err(syn::Error::new(first_ty_span, "expected trait path")); + } + self_ty = input.parse()?; + } else { + trait_ = None; + self_ty = first_ty; + } + + if input.peek(syn::Token![for]) { + let span = impl_token.span(); + let message = "[objc]: expected inherent impl"; + return Err(syn::Error::new(span, message)); + } + + generics.where_clause = input.parse()?; + + let content; + let brace_token = syn::braced!(content in input); + attrs.extend(syn::Attribute::parse_inner(&content)?); + + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + return Ok(syn::ItemImpl { + attrs, + defaultness: None, + unsafety, + impl_token, + generics, + trait_: None, + self_ty: Box::new(self_ty), + brace_token, + items, + }); +} + +fn parse_rest_of_struct( + input: ParseStream<'_>, + attrs: Vec, + vis: syn::Visibility, +) -> syn::Result { + let struct_token = input.parse()?; + let ident = input.parse()?; + let generics = input.parse()?; + let (where_clause, fields, semi_token) = data_struct(input)?; + return Ok(syn::ItemStruct { + attrs, + vis, + struct_token, + ident, + generics: syn::Generics { + where_clause, + ..generics + }, + fields, + semi_token, + }); +} + +fn parse_rest_of_trait( + input: ParseStream<'_>, + mut attrs: Vec, + vis: syn::Visibility, + unsafety: Option, +) -> syn::Result { + let auto_token = input.parse()?; + let trait_token = input.parse()?; + let ident = input.parse()?; + let mut generics = input.parse::()?; + + let colon_token: Option = input.parse()?; + + let mut supertraits = syn::punctuated::Punctuated::new(); + if colon_token.is_some() { + loop { + if input.peek(syn::Token![where]) || input.peek(syn::token::Brace) { + break; + } + supertraits.push_value(input.parse()?); + if input.peek(syn::Token![where]) || input.peek(syn::token::Brace) { + break; + } + supertraits.push_punct(input.parse()?); + } + } + + generics.where_clause = input.parse()?; + + let content; + let brace_token = syn::braced!(content in input); + attrs.extend(syn::Attribute::parse_inner(&content)?); + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + + Ok(syn::ItemTrait { + attrs, + vis, + unsafety, + auto_token, + trait_token, + ident, + generics, + colon_token, + supertraits, + brace_token, + items, + }) +} + +fn parse_rest_of_type( + input: ParseStream<'_>, + attrs: Vec, + vis: syn::Visibility, +) -> syn::Result { + let type_token = input.parse()?; + let ident = input.parse()?; + let generics = { + let mut generics = input.parse::()?; + generics.where_clause = input.parse()?; + generics + }; + let semi_token = input.parse()?; + Ok(ItemType { + attrs, + vis, + type_token, + ident, + generics, + semi_token, + }) +} + +impl Parse for ItemObjC { + fn parse(input: ParseStream<'_>) -> syn::Result { + // parse attributes + let attrs = input.call(syn::Attribute::parse_outer)?; + let vis = input.parse()?; + + let lookahead = input.lookahead1(); + + // parse `type` + if lookahead.peek(syn::Token![type]) { + let item_type = parse_rest_of_type(input, attrs, vis)?; + return Ok(ItemObjC::ItemType(item_type)); + } + + // parse `struct` + if lookahead.peek(syn::Token![struct]) { + let item_struct = parse_rest_of_struct(input, attrs, vis)?; + return Ok(ItemObjC::ItemStruct(item_struct)); + } + + // parse `unsafe` + if lookahead.peek(syn::Token![unsafe]) { + let unsafety = Some(input.parse()?); + + let lookahead = input.lookahead1(); + + // parse impl + if lookahead.peek(syn::Token![impl]) { + let item_impl = parse_rest_of_impl(input, attrs, unsafety)?; + return Ok(ItemObjC::ItemImpl(item_impl)); + } + + // parse `trait` + if lookahead.peek(syn::Token![trait]) { + let item_trait = parse_rest_of_trait(input, attrs, vis, unsafety)?; + return Ok(ItemObjC::ItemTrait(item_trait)); + } + + return Err(lookahead.error()); + } + + Err(lookahead.error()) + } +} + +pub fn objc(attr: TokenStream, item: TokenStream) -> syn::Result { + let item = syn::parse2::(item)?; + match item { + ItemObjC::ItemImpl(item_impl) => crate::class::item_impl(attr, item_impl), + ItemObjC::ItemStruct(item_struct) => crate::class::item_struct(attr, item_struct), + ItemObjC::ItemTrait(item_trait) => crate::protocol::item_trait(attr, item_trait), + ItemObjC::ItemType(item_type) => crate::class::item_type(attr, item_type), + } +} + +pub struct MetaProcessor<'m> { + processed: HashSet<&'m syn::Path>, +} + +impl<'m> MetaProcessor<'m> { + pub fn new() -> Self { + let processed = HashSet::default(); + Self { processed } + } + + pub fn ensure_unique(&mut self, path: &'m syn::Path) -> syn::Result<()> { + if !self.processed.insert(path) { + let span = path.span(); + let message = "#[objc]: duplicate argument"; + Err(syn::Error::new(span, message)) + } else { + Ok(()) + } + } +} + +pub fn error_invalid_argument(span: Span) -> syn::Error { + let message = "#[objc]: invalid argument"; + syn::Error::new(span, message) +} + +pub fn error_invalid_value_type(span: Span, key: &str, r#type: &str) -> syn::Error { + let message = format!("#[objc]: value for `{key}` must be {}", r#type); + syn::Error::new(span, message) +} diff --git a/crates/objc2-proc-macros/src/protocol.rs b/crates/objc2-proc-macros/src/protocol.rs new file mode 100644 index 000000000..217e16983 --- /dev/null +++ b/crates/objc2-proc-macros/src/protocol.rs @@ -0,0 +1,14 @@ +use proc_macro2::TokenStream; +use syn::spanned::Spanned; + +pub(crate) fn item_trait( + attr: TokenStream, + item_trait: syn::ItemTrait, +) -> syn::Result { + if !attr.is_empty() { + let span = attr.span(); + let message = format!("#[objc]: unexpected arguments: `{attr}`"); + return Err(syn::Error::new(span, message)); + } + todo!() +}