[qfcc] Add a failing test case for if-super calls

The common idiom for self init (below) causes a double-call when
compiling with --advanced, resulting in an incorrect retain count.

    if (!(self = [super init])) {
	return nil;
    }
This commit is contained in:
Bill Currie 2022-11-12 20:07:30 +09:00
parent 2d3c2da64d
commit bfda4e776f
3 changed files with 69 additions and 0 deletions

View file

@ -29,6 +29,7 @@ test_progs_dat=\
tools/qfcc/test/func-expr2.dat \
tools/qfcc/test/func-static.dat \
tools/qfcc/test/gcd.dat \
tools/qfcc/test/ifsuper.dat \
tools/qfcc/test/infloop.dat \
tools/qfcc/test/iterfunc.dat \
tools/qfcc/test/ivar-struct-return.dat \
@ -369,6 +370,16 @@ tools/qfcc/test/gcd.run: $(qfcc_test_run_deps)
include $(gcd_dep) # am--include-marker
pas_depfiles_remade += $(gcd_dep)
tools_qfcc_test_ifsuper_dat_SOURCES=tools/qfcc/test/ifsuper.r
ifsuper_obj=$(tools_qfcc_test_ifsuper_dat_SOURCES:.r=.o)
ifsuper_dep=$(call qcautodep,$(tools_qfcc_test_ifsuper_dat_SOURCES))
tools/qfcc/test/ifsuper.dat$(EXEEXT): $(ifsuper_obj) $(QFCC_DEP)
$(V_QFCCLD)$(QLINK) --advanced -o $@ $(ifsuper_obj)
tools/qfcc/test/ifsuper.run: $(qfcc_test_run_deps)
@$(top_srcdir)/tools/qfcc/test/build-run $@
include $(ifsuper_dep) # am--include-marker
r_depfiles_remade += $(ifsuper_dep)
tools_qfcc_test_infloop_dat_SOURCES=tools/qfcc/test/infloop.r
infloop_obj=$(tools_qfcc_test_infloop_dat_SOURCES:.r=.o)
infloop_dep=$(call qcautodep,$(tools_qfcc_test_infloop_dat_SOURCES))

56
tools/qfcc/test/ifsuper.r Normal file
View file

@ -0,0 +1,56 @@
#pragma advanced
#include "test-harness.h"
int obj_increment_retaincount (id object) = #0;
int obj_get_retaincount (id object) = #0;
id (Class class) class_create_instance = #0;
id obj_msgSend_super (Super *class, SEL op, ...) = #0;
@interface Object
{
Class isa;
}
+(id) alloc;
-(id) init;
@end
@interface Foo : Object
-(id) init;
@end
@implementation Object
+(id) alloc
{
return class_create_instance (self);
}
-(id) init
{
obj_increment_retaincount (self);
return self;
}
@end
@implementation Foo
-(id) init
{
if (!(self = [super init])) {
return nil;
}
return self;
}
@end
int main ()
{
Foo *foo = [[Foo alloc] init];
if (!foo) {
printf ("foo is nil\n");
return 1;
}
int retain = obj_get_retaincount (foo);
if (retain != 1) {
printf ("retain count != 1: %d\n", retain);
return 1;
}
return 0;
}

View file

@ -3,6 +3,8 @@ void printf (string fmt, ...) = #0;
int errno (void) = #0;
string strerror (int err) = #0;
void exit (int code) = #0;
void traceon (void) = #0;
void traceoff (void) = #0;
entity spawn (void) = #0;
void remove (entity e) = #0;
id obj_msgSend (id receiver, SEL op, ...) = #0;