# REQUIRES: x86 # RUN: rm -rf %t; split-file %s %t # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos11.0 -I %t %t/cat1.s -o %t/cat1.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos11.0 -I %t %t/cat2.s -o %t/cat2.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos11.0 -I %t %t/klass.s -o %t/klass.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos11.0 -I %t %t/cat1.s --defsym MAKE_LOAD_METHOD=1 -o %t/cat1-with-load.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos11.0 -I %t %t/cat2.s --defsym MAKE_LOAD_METHOD=1 -o %t/cat2-with-load.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos11.0 -I %t %t/klass.s --defsym MAKE_LOAD_METHOD=1 -o %t/klass-with-load.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos11.0 -I %t %t/klass-with-no-rodata.s -o %t/klass-with-no-rodata.o # RUN: %lld -dylib -lobjc %t/klass.o -o %t/libklass.dylib # RUN: %no-fatal-warnings-lld --check-category-conflicts -dylib -lobjc %t/klass.o %t/cat1.o %t/cat2.o -o \ # RUN: /dev/null 2>&1 | FileCheck %s --check-prefixes=CATCLS,CATCAT # RUN: %no-fatal-warnings-lld --check-category-conflicts -dylib -lobjc %t/libklass.dylib %t/cat1.o \ # RUN: %t/cat2.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=CATCAT ## Check that we don't emit spurious warnings around the +load method while ## still emitting the other warnings. Note that we have made separate ## `*-with-load.s` files for ease of comparison with ld64; ld64 will not warn ## at all if multiple +load methods are present. # RUN: %no-fatal-warnings-lld --check-category-conflicts -dylib -lobjc %t/klass-with-load.o \ # RUN: %t/cat1-with-load.o %t/cat2-with-load.o -o /dev/null 2>&1 | \ # RUN: FileCheck %s --check-prefixes=CATCLS,CATCAT --implicit-check-not '+load' ## Regression test: Check that we don't crash. # RUN: %no-fatal-warnings-lld --check-category-conflicts -dylib -lobjc %t/klass-with-no-rodata.o -o /dev/null ## Check that we don't emit any warnings without --check-category-conflicts. # RUN: %no-fatal-warnings-lld -dylib -lobjc %t/klass.o %t/cat1.o %t/cat2.o -o \ # RUN: /dev/null 2>&1 | FileCheck %s --implicit-check-not 'warning' --allow-empty # CATCLS: warning: method '+s1' has conflicting definitions: # CATCLS-NEXT: >>> defined in category Cat1 from {{.*}}cat1{{.*}}.o # CATCLS-NEXT: >>> defined in class Foo from {{.*}}klass{{.*}}.o # CATCLS: warning: method '-m1' has conflicting definitions: # CATCLS-NEXT: >>> defined in category Cat1 from {{.*}}cat1{{.*}}.o # CATCLS-NEXT: >>> defined in class Foo from {{.*}}klass{{.*}}.o # CATCAT: warning: method '+s2' has conflicting definitions: # CATCAT-NEXT: >>> defined in category Cat2 from {{.*}}cat2{{.*}}.o # CATCAT-NEXT: >>> defined in category Cat1 from {{.*}}cat1{{.*}}.o # CATCAT: warning: method '-m2' has conflicting definitions: # CATCAT-NEXT: >>> defined in category Cat2 from {{.*}}cat2{{.*}}.o # CATCAT-NEXT: >>> defined in category Cat1 from {{.*}}cat1{{.*}}.o #--- cat1.s .include "objc-macros.s" ## @interface Foo(Cat1) ## -(void) m1; ## -(void) m2; ## +(void) s1; ## +(void) s2; ## @end ## ## @implementation Foo(Cat1) ## -(void) m1 {} ## -(void) m2 {} ## +(void) s1 {} ## +(void) s2 {} ## @end .section __DATA,__objc_catlist,regular,no_dead_strip .quad __OBJC_$_CATEGORY_Foo_$_Cat1 .ifdef MAKE_LOAD_METHOD .section __DATA,__objc_nlcatlist,regular,no_dead_strip .quad __OBJC_$_CATEGORY_Foo_$_Cat1 .endif .section __DATA,__objc_const __OBJC_$_CATEGORY_Foo_$_Cat1: .objc_classname "Cat1" .quad _OBJC_CLASS_$_Foo .quad __OBJC_$_CATEGORY_INSTANCE_METHODS_Foo_$_Cat1 .quad __OBJC_$_CATEGORY_CLASS_METHODS_Foo_$_Cat1 .quad 0 .quad 0 .quad 0 .long 64 .space 4 __OBJC_$_CATEGORY_INSTANCE_METHODS_Foo_$_Cat1: .long 24 # size of method entry .long 2 # number of methods .empty_objc_method "m1", "v16@0:8", "-[Foo(Cat1) m1]" .empty_objc_method "m2", "v16@0:8", "-[Foo(Cat2) m2]" __OBJC_$_CATEGORY_CLASS_METHODS_Foo_$_Cat1: .long 24 .ifdef MAKE_LOAD_METHOD .long 3 .empty_objc_method "load", "v16@0:8", "+[Foo(Cat1) load]" .else .long 2 .endif .empty_objc_method "s1", "v16@0:8", "+[Foo(Cat1) s1]" .empty_objc_method "s2", "v16@0:8", "+[Foo(Cat1) s2]" .section __DATA,__objc_imageinfo,regular,no_dead_strip .long 0 .long 64 .subsections_via_symbols #--- cat2.s .include "objc-macros.s" ## @interface Foo(Cat2) ## -(void) m2; ## +(void) s2; ## @end ## ## @implementation Foo(Cat2) ## -(void) m2 {} ## +(void) s2 {} ## @end .section __DATA,__objc_catlist,regular,no_dead_strip .quad __OBJC_$_CATEGORY_Foo_$_Cat2 .ifdef MAKE_LOAD_METHOD .section __DATA,__objc_nlcatlist,regular,no_dead_strip .quad __OBJC_$_CATEGORY_Foo_$_Cat2 .endif .section __DATA,__objc_const __OBJC_$_CATEGORY_Foo_$_Cat2: .objc_classname "Cat2" .quad _OBJC_CLASS_$_Foo .quad __OBJC_$_CATEGORY_INSTANCE_METHODS_Foo_$_Cat2 .quad __OBJC_$_CATEGORY_CLASS_METHODS_Foo_$_Cat2 .quad 0 .quad 0 .quad 0 .long 64 .space 4 __OBJC_$_CATEGORY_INSTANCE_METHODS_Foo_$_Cat2: .long 24 .long 1 .empty_objc_method "m2", "v16@0:8", "-[Foo(Cat2) m2]" __OBJC_$_CATEGORY_CLASS_METHODS_Foo_$_Cat2: .long 24 .ifdef MAKE_LOAD_METHOD .long 2 .empty_objc_method "load", "v16@0:8", "+[Foo(Cat2) load]" .else .long 1 .endif .empty_objc_method "s2", "v16@0:8", "+[Foo(Cat2) m2]" .section __DATA,__objc_imageinfo,regular,no_dead_strip .long 0 .long 64 .subsections_via_symbols #--- klass.s .include "objc-macros.s" ## @interface Foo ## -(void) m1; ## +(void) s1; ## @end ## ## @implementation Foo ## -(void) m1 {} ## +(void) s1 {} ## @end .globl _OBJC_CLASS_$_Foo, _OBJC_METACLASS_$_Foo .section __DATA,__objc_data _OBJC_CLASS_$_Foo: .quad _OBJC_METACLASS_$_Foo .quad 0 .quad __objc_empty_cache .quad 0 .quad __OBJC_CLASS_RO_$_Foo _OBJC_METACLASS_$_Foo: .quad _OBJC_METACLASS_$_Foo .quad _OBJC_CLASS_$_Foo .quad __objc_empty_cache .quad 0 .quad __OBJC_METACLASS_RO_$_Foo .section __DATA,__objc_const __OBJC_METACLASS_RO_$_Foo: .long 3 .long 40 .long 40 .space 4 .quad 0 .objc_classname "Foo" .quad __OBJC_$_CLASS_METHODS_Foo .quad 0 .quad 0 .quad 0 .quad 0 __OBJC_CLASS_RO_$_Foo: .long 2 .long 0 .long 0 .space 4 .quad 0 .objc_classname "Foo" .quad __OBJC_$_INSTANCE_METHODS_Foo .quad 0 .quad 0 .quad 0 .quad 0 __OBJC_$_CLASS_METHODS_Foo: .long 24 .ifdef MAKE_LOAD_METHOD .long 2 .empty_objc_method "load", "v16@0:8", "+[Foo load]" .else .long 1 .endif .empty_objc_method "s1", "v16@0:8", "+[Foo s1]" __OBJC_$_INSTANCE_METHODS_Foo: .long 24 .long 1 .empty_objc_method "m1", "v16@0:8", "-[Foo m1]" .section __DATA,__objc_classlist,regular,no_dead_strip .quad _OBJC_CLASS_$_Foo .ifdef MAKE_LOAD_METHOD .section __DATA,__objc_nlclslist,regular,no_dead_strip .quad _OBJC_CLASS_$_Foo .endif .section __DATA,__objc_imageinfo,regular,no_dead_strip .long 0 .long 64 .subsections_via_symbols #--- klass-with-no-rodata.s .include "objc-macros.s" ## swiftc generates some classes without a statically-linked rodata. Not ## entirely sure what the corresponding Swift inputs are required for this to ## happen; this test merely checks that we can gracefully handle this case ## without crashing. ## FIXME: It would be better if this test used the output of some real Swift ## code. .globl _$s11FooAACfD .section __DATA,__objc_data _$s11FooAACfD: .quad _$s11FooAACfD .quad 0 .quad __objc_empty_cache .quad 0 .quad __objc_empty_cache .section __DATA,__objc_catlist,regular,no_dead_strip .quad __CATEGORY_METAFoo_$_Foo20 .section __DATA,__objc_const __CATEGORY_METAFoo_$_Foo20: .objc_classname "Foo20" .quad _$s11FooAACfD .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 .long 64 .space 4 #--- objc-macros.s # Macros for taking some of the boilerplate out of defining objc structs. # NOTE: \@ below is a variable that gets auto-incremented by the assembler on # each macro invocation. It serves as a mechanism for generating unique symbol # names for each macro call. .macro .objc_classname name .section __TEXT,__objc_classname,cstring_literals L_OBJC_CLASS_NAME_.\@: .asciz "\name" .section __DATA,__objc_const .quad L_OBJC_CLASS_NAME_.\@ .endm # struct method_t { # const char *name; # const char *type; # void *impl; # } .macro .objc_method name, type, impl .section __TEXT,__objc_methname,cstring_literals L_OBJC_METH_VAR_NAME_.\@: .asciz "\name" .section __TEXT,__objc_methtype,cstring_literals L_OBJC_METH_VAR_TYPE_.\@: .asciz "\type" .section __DATA,__objc_const .quad L_OBJC_METH_VAR_NAME_.\@ .quad L_OBJC_METH_VAR_TYPE_.\@ .quad "\impl" .endm # Generate a method_t with a basic impl that just contains `ret`. .macro .empty_objc_method name, type, impl .text "\impl": ret .objc_method "\name", "\type", "\impl" .endm