diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /gcc/testsuite/objc.dg | |
download | cbb-gcc-4.6.4-upstream.tar.bz2 cbb-gcc-4.6.4-upstream.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'gcc/testsuite/objc.dg')
423 files changed, 23076 insertions, 0 deletions
diff --git a/gcc/testsuite/objc.dg/alias.m b/gcc/testsuite/objc.dg/alias.m new file mode 100644 index 000000000..a57d032eb --- /dev/null +++ b/gcc/testsuite/objc.dg/alias.m @@ -0,0 +1,12 @@ +/* Test alias warnings. */ +/* { dg-do compile } */ + +@compatibility_alias class1 class2; /* { dg-warning "annot find class" } */ + +@interface class3; +@end + +@interface class4; +@end + +@compatibility_alias class4 class3; /* { dg-warning "lass" "already exists" } */ diff --git a/gcc/testsuite/objc.dg/anon-1.m b/gcc/testsuite/objc.dg/anon-1.m new file mode 100644 index 000000000..5f10f7d60 --- /dev/null +++ b/gcc/testsuite/objc.dg/anon-1.m @@ -0,0 +1,14 @@ +/* Test for graceful handling of anonymous ivars. */ +/* { dg-do compile } */ + +@interface Foo { + unsigned char : 1; + int e: 3; + signed: 2; + float f; +} +@end + +@implementation Foo +@end + diff --git a/gcc/testsuite/objc.dg/at-class-1.m b/gcc/testsuite/objc.dg/at-class-1.m new file mode 100644 index 000000000..63721aa99 --- /dev/null +++ b/gcc/testsuite/objc.dg/at-class-1.m @@ -0,0 +1,11 @@ +/* Test @class. */ +/* { dg-do compile } */ + +@class Object; /* Ok */ + +@class Object, ; /* { dg-error "expected identifier" } */ +@class Object, ; /* { dg-error "expected identifier" } */ +@class Object, AnotherObject, ; /* { dg-error "expected identifier" } */ +@class Object, AnotherObject, TestObject ; /* Ok */ + +@class Object /* { dg-error "expected .;." } */ diff --git a/gcc/testsuite/objc.dg/attributes/attributes.exp b/gcc/testsuite/objc.dg/attributes/attributes.exp new file mode 100644 index 000000000..cb11216c5 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/attributes.exp @@ -0,0 +1,44 @@ +# Copyright (C) 2010 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Load support procs. + +load_lib objc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS "" +} + +# Initialize `dg'. +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]] + +# Main loop. +dg-runtest $tests "-fgnu-runtime" $DEFAULT_CFLAGS + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { + dg-runtest $tests "-fnext-runtime" $DEFAULT_CFLAGS +} + +# All done. +dg-finish diff --git a/gcc/testsuite/objc.dg/attributes/categ-attribute-1.m b/gcc/testsuite/objc.dg/attributes/categ-attribute-1.m new file mode 100644 index 000000000..e9fe9c986 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/categ-attribute-1.m @@ -0,0 +1,31 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> +#include "../../objc-obj-c++-shared/Object1.h" + +@interface obj : Object { +@public + int var; +} +- (int) mth; +@end + +@implementation obj +- (int) mth { return var; } +@end + +__attribute ((deprecated)) +@interface obj (dep_categ) +- (int) depmth;/* { dg-warning "category attributes are not available in this version" } */ +@end + +@implementation obj (dep_categ) +- (int) depmth { return var + 1; } +@end + +int foo (void) +{ + obj *p = [obj new]; + int q = [p depmth]; + return [p mth]; +} diff --git a/gcc/testsuite/objc.dg/attributes/categ-attribute-2.m b/gcc/testsuite/objc.dg/attributes/categ-attribute-2.m new file mode 100644 index 000000000..4a98de130 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/categ-attribute-2.m @@ -0,0 +1,32 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> +#include "../../objc-obj-c++-shared/Object1.h" + +@interface obj : Object { +@public + int var; +} +- (int) mth; +@end + +@implementation obj +- (int) mth { return var; } +@end + +__attribute__ ((deprecated("no dep_categ"))) +@interface obj (dep_categ) +- (int) depmth;/* { dg-warning "category attributes are not available in this version" } */ +@end + +__attribute__ ((deprecated)) +@implementation obj (dep_categ) /* { dg-warning "prefix attributes are ignored for implementations" } */ +- (int) depmth { return var + 1; } +@end + +int foo (void) +{ + obj *p = [obj new]; + int q = [p depmth]; + return [p mth]; +} diff --git a/gcc/testsuite/objc.dg/attributes/class-attribute-1.m b/gcc/testsuite/objc.dg/attributes/class-attribute-1.m new file mode 100644 index 000000000..3444760bc --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/class-attribute-1.m @@ -0,0 +1,59 @@ +/* { dg-do compile } */ + +/* Test deprecate attribute with an @interface declaration. */ + +#include <objc/objc.h> + +__attribute__ ((deprecated)) +@interface DeprecatedClass +{ + Class isa; +} ++ (id) classObject; ++ (id) new; +@end + +@implementation DeprecatedClass ++ (id) classObject { return self; } ++ (id) new { return nil; } +@end + +@interface DeprecatedClass (Category) +@end /* { dg-warning "is deprecated" } */ + +@interface Subclass : DeprecatedClass +@end /* { dg-warning "is deprecated" } */ + +DeprecatedClass *object; /* { dg-warning "is deprecated" } */ + +int function (DeprecatedClass *object) /* { dg-warning "is deprecated" } */ +{ + /* Note how the following deprecation warning is generated by + "DeprecatedClass *", not by "[DeprecatedClass ...]. */ + DeprecatedClass *x = [DeprecatedClass new]; /* { dg-warning "is deprecated" } */ + + if (x == object) + return 0; + else + return 1; +} + +id function2 (void) +{ + return DeprecatedClass.classObject; /* { dg-warning "is deprecated" } */ +} + +@interface NormalClass +{ + Class isa; + DeprecatedClass *object; /* { dg-warning "is deprecated" } */ +} +- (DeprecatedClass *)method; /* { dg-warning "is deprecated" } */ +@end + +@implementation NormalClass +- (DeprecatedClass *)method /* { dg-warning "is deprecated" } */ +{ + return nil; +} +@end diff --git a/gcc/testsuite/objc.dg/attributes/class-attribute-2.m b/gcc/testsuite/objc.dg/attributes/class-attribute-2.m new file mode 100644 index 000000000..2e1bacb3f --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/class-attribute-2.m @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> + +__attribute__ ((deprecated)) +@interface DeprecatedClass +{ + Class isa; +} ++ (id) new; +@end + +__attribute__ ((deprecated)) +@implementation DeprecatedClass /* { dg-warning "prefix attributes are ignored for implementations" } */ ++ (id) new { return nil; } +@end + +void function (void) +{ + DeprecatedClass *object = [DeprecatedClass new]; /* { dg-warning "is deprecated" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/class-attribute-3.m b/gcc/testsuite/objc.dg/attributes/class-attribute-3.m new file mode 100644 index 000000000..6cc5d4e26 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/class-attribute-3.m @@ -0,0 +1,14 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +/* Test that you get a warning when an unknown class attribute is ignored. */ + +#include <objc/objc.h> + +__attribute__ ((unknown_attribute)) +@interface MyClass +{ /* { dg-warning "ignored" } */ + Class isa; +} ++ (id) new; +@end diff --git a/gcc/testsuite/objc.dg/attributes/invalid-attribute-1.m b/gcc/testsuite/objc.dg/attributes/invalid-attribute-1.m new file mode 100644 index 000000000..ec17e9d71 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/invalid-attribute-1.m @@ -0,0 +1,6 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, January 2011. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +__attribute__ ((deprecated)) @class A; /* { dg-error "unexpected attribute before .class." } */ diff --git a/gcc/testsuite/objc.dg/attributes/method-attribute-1.m b/gcc/testsuite/objc.dg/attributes/method-attribute-1.m new file mode 100644 index 000000000..ffe72e20f --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-attribute-1.m @@ -0,0 +1,40 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> +#include "../../objc-obj-c++-shared/Object1.h" + +@interface obj : Object { +@public + int var; +} +- (int) mth; ++ (id) dep_cls_mth __attribute__((deprecated)) ; +- (int) dep_ins_mth __attribute__((deprecated)) ; +- (int) dep_ins_mtharg: (int) i __attribute__((deprecated)) ; +- (int) dep_ins_mtharg1: (int) i __attribute__((deprecated)) add: (int) j;/* { dg-error "expected ';' or '\{' after method attribute definition" } */ +- (int) nodef __attribute__((deprecated)) { return var-2; } ; /* { dg-error "expected ';' before '\{' token" } */ +__attribute__((deprecated)) +- (int) bad_pref_mth; /* { dg-warning "prefix attributes are ignored for methods" } */ +@end + +@implementation obj +- (int) mth { return var; } ++ (id) dep_cls_mth { return self; } +- (int) dep_ins_mth { return var ; } +- (int) dep_ins_mtharg: (int) i { return var + i ; } +- (int) dep_ins_mtharg1: (int) i add: (int) j { return var + i + j ; } +- (int) bad_pref_mth { return var; }; +- (int) nodef { return var-2; } ; +@end + +int foo (void) +{ + obj *p = [obj new]; + id n = [obj dep_cls_mth]; /* { dg-warning "is deprecated" } */ + + [p dep_ins_mth]; /* { dg-warning "is deprecated" } */ + [p dep_ins_mtharg:2]; /* { dg-warning "is deprecated" } */ + [p dep_ins_mtharg1:3 add:3]; + + return [p mth]; +} diff --git a/gcc/testsuite/objc.dg/attributes/method-attribute-2.m b/gcc/testsuite/objc.dg/attributes/method-attribute-2.m new file mode 100644 index 000000000..4a56b3aa8 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-attribute-2.m @@ -0,0 +1,33 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> +#include "../../objc-obj-c++-shared/Object1.h" + +@interface obj : Object { +@public + int var; +} +- (int) depmth __attribute__((deprecated)); +- (int) depmtharg:(int) iarg __attribute__((deprecated)); +- (int) unusedarg:(int) __attribute__((unused)) uarg ; +- (int) depunusedarg:(int) __attribute__((unused)) uarg __attribute__((deprecated)) ; +@end + +@implementation obj +- (int) depmth __attribute__((deprecated)) { return var; } /* { dg-warning "method attributes can not be specified in @implementation context" } */ +- (int) depmtharg:(int) iarg { return var + iarg ; } +- (int) unusedarg:(int) __attribute__((unused)) uarg { return var; } +- (int) depunusedarg:(int) __attribute__((unused)) uarg { return var; } +@end + +int foo (void) +{ + obj *p = [obj new]; + + [p depmth]; /* { dg-warning "is deprecated" } */ + [p depmtharg:1]; /* { dg-warning "is deprecated" } */ + [p unusedarg:2]; /* { dg-bogus "is deprecated" } */ + [p depunusedarg:3 ]; /* { dg-warning "is deprecated" } */ + + return [p depmtharg:0]; /* { dg-warning "is deprecated" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-attribute-3.m b/gcc/testsuite/objc.dg/attributes/method-attribute-3.m new file mode 100644 index 000000000..de607a3d9 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-attribute-3.m @@ -0,0 +1,24 @@ +/* { dg-do compile } */ + +#include "../../objc-obj-c++-shared/Object1.h" + +@interface obj : Object { +@public + int var; +} +- (int) vargsn: (int) count, ... __attribute__((deprecated)); +@end + +@implementation obj +- (int) vargsn: (int) count, ... +{ + return 0; +} +@end + +int foo (void) +{ + obj *p = [obj new]; + + return [p vargsn:0]; /* { dg-warning "'vargsn:' is deprecated .declared at " } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-deprecated-1.m b/gcc/testsuite/objc.dg/attributes/method-deprecated-1.m new file mode 100644 index 000000000..8343856a5 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-deprecated-1.m @@ -0,0 +1,33 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) method; +- (int) method; ++ (int) deprecatedClassMethod __attribute__((deprecated)); +- (int) deprecatedInstanceMethod __attribute__((deprecated)); +@end + +/* Test that deprecation warnings are produced, but not if the + receiver is of type 'id'. */ +void foo (void) +{ + Class c; + id object; + MyClass *another_object; + + [c method]; + [object method]; + [c deprecatedClassMethod]; + [object deprecatedInstanceMethod]; + + [object method]; + [another_object method]; + [MyClass deprecatedClassMethod]; /* { dg-warning "is deprecated" } */ + [another_object deprecatedInstanceMethod]; /* { dg-warning "is deprecated" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-deprecated-2.m b/gcc/testsuite/objc.dg/attributes/method-deprecated-2.m new file mode 100644 index 000000000..1e5d87f3e --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-deprecated-2.m @@ -0,0 +1,23 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) deprecatedClassMethod: (id)firstObject, ... __attribute__((sentinel)) __attribute__((deprecated)); +- (int) deprecatedInstanceMethod: (id)firstobject, ... __attribute__((sentinel)) __attribute__((deprecated)); +@end + +/* Test that deprecation warnings are produced even if the method is + also marked with another attribute too (this is to test the + processing of multiple attributes). */ +void foo (void) +{ + MyClass *object = nil; + + [MyClass deprecatedClassMethod: object, nil]; /* { dg-warning "is deprecated" } */ + [object deprecatedInstanceMethod: object, nil]; /* { dg-warning "is deprecated" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-deprecated-3.m b/gcc/testsuite/objc.dg/attributes/method-deprecated-3.m new file mode 100644 index 000000000..5c715a20b --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-deprecated-3.m @@ -0,0 +1,21 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test that __attribute__ ((__deprecated__)) works as well as __attribute__ ((deprecated)). */ +@interface MyClass +{ + Class isa; +} ++ (int) deprecatedClassMethod: (id)firstObject, ... __attribute__((__deprecated__)); +- (int) deprecatedInstanceMethod: (id)firstobject, ... __attribute__((__deprecated__)); +@end + +void foo (void) +{ + MyClass *object = nil; + + [MyClass deprecatedClassMethod: object, nil]; /* { dg-warning "is deprecated" } */ + [object deprecatedInstanceMethod: object, nil]; /* { dg-warning "is deprecated" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-format-1.m b/gcc/testsuite/objc.dg/attributes/method-format-1.m new file mode 100644 index 000000000..11ce8eebb --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-format-1.m @@ -0,0 +1,43 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +#include <objc/objc.h> +#include <stdlib.h> + +@interface LogObject +{ + Class isa; +} ++ (void) log: (int)level message: (const char *) my_format, ... __attribute__ ((format (printf, 2, 3))); +- (void) log: (int)level message: (const char *) my_format, ... __attribute__ ((format (printf, 2, 3))); + ++ (void) debug: (const char *) my_format, ... __attribute__ ((format (printf, 1, 2))); +- (void) debug: (const char *) my_format, ... __attribute__ ((format (printf, 1, 2))); + +/* Just make sure a missing or invalid attribute won't crash the compiler. */ +- (void) log2: (int)level message: (const char *) my_format, ... __attribute__ ((format (printf, 2))); /* { dg-error "wrong" } */ ++ (void) debug2: (const char *) my_format, ... __attribute__ ((format (printf))); /* { dg-error "wrong" } */ +- (void) debug2: (const char *) my_format, ... __attribute__ ((format (printf))); /* { dg-error "wrong" } */ ++ (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */ +- (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */ +@end + +void test (LogObject *object) +{ + [object log: 2 message: "attribute only applies to variadic functions"]; + [object log: 2 message: "attribute %s only applies to variadic functions", "'format'"]; + [object log: 2 message: "attribute %s only applies to variadic functions"]; /* { dg-warning "expects a matching" } */ + + [object debug: "attribute only applies to variadic functions"]; + [object debug: "attribute %s only applies to variadic functions", "'format'"]; + [object debug: "attribute %s only applies to variadic functions"]; /* { dg-warning "expects a matching" } */ + + [LogObject log: 2 message: "attribute only applies to variadic functions"]; + [LogObject log: 2 message: "attribute %s only applies to variadic functions", "'format'"]; + [LogObject log: 2 message: "attribute %s only applies to variadic functions"]; /* { dg-warning "expects a matching" } */ + + [LogObject debug: "attribute only applies to variadic functions"]; + [LogObject debug: "attribute %s only applies to variadic functions", "'format'"]; + [LogObject debug: "attribute %s only applies to variadic functions"]; /* { dg-warning "expects a matching" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-noreturn-1.m b/gcc/testsuite/objc.dg/attributes/method-noreturn-1.m new file mode 100644 index 000000000..717d6e65e --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-noreturn-1.m @@ -0,0 +1,34 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> +#include <stdlib.h> + +@interface MyClass +{ + Class isa; +} ++ (id) method1 __attribute__ ((noreturn)); +- (id) method2 __attribute__ ((noreturn)); ++ (id) method3 __attribute__ ((noreturn)); +- (id) method4 __attribute__ ((noreturn)); +@end + +@implementation MyClass ++ (id) method1 +{ + return self; /* { dg-warning "function declared .noreturn. has a .return. statement" } */ +} /* { dg-warning ".noreturn. function does return" "" { target *-*-* } 20 } */ +- (id) method2 +{ + return self; /* { dg-warning "function declared .noreturn. has a .return. statement" } */ +} /* { dg-warning ".noreturn. function does return" "" { target *-*-* } 24 } */ ++ (id) method3 +{ + abort (); +} +- (id) method4 +{ + abort (); +} +@end diff --git a/gcc/testsuite/objc.dg/attributes/method-sentinel-1.m b/gcc/testsuite/objc.dg/attributes/method-sentinel-1.m new file mode 100644 index 000000000..e2abb1e8a --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-sentinel-1.m @@ -0,0 +1,35 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +#include <objc/objc.h> +#include <stdlib.h> +#include "../../objc-obj-c++-shared/objc-test-suite-types.h" + +@interface NSArray +{ + Class isa; +} ++ (id) arrayWithObject: (id)object __attribute__ ((sentinel)); /* { dg-warning "attribute only applies to variadic functions" } */ ++ (id) arrayWithObjects: (id)firstObject, ... __attribute__ ((sentinel)); + +- (id) initWithObject: (id)object __attribute__ ((sentinel)); /* { dg-warning "attribute only applies to variadic functions" } */ +- (id) initWithObjects: (id)firstObject, ... __attribute__ ((sentinel)); +@end + +void test (id object) +{ + NSArray *array; + + array = [NSArray arrayWithObject: object]; + array = [NSArray arrayWithObjects: object, nil]; + array = [NSArray arrayWithObjects: object, object, nil]; + array = [NSArray arrayWithObjects: object]; /* { dg-warning "not enough variable arguments" } */ + array = [NSArray arrayWithObjects: object, object]; /* { dg-warning "missing sentinel" } */ + + [array initWithObject: object]; + [array initWithObjects: object, nil]; + [array initWithObjects: object, object, nil]; + [array initWithObjects: object]; /* { dg-warning "not enough variable arguments" } */ + [array initWithObjects: object, object]; /* { dg-warning "missing sentinel" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/objc-exception-1.m b/gcc/testsuite/objc.dg/attributes/objc-exception-1.m new file mode 100644 index 000000000..e7f6f856f --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/objc-exception-1.m @@ -0,0 +1,32 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, February 2011. */ +/* { dg-do compile } */ + +/* Test that the 'objc_exception' attribute is accepted for + @interfaces, but not for anything else. */ + +#include <objc/objc.h> + +/* Fine. */ +__attribute__ ((objc_exception)) +@interface MyClass +{ + Class isa; +} +@end + +/* Fine. */ +__attribute__ ((__objc_exception__)) +@interface MyClass2 +{ + Class isa; +} +@end + +__attribute__ ((objc_exception)) +@protocol MyProtocol; /* { dg-warning "ignored" } */ + +__attribute__ ((objc_exception)) +int myVariable; /* { dg-warning "ignored" } */ + +__attribute__ ((objc_exception)) +int myFunction (int argument); /* { dg-warning "ignored" } */ diff --git a/gcc/testsuite/objc.dg/attributes/parameter-attribute-1.m b/gcc/testsuite/objc.dg/attributes/parameter-attribute-1.m new file mode 100644 index 000000000..8263df66d --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/parameter-attribute-1.m @@ -0,0 +1,45 @@ +/* Test __attribute__((unused)) for an Objective-C method parameter. */ +/* { dg-do compile } */ +/* { dg-options "-Wunused-parameter" } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +- (id) method1: (id) argument1; +- (id) method2: (id) __attribute__((unused)) argument1; +- (id) method3: (id) __attribute__((unused)) argument1 + andArgument: (id) argument2; +- (id) method4: (id) __attribute__((unused)) argument1 + andArgument: (id) __attribute__((unused)) argument2; +- (id) method5: (id) argument1 + andArgument: (id) __attribute__ ((unused)) argument2; +@end + +@implementation MyRootClass +- (id) method1: (id) argument1 +{ /* { dg-warning "unused parameter .argument1." } */ + return nil; +} +- (id) method2: (id) __attribute__((unused)) argument1 +{ + return nil; +} +- (id) method3: (id) __attribute__((unused)) argument1 + andArgument: (id) argument2 +{ /* { dg-warning "unused parameter .argument2." } */ + return nil; +} +- (id) method4: (id) __attribute__((unused)) argument1 + andArgument: (id) __attribute__((unused)) argument2 +{ + return nil; +} +- (id) method5: (id) argument1 + andArgument: (id) __attribute__ ((unused)) argument2 +{ /* { dg-warning "unused parameter .argument1." } */ + return nil; +} +@end diff --git a/gcc/testsuite/objc.dg/attributes/parameter-attribute-2.m b/gcc/testsuite/objc.dg/attributes/parameter-attribute-2.m new file mode 100644 index 000000000..99c5a308b --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/parameter-attribute-2.m @@ -0,0 +1,25 @@ +/* Test that we get warnings for unrecognized attributes. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +/* TODO: Emit warnings in the @interface as well. Currently we only emit + them in @implementation. */ ++ (id) method1: (id) __attribute__ ((xxxxx)) argument1; ++ (id) method2: (id) __attribute__ ((noinline)) argument1; +@end + +@implementation MyRootClass ++ (id) method1: (id) __attribute__ ((xxxxx)) argument1 +{ /* { dg-warning ".xxxxx. attribute directive ignored" } */ + return argument1; +} ++ (id) method2: (id) __attribute__ ((noinline)) argument1 +{ /* { dg-warning ".noinline. attribute ignored" } */ + return argument1; +} +@end diff --git a/gcc/testsuite/objc.dg/attributes/proto-attribute-1.m b/gcc/testsuite/objc.dg/attributes/proto-attribute-1.m new file mode 100644 index 000000000..a852a7a6c --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/proto-attribute-1.m @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> + +__attribute ((deprecated)) +@protocol dep_proto +- (int) depprotomth; +@end + +@interface obj <dep_proto> /* { dg-warning "is deprecated" } */ +{ +@public + int var; +} +- (int) mth; +@end + +@implementation obj +- (int) mth { return var; } +- (int) depprotomth { return var + 1; } +@end diff --git a/gcc/testsuite/objc.dg/attributes/proto-attribute-2.m b/gcc/testsuite/objc.dg/attributes/proto-attribute-2.m new file mode 100644 index 000000000..b23b81de2 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/proto-attribute-2.m @@ -0,0 +1,31 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test deprecate attribute with a forward declarations of + @protocol. */ + +#include <stdlib.h> +#include <objc/objc.h> + +__attribute__ ((deprecated)) +@protocol DeprecatedProtocol1; + +@protocol NonDeprecatedProtocol1; + +void function1 (id <DeprecatedProtocol1> object); /* { dg-warning "is deprecated" } */ +void function2 (id <NonDeprecatedProtocol1> object); + +@class Class4; + +void function3 (Class4 <DeprecatedProtocol1> *object); /* { dg-warning "is deprecated" } */ +void function4 (Class4 <NonDeprecatedProtocol1> *object); +void function5 (Class4 <NonDeprecatedProtocol1, DeprecatedProtocol1> *object); /* { dg-warning "is deprecated" } */ + +int function6 (void) +{ + Protocol *p1 = @protocol (DeprecatedProtocol1); /* { dg-warning "is deprecated" } */ + Protocol *p2 = @protocol (NonDeprecatedProtocol1); + + return (p1 == p2); +} + diff --git a/gcc/testsuite/objc.dg/attributes/proto-attribute-3.m b/gcc/testsuite/objc.dg/attributes/proto-attribute-3.m new file mode 100644 index 000000000..2be286ecf --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/proto-attribute-3.m @@ -0,0 +1,59 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test deprecate attribute with normal @protocol declarations. */ + + +#include <stdlib.h> +#include <objc/objc.h> + +__attribute__ ((deprecated)) +@protocol DeprecatedProtocol1 +- (void) aMethod; +@end + +@protocol NonDeprecatedProtocol1 +- (void) anotherMethod; +@end + +@protocol Protocol2 <DeprecatedProtocol1> /* { dg-warning "is deprecated" } */ +- (void) someOtherMethod; +@end + +@protocol Protocol3 <NonDeprecatedProtocol1> +- (void) someOtherMethod2; +@end + +@protocol Protocol4 <NonDeprecatedProtocol1, DeprecatedProtocol1> /* { dg-warning "is deprecated" } */ +- (void) someOtherMethod3; +@end + + +@interface Class1 <DeprecatedProtocol1> /* { dg-warning "is deprecated" } */ +@end + +@interface Class2 <NonDeprecatedProtocol1> +@end + +@interface Class3 <NonDeprecatedProtocol1, DeprecatedProtocol1> /* { dg-warning "is deprecated" } */ +@end + +@interface Class2 (Category1) <DeprecatedProtocol1> /* { dg-warning "is deprecated" } */ +@end + +void function1 (id <DeprecatedProtocol1> object); /* { dg-warning "is deprecated" } */ +void function2 (id <NonDeprecatedProtocol1> object); + +@class Class4; + +void function3 (Class4 <DeprecatedProtocol1> *object); /* { dg-warning "is deprecated" } */ +void function4 (Class4 <NonDeprecatedProtocol1> *object); +void function5 (Class4 <NonDeprecatedProtocol1, DeprecatedProtocol1> *object); /* { dg-warning "is deprecated" } */ + +int function6 (void) +{ + Protocol *p1 = @protocol (DeprecatedProtocol1); /* { dg-warning "is deprecated" } */ + Protocol *p2 = @protocol (NonDeprecatedProtocol1); + + return (p1 == p2); +} diff --git a/gcc/testsuite/objc.dg/attributes/proto-attribute-4.m b/gcc/testsuite/objc.dg/attributes/proto-attribute-4.m new file mode 100644 index 000000000..226fd68b3 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/proto-attribute-4.m @@ -0,0 +1,31 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +/* Test that you get a warning when an unknown protocol attribute is ignored. */ + +#include <objc/objc.h> + +__attribute__ ((unknown_attribute)) +@protocol MyProtocol +- (id) new; /* { dg-warning "ignored" } */ +@end + +__attribute__ ((unknown_attribute)) +@protocol MyProtocol2; /* { dg-warning "ignored" } */ + +/* Use the protocols to double-check that no more warnings are + generated. */ + +@interface MyClass <MyProtocol> +@end + +int test (id <MyProtocol2> x) +{ + if (@protocol (MyProtocol) == @protocol (MyProtocol2)) + return 1; + + if (x) + return 2; + + return 3; +} diff --git a/gcc/testsuite/objc.dg/bad-receiver-type-2.m b/gcc/testsuite/objc.dg/bad-receiver-type-2.m new file mode 100644 index 000000000..eca8400d5 --- /dev/null +++ b/gcc/testsuite/objc.dg/bad-receiver-type-2.m @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* Contributed by Alexander Malmberg: PR18456 */ + +@interface Foo +-(void) foo; +@end + +void *ip; + +void (*func1)(void); + +struct +{ + int a:2; +} struct1,struct2[2]; + +union +{ + int a:2; +} union1,union2[2]; + +Foo **f; + +int main(int argc,char **argv) +{ + [(struct {int a;} *)ip foo]; /* { dg-warning "invalid receiver type" } */ + [func1 foo]; /* { dg-warning "invalid receiver type" } */ + [struct1.a foo]; /* { dg-warning "invalid receiver type" } */ + /* { dg-warning "cast to pointer from integer" "" { target *-*-* } 28 } */ + [union1.a foo]; /* { dg-warning "invalid receiver type" } */ + /* { dg-warning "cast to pointer from integer" "" { target *-*-* } 30 } */ + [struct1 foo]; /* { dg-warning "invalid receiver type" } */ + /* { dg-error "cannot convert" "" { target *-*-* } 32 } */ + [union1 foo]; /* { dg-warning "invalid receiver type" } */ + /* { dg-error "cannot convert" "" { target *-*-* } 34 } */ + [struct2 foo]; /* { dg-warning "invalid receiver type" } */ + /* { dg-error "cannot convert" "" { target *-*-* } 36 } */ + [union2 foo]; /* { dg-warning "invalid receiver type" } */ + /* { dg-error "cannot convert" "" { target *-*-* } 38 } */ + [f foo]; /* { dg-warning "invalid receiver type" } */ +} diff --git a/gcc/testsuite/objc.dg/bad-receiver-type.m b/gcc/testsuite/objc.dg/bad-receiver-type.m new file mode 100644 index 000000000..8ab296257 --- /dev/null +++ b/gcc/testsuite/objc.dg/bad-receiver-type.m @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +@interface A + +- (void)test; + +@end + +extern int foo(); + +void baz() +{ + [foo test]; /* { dg-warning "invalid receiver type" } */ + /* { dg-error "cannot convert to a pointer type" "" { target *-*-* } 13 } */ +} diff --git a/gcc/testsuite/objc.dg/bitfield-1.m b/gcc/testsuite/objc.dg/bitfield-1.m new file mode 100644 index 000000000..664a0e8d4 --- /dev/null +++ b/gcc/testsuite/objc.dg/bitfield-1.m @@ -0,0 +1,83 @@ +/* Check if bitfield ivars are inherited correctly (i.e., without + being "promoted" to ints). */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include <objc/objc.h> + +extern void abort(void); + +#define CHECK_IF(expr) if(!(expr)) abort(); + +@interface Base: Object +{ + int full; + int full2: 32; + int _refs: 8; + int field2: 3; + unsigned f3: 8; + short cc; + unsigned g: 16; + int r2: 8; + int r3: 8; + int r4: 2; + int r5: 8; + char c; +} +- (void)setValues; +@end + +@interface Derived: Base +{ + char d; + int _field3: 6; +} +- (void)checkValues; +@end + +@implementation Base +-(void)setValues { + full = 1; + full2 = 2; + _refs = 3; + field2 = 1; + f3 = 6; + cc = 7; + g = 8; + r2 = 9; + r3 = 10; + r4 = 1; + r5 = 12; + c = 13; +} +@end + +@implementation Derived +-(void)checkValues { + CHECK_IF(full == 1); + CHECK_IF(full2 == 2); + CHECK_IF(_refs == 3); + CHECK_IF(field2 == 1); + CHECK_IF(f3 == 6); + CHECK_IF(cc == 7); + CHECK_IF(g == 8); + CHECK_IF(r2 == 9); + CHECK_IF(r3 == 10); + CHECK_IF(r4 == 1); + CHECK_IF(r5 == 12); + CHECK_IF(c == 13); +} +@end + +int main(void) { + Derived *obj = [[Derived alloc] init]; + + [obj setValues]; + [obj checkValues]; + + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/bitfield-2.m b/gcc/testsuite/objc.dg/bitfield-2.m new file mode 100644 index 000000000..7e8147a70 --- /dev/null +++ b/gcc/testsuite/objc.dg/bitfield-2.m @@ -0,0 +1,56 @@ +/* Check if bitfield ivars are correctly @encode'd when + the NeXT runtime is used. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-fsigned-char" } */ +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ + +typedef struct objc_object { struct objc_class *class_pointer; } *id; + +extern void abort(void); +extern int strcmp(const char *, const char *); + +#define CHECK_IF(expr) if(!(expr)) abort(); + +@interface Base +{ + struct objc_class *isa; + int full; + int full2: 32; + int _refs: 8; + int field2: 3; + unsigned f3: 8; + short cc; + unsigned g: 16; + int r2: 8; + int r3: 8; + int r4: 2; + int r5: 8; + char c; +} +@end + +@interface Derived: Base +{ + char d; + int _field3: 6; +} +@end + +@implementation Base +@end + +@implementation Derived +@end + +int main(void) { + const char *s1r = "{Base=#ib32b8b3b8sb16b8b8b2b8c}"; + const char *s1 = @encode(Base); + const char *s2r = "{Derived=#ib32b8b3b8sb16b8b8b2b8ccb6}"; + const char *s2 = @encode(Derived); + + CHECK_IF(!strcmp(s1r, s1)); + CHECK_IF(!strcmp(s2r, s2)); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/bitfield-3.m b/gcc/testsuite/objc.dg/bitfield-3.m new file mode 100644 index 000000000..5bea0fca9 --- /dev/null +++ b/gcc/testsuite/objc.dg/bitfield-3.m @@ -0,0 +1,49 @@ +/* Check if the @defs() construct preserves the correct + layout of bitfields. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-Wpadded" } */ +/* { dg-do run } */ + +#include "../objc-obj-c++-shared/Object1.h" + +extern void abort(void); +extern int strcmp(const char *str1, const char *str2); +#define CHECK_IF(expr) if(!(expr)) abort() + +enum Enum { one, two, three, four }; + +@interface Base: Object { + unsigned a: 2; + int b: 3; + enum Enum c: 4; + unsigned d: 5; +} /* { dg-warning "padding struct size to alignment boundary" } */ +@end + +@interface Derived: Base { + signed e: 5; + int f: 4; + enum Enum g: 3; +} /* { dg-warning "padding struct size to alignment boundary" } */ +@end + +/* Note that the semicolon after @defs(...) is optional. */ + +typedef struct { @defs(Base) } Base_t; /* { dg-warning "padding struct size to alignment boundary" } */ +typedef struct { @defs(Derived); } Derived_t; /* { dg-warning "padding struct size to alignment boundary" } */ + +int main(void) +{ + CHECK_IF(sizeof(Base_t) == sizeof(Base)); + CHECK_IF(sizeof(Derived_t) == sizeof(Derived)); + +#ifdef __NEXT_RUNTIME__ + CHECK_IF(!strcmp(@encode(Base), "{Base=#b2b3b4b5}")); + CHECK_IF(!strcmp(@encode(Derived), "{Derived=#b2b3b4b5b5b4b3}")); + + CHECK_IF(!strcmp(@encode(Base_t), "{?=#b2b3b4b5}")); + CHECK_IF(!strcmp(@encode(Derived_t), "{?=#b2b3b4b5b5b4b3}")); +#endif /* __NEXT_RUNTIME__ */ + + return 0; +} diff --git a/gcc/testsuite/objc.dg/bitfield-4.m b/gcc/testsuite/objc.dg/bitfield-4.m new file mode 100644 index 000000000..4883497e8 --- /dev/null +++ b/gcc/testsuite/objc.dg/bitfield-4.m @@ -0,0 +1,28 @@ +/* Make sure that bitfield types are printed correctly, and that ivar redeclaration + (@interface vs. @implementation) checks take the bitfield width into account. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ + +@interface Base { + int i; +} +@end + +@interface WithBitfields: Base { + void *isa; + unsigned a: 3; + signed b: 4; + int c: 5; +} +@end + +@implementation WithBitfields { + char *isa; /* { dg-error "conflicting instance variable type .char \\*isa." } */ + /* { dg-error "previous declaration of .void \\*isa." "" { target *-*-* } 12 } */ + unsigned a: 5; /* { dg-error "conflicting instance variable type .unsigned( int)? a: 5." } */ + /* { dg-error "previous declaration of .unsigned( int)? a: 3." "" { target *-*-* } 13 } */ + signed b: 4; /* This one is fine. */ + int c: 3; /* { dg-error "conflicting instance variable type .int c: 3." } */ + /* { dg-error "previous declaration of .int c: 5." "" { target *-*-* } 15 } */ +} +@end diff --git a/gcc/testsuite/objc.dg/bitfield-5.m b/gcc/testsuite/objc.dg/bitfield-5.m new file mode 100644 index 000000000..1cc1cad9b --- /dev/null +++ b/gcc/testsuite/objc.dg/bitfield-5.m @@ -0,0 +1,113 @@ +/* Check ObjC class layout follows the ABI (informally) + set in the past. ObjC structs must be laid out as if + all ivars, including those inherited from superclasses, + were defined at once (i.e., any padding introduced for + superclasses should be removed). */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-Wpadded" } */ +/* { dg-do run } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include <objc/objc.h> +#include <stdlib.h> + +#define CHECK_IF(expr) if(!(expr)) abort() + +enum Enum { zero, one, two, three, four }; + +@interface Base: Object { +@public + unsigned a: 2; + int b: 3; + enum Enum c: 4; + unsigned d: 5; +} /* { dg-warning "padding struct size to alignment boundary" } */ +@end + +struct Base_0 { + Class isa; + unsigned a: 2; + int b: 3; + enum Enum c: 4; + unsigned d: 5; +}; /* { dg-warning "padding struct size to alignment boundary" } */ + +@interface Derived: Base { +@public + signed e: 5; + unsigned f: 4; + enum Enum g: 3; +} /* { dg-warning "padding struct size to alignment boundary" } */ +@end + +struct Derived_0 { + Class isa; + unsigned a: 2; + int b: 3; + enum Enum c: 4; + unsigned d: 5; + signed e: 5; + int f: 4; + enum Enum g: 3; +}; /* { dg-warning "padding struct size to alignment boundary" } */ + +@interface Leaf: Derived { +@public + signed h: 2; +} /* { dg-warning "padding struct size to alignment boundary" } */ +@end + +struct Leaf_0 { + Class isa; + unsigned a: 2; + int b: 3; + enum Enum c: 4; + unsigned d: 5; + signed e: 5; + unsigned f: 4; + enum Enum g: 3; + signed h: 2; +}; /* { dg-warning "padding struct size to alignment boundary" } */ + +/* Note that the semicolon after @defs(...) is optional. */ + +typedef struct { @defs(Base) } Base_t; /* { dg-warning "padding struct size to alignment boundary" } */ +typedef struct { @defs(Derived); } Derived_t; /* { dg-warning "padding struct size to alignment boundary" } */ +typedef struct { @defs(Leaf); } Leaf_t; /* { dg-warning "padding struct size to alignment boundary" } */ + +int main(void) +{ + struct Leaf_0 l_0; + Leaf *l = (Leaf *)&l_0; + Leaf_t *l_t = (Leaf_t *)&l_0; + + CHECK_IF(sizeof(Base_t) == sizeof(Base)); + CHECK_IF(sizeof(Derived_t) == sizeof(Derived)); + CHECK_IF(sizeof(Leaf_t) == sizeof(Leaf)); + + CHECK_IF(sizeof(struct Base_0) == sizeof(Base)); + CHECK_IF(sizeof(struct Derived_0) == sizeof(Derived)); + CHECK_IF(sizeof(struct Leaf_0) == sizeof(Leaf)); + + l_0.isa = (Class)0; + l_0.a = 3; + l_0.b = 0; + l_0.c = three; + l_0.d = 31; + l_0.e = 0; + l_0.f = 15; + l_0.g = zero; + l_0.h = -2; + + CHECK_IF(!l_t->isa); + CHECK_IF(l->a == 3 && l_t->a == 3); + CHECK_IF(!l->b && !l_t->b); + CHECK_IF(l->c == three && l_t->c == three); + CHECK_IF(l->d == 31 && l_t->d == 31); + CHECK_IF(!l->e && !l_t->e); + CHECK_IF(l->f == 15 && l_t->f == 15); + CHECK_IF(l->g == zero && l_t->g == zero); + CHECK_IF(l->h == -2 && l_t->h == -2); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/break-in-ifstmt.m b/gcc/testsuite/objc.dg/break-in-ifstmt.m new file mode 100644 index 000000000..896849472 --- /dev/null +++ b/gcc/testsuite/objc.dg/break-in-ifstmt.m @@ -0,0 +1,14 @@ +/* { dg-do compile } */ + +@interface foo +- (void) test; +@end + +@implementation foo +-(void) test { + if (1) { + break; /* { dg-error "break" } */ + } +} +@end + diff --git a/gcc/testsuite/objc.dg/call-super-1.m b/gcc/testsuite/objc.dg/call-super-1.m new file mode 100644 index 000000000..37b705ea1 --- /dev/null +++ b/gcc/testsuite/objc.dg/call-super-1.m @@ -0,0 +1,78 @@ +/* Check if objc_super stack variables are created correctly (and + not clobbered by other values). */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-std=c99" } */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" + +extern void abort(void); + +#define CHECK_IF(expr) if(!(expr)) abort(); + +typedef struct _Point { + float x; + float y; +} Point; + +Point MakePoint ( float x , float y ) { + Point p; + p.x = x; + p.y = y; + return p; +} + +@interface Base: Object +- ( void ) translateOriginToPoint : ( Point ) translation ; +@end + +@interface Derived : Base +- ( void ) scrollToPoint : ( Point ) newOrigin ; +- ( void ) translateOriginToPoint : ( Point ) translation ; +@end + +int blort; +float result; + +@implementation Base +- ( void ) translateOriginToPoint : ( Point ) translation { + result = translation.x + translation.y; +} +@end + +@implementation Derived +- ( void ) scrollToPoint : ( Point ) newOrigin { + float transDeltaX =newOrigin.x, transDeltaY =newOrigin.y ; + Point w; + if ( ! blort ) { + w.x = transDeltaX ; w.y = transDeltaY ; + [ super translateOriginToPoint : w ] ; + return; + } + [ super translateOriginToPoint : MakePoint ( transDeltaX , transDeltaY ) ] ; + return; +} +- (void) translateOriginToPoint : ( Point ) translation { + /* This should never be called. */ + CHECK_IF(0); +} +@end + +int main(void) { + Derived *v = [Derived new]; + float r0 = 1.5 + 1.5; + blort = 1; + [v scrollToPoint: MakePoint(1.5, 1.5)]; + CHECK_IF(result == r0); + blort = 0; + [v scrollToPoint: MakePoint(1.5, 1.5)]; + CHECK_IF(result == r0); + blort = 1; + [v scrollToPoint: MakePoint(1.5, 1.5)]; + CHECK_IF(result == r0); + [v free]; + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/call-super-2.m b/gcc/testsuite/objc.dg/call-super-2.m new file mode 100644 index 000000000..190c407f7 --- /dev/null +++ b/gcc/testsuite/objc.dg/call-super-2.m @@ -0,0 +1,138 @@ +/* Check if casting 'self' or 'super' affects message lookup in the correct way. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include "../objc-obj-c++-shared/next-mapping.h" +#include <stddef.h> + +@protocol Func ++ (int) class_func0; +- (int) instance_func0; +@end + +@interface Derived: Object ++ (int) class_func1; ++ (int) class_func2; ++ (int) class_func3; ++ (int) class_func4; ++ (int) class_func5; ++ (int) class_func6; ++ (int) class_func7; +- (int) instance_func1; +- (int) instance_func2; +- (int) instance_func3; +- (int) instance_func4; +- (int) instance_func5; +- (int) instance_func6; +- (int) instance_func7; +@end + +@interface Derived (Categ) ++ (int) categ_class_func1; ++ (int) categ_class_func2; +- (int) categ_instance_func1; +- (int) categ_instance_func2; +@end + +@implementation Derived ++ (int) class_func1 +{ + int i = (size_t)[self class_func0]; /* { dg-warning ".Derived. may not respond to .\\+class_func0." } */ + return i + (size_t)[super class_func0]; /* { dg-warning ".Object. may not respond to .\\+class_func0." } */ +} ++ (int) class_func2 +{ + int i = [(id <Func>)self class_func0]; /* { dg-warning ".\\-class_func0. not found in protocol" } */ + i += [(id <Func>)super class_func0]; /* { dg-warning ".\\-class_func0. not found in protocol" } */ + i += [(Class <Func>)self class_func0]; + return i + [(Class <Func>)super class_func0]; +} ++ (int) class_func3 +{ + return [(Object <Func> *)super class_func0]; +} ++ (int) class_func4 +{ + return [(Derived <Func> *)super class_func0]; +} ++ (int) class_func5 +{ + int i = (size_t)[Derived class_func0]; /* { dg-warning ".Derived. may not respond to .\\+class_func0." } */ + return i + (size_t)[Object class_func0]; /* { dg-warning ".Object. may not respond to .\\+class_func0." } */ +} ++ (int) class_func6 +{ + return (size_t)[objc_get_class("Object") class_func1]; /* { dg-warning ".Object. may not respond to .\\+class_func1." } */ +} ++ (int) class_func7 +{ + return [objc_get_class("Derived") class_func1]; +} +- (int) instance_func1 +{ + int i = (size_t)[self instance_func0]; /* { dg-warning ".Derived. may not respond to .\\-instance_func0." } */ + return i + (size_t)[super instance_func0]; /* { dg-warning ".Object. may not respond to .\\-instance_func0." } */ +} +- (int) instance_func2 +{ + return [(id <Func>)super instance_func0]; +} +- (int) instance_func3 +{ + return [(Object <Func> *)super instance_func0]; +} +- (int) instance_func4 +{ + return [(Derived <Func> *)super instance_func0]; +} +- (int) instance_func5 +{ + int i = (size_t)[Derived instance_func1]; /* { dg-warning ".Derived. may not respond to .\\+instance_func1." } */ + return i + (size_t)[Object instance_func1]; /* { dg-warning ".Object. may not respond to .\\+instance_func1." } */ +} +- (int) instance_func6 +{ + return (size_t)[objc_get_class("Object") class_func1]; /* { dg-warning ".Object. may not respond to .\\+class_func1." } */ +} +- (int) instance_func7 +{ + return [objc_get_class("Derived") class_func1]; +} +@end + +@implementation Derived (Categ) ++ (int) categ_class_func1 +{ + int i = (size_t)[self class_func0]; /* { dg-warning ".Derived. may not respond to .\\+class_func0." } */ + i += [self class_func1]; + i += [self categ_class_func2]; + i += (size_t)[self categ_instance_func1]; /* { dg-warning ".Derived. may not respond to .\\+categ_instance_func1." } */ + return i + (size_t)[super class_func0]; /* { dg-warning ".Object. may not respond to .\\+class_func0." } */ +} ++ (int) categ_class_func2 +{ + int i = [(id <Func>)self class_func0]; /* { dg-warning ".\\-class_func0. not found in protocol" } */ + i += [(id <Func>)super class_func0]; /* { dg-warning ".\\-class_func0. not found in protocol" } */ + i += [(Class <Func>)self class_func0]; + return i + [(Class <Func>)super class_func0]; +} +- (int) categ_instance_func1 +{ + int i = (size_t)[self instance_func0]; /* { dg-warning ".Derived. may not respond to .\\-instance_func0." } */ + i += [(Derived <Func> *)self categ_instance_func2]; + i += (size_t)[(Object <Func> *)self categ_instance_func2]; /* { dg-warning ".Object. may not respond to .\\-categ_instance_func2." } */ + /* { dg-warning ".\\-categ_instance_func2. not found in protocol" "" { target *-*-* } 124 } */ + i += (size_t)[(id <Func>)self categ_instance_func2]; /* { dg-warning ".\\-categ_instance_func2. not found in protocol" } */ + i += [(id)self categ_instance_func2]; + return i + (size_t)[super instance_func0]; /* { dg-warning ".Object. may not respond to .\\-instance_func0." } */ +} +- (int) categ_instance_func2 +{ + return [(id <Func>)super instance_func0]; +} +@end + +/* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */ +/* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 0 } */ +/* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/objc.dg/call-super-3.m b/gcc/testsuite/objc.dg/call-super-3.m new file mode 100644 index 000000000..0b950294b --- /dev/null +++ b/gcc/testsuite/objc.dg/call-super-3.m @@ -0,0 +1,57 @@ +/* Check if sending messages to super does not interfere with sending messages + to classes. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "" } */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +@interface Base: Object ++ (int) class_func1; +- (int) instance_func1; +@end + +@interface Derived: Base ++ (int) class_func1; +@end + +@interface Derived (Categ) +- (int) instance_func1; +@end + +@implementation Base ++ (int) class_func1 { return 234; } +- (int) instance_func1 { return 345; } +@end + +@implementation Derived ++ (int) class_func1 { + int i = [super class_func1]; + i += [Base class_func1]; + return i; +} +@end + +@implementation Derived (Categ) +- (int) instance_func1 { + int i = [super instance_func1]; + i += [Base class_func1]; /* { dg-bogus "invalid receiver type" } */ + return i; +} +@end + +int main(void) { + Base *base = [[Base alloc] init]; /* { dg-bogus "invalid receiver type" } */ + Derived *derived = [[Derived alloc] init]; + CHECK_IF([Base class_func1] == 234); /* { dg-bogus "invalid receiver type" } */ + CHECK_IF([Derived class_func1] == 234 + 234); + CHECK_IF([base instance_func1] == 345); + CHECK_IF([derived instance_func1] == 234 + 345); + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/category-1.m b/gcc/testsuite/objc.dg/category-1.m new file mode 100644 index 000000000..e195a46bf --- /dev/null +++ b/gcc/testsuite/objc.dg/category-1.m @@ -0,0 +1,51 @@ +/* Test class methods inside categories. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do run } */ +/* { dg-xfail-run-if "need OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" +extern int strcmp(const char *s1, const char *s2); +extern void abort(void); + +#ifdef __NEXT_RUNTIME__ +#define SUPERCLASS superclass +#else +#define SUPERCLASS superClass +#endif + +#define CHECK_IF(expr) if(!(expr)) abort() + +@interface MyObject: Object ++ (Class)whatever1; +@end + +@implementation MyObject ++ (Class)whatever1 { return [super SUPERCLASS]; } +@end + +@interface MyObject (ThisWontCompile) ++(Class)whatever2; +@end + +@implementation MyObject (ThisWontCompile) ++(Class)whatever2 { return [super SUPERCLASS]; } +@end + +int main (int argc, const char * argv[]) +{ + Class w1 = [MyObject whatever1]; + Class w2 = [MyObject whatever2]; + +#ifdef NEXT_OBJC_USE_NEW_INTERFACE + CHECK_IF(!strcmp( object_getClassName( w1 ), "Object")); + CHECK_IF(!strcmp( object_getClassName( w2 ), "Object")); +#else + CHECK_IF(!strcmp(w1->name, "Object")); + CHECK_IF(!strcmp(w2->name, "Object")); +#endif + + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/class-1.m b/gcc/testsuite/objc.dg/class-1.m new file mode 100644 index 000000000..64304f590 --- /dev/null +++ b/gcc/testsuite/objc.dg/class-1.m @@ -0,0 +1,20 @@ +/* Redeclarations of class names. */ +/* { dg-do compile } */ + +typedef int foo; + +@class foo; /* { dg-error "redeclared as different kind of symbol" } */ +/* { dg-error "previous declaration of" "" { target *-*-* } 4 } */ + +typedef int bar; + +@interface bar +@end /* { dg-error "redeclared as different kind of symbol" } */ +/* { dg-error "previous declaration of" "" { target *-*-* } 9 } */ + +int glob; + +@implementation glob +@end /* { dg-error "redeclared as different kind of symbol" } */ +/* { dg-error "previous declaration of" "" { target *-*-* } 15 } */ +/* { dg-warning "annot find interface declaration" "" { target *-*-* } 18 } */ diff --git a/gcc/testsuite/objc.dg/class-2.m b/gcc/testsuite/objc.dg/class-2.m new file mode 100644 index 000000000..b98d117f5 --- /dev/null +++ b/gcc/testsuite/objc.dg/class-2.m @@ -0,0 +1,14 @@ +/* Test super classes. */ +/* { dg-do compile } */ + +@interface supclass1 +@end + +@interface supclass2 +@end + +@interface class1 : supclass1 +@end + +@implementation class1 : supclass2 /* { dg-error "conflicting super class name" } */ +@end /* { dg-error "previous declaration" "" { target *-*-* } 13 } */ diff --git a/gcc/testsuite/objc.dg/class-extension-1.m b/gcc/testsuite/objc.dg/class-extension-1.m new file mode 100644 index 000000000..eab59c413 --- /dev/null +++ b/gcc/testsuite/objc.dg/class-extension-1.m @@ -0,0 +1,30 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +/* This test tests the basic of class extensions. */ + +#include <objc/objc.h> + +@interface MyObject +{ + Class isa; +} +- (int) test; +@end + +@interface MyObject () +- (int) test2; +- (int) test3; +@end + +@implementation MyObject +- (int) test +{ + return 20; +} +- (int) test2 +{ + return 20; +} +@end /* { dg-warning "incomplete implementation of class .MyObject." } */ + /* { dg-warning "method definition for .-test3. not found" "" { target *-*-* } 29 } */ diff --git a/gcc/testsuite/objc.dg/class-extension-2.m b/gcc/testsuite/objc.dg/class-extension-2.m new file mode 100644 index 000000000..79b126f52 --- /dev/null +++ b/gcc/testsuite/objc.dg/class-extension-2.m @@ -0,0 +1,56 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +/* This test tests class extensions and protocols. */ + +#include <objc/objc.h> + +/* First, a simple test where a plain class has a protocol attached to + it in a class extension. */ +@interface MyObject +{ + Class isa; +} +@end + +@protocol MyProtocol +- (void) test; +@end + +@interface MyObject () <MyProtocol> +@end + +@implementation MyObject +@end /* { dg-warning "incomplete implementation of class .MyObject." } */ + /* { dg-warning "method definition for .-test. not found" "" { target *-*-* } 24 } */ + /* { dg-warning "class .MyObject. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 24 } */ + + + +/* Second, a more interesting test where protocols are added from the + main class and from two different class extensions. */ +@interface MyObject2 : MyObject <MyProtocol> +@end + +@protocol MyProtocol2 +- (void) test2; +@end + +@protocol MyProtocol3 +- (void) test3; +@end + +@interface MyObject2 () <MyProtocol2> +@end + +@interface MyObject2 () <MyProtocol3> +@end + +@implementation MyObject2 +@end /* { dg-warning "incomplete implementation of class .MyObject2." } */ + /* { dg-warning "method definition for .-test. not found" "" { target *-*-* } 50 } */ + /* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 50 } */ + /* { dg-warning "method definition for .-test2. not found" "" { target *-*-* } 50 } */ + /* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol2. protocol" "" { target *-*-* } 50 } */ + /* { dg-warning "method definition for .-test3. not found" "" { target *-*-* } 50 } */ + /* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol3. protocol" "" { target *-*-* } 50 } */ diff --git a/gcc/testsuite/objc.dg/class-extension-3.m b/gcc/testsuite/objc.dg/class-extension-3.m new file mode 100644 index 000000000..69e570539 --- /dev/null +++ b/gcc/testsuite/objc.dg/class-extension-3.m @@ -0,0 +1,26 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +/* This test tests warnings on class extensions. */ + +#include <objc/objc.h> + +@interface MyObject +{ + Class isa; + int count; +} +- (int) test; /* { dg-message "previous declaration" } */ +@property int count; /* { dg-message "originally specified here" } */ +@end + +@interface MyObject () +- (void) test; /* { dg-error "duplicate declaration of method .-test." } */ +@end + +@interface MyObject () +@end + +@interface MyObject () +@property int count; /* { dg-error "redeclaration of property .count." } */ +@end diff --git a/gcc/testsuite/objc.dg/class-extension-4.m b/gcc/testsuite/objc.dg/class-extension-4.m new file mode 100644 index 000000000..692a0fcbd --- /dev/null +++ b/gcc/testsuite/objc.dg/class-extension-4.m @@ -0,0 +1,19 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +/* This test tests you can not declare a class extension after the class @implementation. */ + +#include <objc/objc.h> + +@interface MyObject +{ + Class isa; +} +@end + +@implementation MyObject +@end + +@interface MyObject () +- (void) test; /* { dg-error "class extension for class .MyObject. declared after its ..implementation." } */ +@end diff --git a/gcc/testsuite/objc.dg/class-protocol-1.m b/gcc/testsuite/objc.dg/class-protocol-1.m new file mode 100644 index 000000000..cf061cb8e --- /dev/null +++ b/gcc/testsuite/objc.dg/class-protocol-1.m @@ -0,0 +1,441 @@ +/* Check Class <protocol> types */ +/* Author: David Ayers <d.ayers@inode.at> */ +/* { dg-do compile } */ + +#include <objc/objc.h> +#include <objc/objc-api.h> + +@protocol MyProto1 ++(void)doItClass1; +-(void)doItInstance1; +@end + +@protocol MyProto2 ++(void)doItClass2; +-(void)doItInstance2; +@end + +@interface MyClass1 <MyProto1> +{ + Class isa; +} +@end +@implementation MyClass1 ++(void)doItClass1{} +-(void)doItInstance1{} +@end + +@interface MyClass2 : MyClass1 <MyProto2> +@end +@implementation MyClass2 ++(void)doItClass2{} +-(void)doItInstance2{} +@end + +@interface MyClass3 +{ + Class isa; +} +@end +@interface MyClass4 : MyClass3 <MyProto1> +@end + +/*----------------------------------------*/ + +Class cls = 0; +Class <MyProto1> clsP1 = 0; +Class <MyProto2> clsP2 = 0; + +void +testSimple(void) +{ + [cls doItClass1]; + [cls doItInstance1]; + [cls doItClass2]; + [cls doItInstance2]; + + [clsP1 doItClass1]; + [clsP1 doItInstance1]; /* { dg-warning "instead of" } */ + [clsP1 doItClass2]; /* { dg-warning "not found in protocol" } */ + [clsP1 doItInstance2]; /* { dg-warning "not found in protocol" } */ + + [clsP2 doItClass1]; /* { dg-warning "not found in protocol" } */ + [clsP2 doItInstance1]; /* { dg-warning "not found in protocol" } */ + [clsP2 doItClass2]; + [clsP2 doItInstance2]; /* { dg-warning "instead of" } */ + + [MyClass1 doItClass1]; + [MyClass1 doItInstance1]; + [MyClass1 doItClass2]; /* { dg-warning "may not respond to" } */ + [MyClass1 doItInstance2]; /* { dg-warning "may not respond to" } */ + + [MyClass2 doItClass1]; + [MyClass2 doItInstance1]; + [MyClass2 doItClass2]; + [MyClass2 doItInstance2]; /* { dg-warning "may not respond to" } */ + + [MyClass3 doItClass1]; /* { dg-warning "may not respond to" } */ + [MyClass3 doItInstance1]; /* { dg-warning "may not respond to" } */ + + [MyClass4 doItClass1]; + [MyClass4 doItInstance1]; /* { dg-warning "may not respond to" } */ +} + +/*----------------------------------------*/ +/* Protocols declared by categories */ + +@protocol MyProto3 ++(void)doItClass3; +-(void)doItInstance3; +@end +@protocol MyProto4 ++(void)doItClass4; +-(void)doItInstance4; +@end + +@interface MyClass1 (Category1) <MyProto3> +@end +@interface MyClass2 (Category2) <MyProto4> +@end + +void +testCategory(void) +{ + [cls doItClass3]; + [cls doItInstance3]; + [cls doItClass4]; + [cls doItInstance4]; + + [MyClass1 doItClass3]; + [MyClass1 doItInstance3]; + [MyClass1 doItClass4]; /* { dg-warning "may not respond" } */ + [MyClass1 doItInstance4]; /* { dg-warning "may not respond" } */ + + [MyClass2 doItClass3]; + [MyClass2 doItInstance3]; + [MyClass2 doItClass4]; + [MyClass2 doItInstance4]; /* { dg-warning "may not respond" } */ + +} + +/*----------------------------------------*/ +/* Inherited protocols declared by categories */ + +@protocol MyProto5 <MyProto1> ++(void)doItClass5; +-(void)doItInstance5; +@end + +@protocol MyProto6 <MyProto2> ++(void)doItClass6; +-(void)doItInstance6; +@end + +@interface MyClass1 (Category3) <MyProto5> +@end +@interface MyClass2 (Category4) <MyProto6> +@end + +Class <MyProto5> clsP5 = 0; +Class <MyProto6> clsP6 = 0; + +void +testCategoryInherited(void) +{ + [cls doItClass5]; + [cls doItInstance5]; + [cls doItClass6]; + [cls doItInstance6]; + + [clsP5 doItClass1]; + [clsP5 doItInstance1]; /* { dg-warning "instead of" } */ + [clsP5 doItClass2]; /* { dg-warning "not found in protocol" } */ + [clsP5 doItInstance2]; /* { dg-warning "not found in protocol" } */ + + [clsP6 doItClass1]; /* { dg-warning "not found in protocol" } */ + [clsP6 doItInstance1]; /* { dg-warning "not found in protocol" } */ + [clsP6 doItClass2]; + [clsP6 doItInstance2]; /* { dg-warning "instead of" } */ + + + [MyClass1 doItClass5]; + [MyClass1 doItInstance5]; + [MyClass1 doItClass6]; /* { dg-warning "may not respond" } */ + [MyClass1 doItInstance6]; /* { dg-warning "may not respond" } */ + + [MyClass2 doItClass5]; + [MyClass2 doItInstance5]; + [MyClass2 doItClass6]; + [MyClass2 doItInstance6]; /* { dg-warning "may not respond" } */ + +} + +/*----------------------------------------*/ +/* Forward declared root protocols */ + +@protocol FwProto; + +@interface MyClass1 (Forward) <FwProto> /* { dg-warning "definition of protocol .FwProto. not found" } */ +@end + +Class <FwProto> clsP7 = 0; + +void +testForwardeDeclared1(void) +{ + [cls doItClass7]; /* { dg-warning "no .\\+doItClass7. method found" } */ + [cls doItInstance7]; /* { dg-warning "no .\\+doItInstance7. method found" } */ + + [clsP7 doItClass7]; /* { dg-warning "not found in protocol" } */ + /* { dg-warning "no .\\+doItClass7. method found" "" { target *-*-* } 189 } */ + [clsP7 doItInstance7]; /* { dg-warning "not found in protocol" } */ + /* { dg-warning "no .\\+doItInstance7. method found" "" { target *-*-* } 191 } */ + + [MyClass1 doItClass7]; /* { dg-warning "may not respond" } */ + [MyClass1 doItInstance7]; /* { dg-warning "may not respond" } */ + + [MyClass2 doItClass7]; /* { dg-warning "may not respond" } */ + [MyClass2 doItInstance7]; /* { dg-warning "may not respond" } */ + +} + +@protocol FwProto ++(void)doItClass7; +-(void)doItInstance7; +@end + +void +testForwardeDeclared2(void) +{ + [cls doItClass7]; + [cls doItInstance7]; + + [clsP7 doItClass7]; + [clsP7 doItInstance7]; /* { dg-warning "instead of" } */ + + [MyClass1 doItClass7]; + [MyClass1 doItInstance7]; + + [MyClass2 doItClass7]; + [MyClass2 doItInstance7]; +} + +/*----------------------------------------*/ +/* Inherited non root protocols */ + +@protocol MyProto8 ++(void)doItClass8; +-(void)doItInstance8; +@end + +@protocol MyProto9 <MyProto8> ++(void)doItClass9; +-(void)doItInstance9; +@end + +@interface MyClass1 (InheritedNonRoot) <MyProto9> +@end + +Class <MyProto8> clsP8 = 0; +Class <MyProto9> clsP9 = 0; + +void +testInheritedNonRoot(void) +{ + [cls doItClass8]; + [cls doItInstance8]; + [cls doItClass9]; + [cls doItInstance9]; + + [clsP8 doItClass8]; + [clsP8 doItInstance8]; /* { dg-warning "instead of" } */ + [clsP8 doItClass9]; /* { dg-warning "not found in protocol" } */ + [clsP8 doItInstance9]; /* { dg-warning "not found in protocol" } */ + + [clsP9 doItClass8]; + [clsP9 doItInstance8]; /* { dg-warning "instead of" } */ + [clsP9 doItClass9]; + [clsP9 doItInstance9]; /* { dg-warning "instead of" } */ + + [MyClass1 doItClass8]; + [MyClass1 doItInstance8]; + [MyClass1 doItClass9]; + [MyClass1 doItInstance9]; + + [MyClass2 doItClass8]; + [MyClass2 doItInstance8]; + [MyClass2 doItClass9]; + [MyClass2 doItInstance9]; + +} + +/*----------------------------------------*/ +/* Prototype mismatch */ + +@protocol MyOtherProto1 ++(id)doItClass1; +-(id)doItInstance1; +@end +@interface MyOtherClass1 <MyOtherProto1> +@end + +Class <MyOtherProto1> oclsP1; + +void +testPrototypeMismatch(void) +{ + id tmp1 = [oclsP1 doItClass1]; + id tmp2 = [oclsP1 doItInstance1]; /* { dg-warning "instead of" } */ + + [clsP1 doItClass1]; + [clsP1 doItInstance1]; /* { dg-warning "instead of" } */ +} + +id obj = nil; +id <MyProto1> objP1 = nil; +id <MyProto2> objP2 = nil; +id <MyProto5> objP5 = nil; +int num = 0; +void *ptr = 0; + +MyClass1 *mc1 = nil; + +void +testComptypes(void) +{ + { /* id <protocol>, id <protocol> */ + objP1 == objP2; /* { dg-warning "lacks a cast" } */ + objP2 == objP1; /* { dg-warning "lacks a cast" } */ + + objP1 == objP5; + objP5 == objP1; + } + { /* id <protocol>, SomeClass * */ + mc1 == objP1; + objP1 == mc1; + + mc1 == objP2; /* { dg-warning "lacks a cast" } */ + objP2 == mc1; /* { dg-warning "lacks a cast" } */ + } + { /* id <protocol>, id */ + obj == objP1; + objP1 == obj; + } + { /* id <protocol>, Class */ + cls == objP1; /* { dg-warning "lacks a cast" } */ + objP1 == cls; /* { dg-warning "lacks a cast" } */ + } + { /* id <protocol>, non-ObjC */ + num == objP1; /* { dg-warning "between pointer" } */ + objP1 == num; /* { dg-warning "between pointer" } */ + + ptr == objP1; + objP1 == ptr; + } + { /* Class <protocol>, Class <protocol> */ + clsP1 == clsP2; /* { dg-warning "lacks a cast" } */ + clsP2 == clsP1; /* { dg-warning "lacks a cast" } */ + + clsP1 == clsP5; + clsP5 == clsP1; + } + { /* Class <protocol>, SomeClass * */ + mc1 == clsP1; /* { dg-warning "lacks a cast" } */ + clsP1 == mc1; /* { dg-warning "lacks a cast" } */ + } + { /* Class <protocol>, id */ + obj == clsP1; + clsP1 == obj; + } + { /* Class <protocol>, Class */ + cls == clsP1; + clsP1 == cls; + } + { /* Class <protocol>, non-ObjC */ + num == clsP1; /* { dg-warning "between pointer" } */ + clsP1 == num; /* { dg-warning "between pointer" } */ + + ptr == clsP1; + clsP1 == ptr; + } + { /* Class <protocol>, id <protocol> */ + clsP1 == objP1; /* { dg-warning "lacks a cast" } */ + objP1 == clsP1; /* { dg-warning "lacks a cast" } */ + } + + { /* id <protocol>, id <protocol> */ + objP1 = objP2; /* { dg-warning "does not conform" } */ + objP2 = objP1; /* { dg-warning "does not conform" } */ + + objP1 = objP5; + objP5 = objP1; /* { dg-warning "does not conform" } */ + } + { /* id <protocol>, SomeClass * */ + mc1 = objP1; + objP1 = mc1; + + mc1 = objP2; /* { dg-warning "does not conform" } */ + objP2 = mc1; /* { dg-warning "does not implement" } */ + } + { /* id <protocol>, id */ + obj = objP1; + objP1 = obj; + } + { /* id <protocol>, Class */ + cls = objP1; /* { dg-warning "distinct Objective\\-C type" } */ + objP1 = cls; /* { dg-warning "distinct Objective\\-C type" } */ + } + { /* id <protocol>, non-ObjC */ + num = objP1; /* { dg-warning "makes integer" } */ + objP1 = num; /* { dg-warning "makes pointer" } */ + + ptr = objP1; + objP1 = ptr; + } + { /* Class <protocol>, Class <protocol> */ + clsP1 = clsP2; /* { dg-warning "does not conform" } */ + clsP2 = clsP1; /* { dg-warning "does not conform" } */ + + clsP1 = clsP5; + clsP5 = clsP1; /* { dg-warning "does not conform" } */ + } + { /* Class <protocol>, SomeClass * */ + /* These combinations should always elicit a warning. */ + mc1 = clsP1; /* { dg-warning "distinct Objective\\-C type" } */ + clsP1 = mc1; /* { dg-warning "distinct Objective\\-C type" } */ + + mc1 = clsP2; /* { dg-warning "distinct Objective\\-C type" } */ + clsP2 = mc1; /* { dg-warning "distinct Objective\\-C type" } */ + } + { /* Class <protocol>, id */ + obj = clsP1; + clsP1 = obj; + } + { /* Class <protocol>, Class */ + cls = clsP1; + clsP1 = cls; + } + { /* Class <protocol>, non-ObjC */ + num = clsP1; /* { dg-warning "makes integer" } */ + clsP1 = num; /* { dg-warning "makes pointer" } */ + + ptr = clsP1; + clsP1 = ptr; + } + { /* Class <protocol>, id <protocol> */ + clsP1 = objP1; /* { dg-warning "distinct Objective\\-C type" } */ + objP1 = clsP1; /* { dg-warning "distinct Objective\\-C type" } */ + } +} + +int main () +{ + testSimple(); + testCategory(); + testCategoryInherited(); + return(0); +} + +/* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */ +/* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 0 } */ +/* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/objc.dg/comp-types-1.m b/gcc/testsuite/objc.dg/comp-types-1.m new file mode 100644 index 000000000..5bf59a73c --- /dev/null +++ b/gcc/testsuite/objc.dg/comp-types-1.m @@ -0,0 +1,87 @@ +/* Test various ObjC types assignments and comparisons. */ +/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */ +/* { dg-do compile } */ +#include <objc/objc.h> + +@protocol MyProtocol +- (void) foo; +@end + +@interface MyClass +@end + +@interface MyOtherClass <MyProtocol> +- (void) foo; +@end + +int main() +{ + id obj = nil; + id<MyProtocol> obj_p = nil; + MyClass *obj_c = nil; + MyOtherClass *obj_cp = nil; + Class obj_C = Nil; + + /* Assigning to an 'id' variable should never + generate a warning. */ + obj = obj_p; /* Ok */ + obj = obj_c; /* Ok */ + obj = obj_cp; /* Ok */ + obj = obj_C; /* Ok */ + + /* Assigning to a 'MyClass *' variable should always generate a + warning, unless done from an 'id'. */ + obj_c = obj; /* Ok */ + obj_c = obj_p; /* { dg-warning "distinct Objective\\-C type" } */ + obj_c = obj_cp; /* { dg-warning "distinct Objective\\-C type" } */ + obj_c = obj_C; /* { dg-warning "distinct Objective\\-C type" } */ + + /* Assigning to an 'id<MyProtocol>' variable should generate a + warning if done from a 'MyClass *' (which doesn't implement + MyProtocol), but not from an 'id' or from a 'MyOtherClass *' + (which implements MyProtocol). */ + obj_p = obj; /* Ok */ + obj_p = obj_c; /* { dg-warning "does not implement" } */ + obj_p = obj_cp; /* Ok */ + obj_p = obj_C; /* { dg-warning "distinct Objective\\-C type" } */ + + /* Assigning to a 'MyOtherClass *' variable should always generate + a warning, unless done from an 'id' or an 'id<MyProtocol>' (since + MyOtherClass implements MyProtocol). */ + obj_cp = obj; /* Ok */ + obj_cp = obj_c; /* { dg-warning "distinct Objective\\-C type" } */ + obj_cp = obj_p; /* Ok */ + obj_cp = obj_C; /* { dg-warning "distinct Objective\\-C type" } */ + + /* Any comparison involving an 'id' must be without warnings. */ + if (obj == obj_p) ; /* Ok */ /*Bogus warning here in 2.95.4*/ + if (obj_p == obj) ; /* Ok */ + if (obj == obj_c) ; /* Ok */ + if (obj_c == obj) ; /* Ok */ + if (obj == obj_cp) ; /* Ok */ + if (obj_cp == obj) ; /* Ok */ + if (obj == obj_C) ; /* Ok */ + if (obj_C == obj) ; /* Ok */ + + /* Any comparison between 'MyClass *' and anything which is not an 'id' + must generate a warning. */ + if (obj_c == obj_p) ; /* { dg-warning "lacks a cast" } */ + if (obj_p == obj_c) ; /* { dg-warning "lacks a cast" } */ + if (obj_c == obj_cp) ; /* { dg-warning "lacks a cast" } */ + if (obj_cp == obj_c) ; /* { dg-warning "lacks a cast" } */ + if (obj_c == obj_C) ; /* { dg-warning "lacks a cast" } */ + if (obj_C == obj_c) ; /* { dg-warning "lacks a cast" } */ + + /* Any comparison between 'MyOtherClass *' (which implements + MyProtocol) and an 'id' implementing MyProtocol are Ok. */ + if (obj_cp == obj_p) ; /* Ok */ + if (obj_p == obj_cp) ; /* Ok */ + + + if (obj_p == obj_C) ; /* { dg-warning "lacks a cast" } */ + if (obj_C == obj_p) ; /* { dg-warning "lacks a cast" } */ + if (obj_cp == obj_C) ; /* { dg-warning "lacks a cast" } */ + if (obj_C == obj_cp) ; /* { dg-warning "lacks a cast" } */ + + return 0; +} diff --git a/gcc/testsuite/objc.dg/comp-types-10.m b/gcc/testsuite/objc.dg/comp-types-10.m new file mode 100644 index 000000000..3d8598399 --- /dev/null +++ b/gcc/testsuite/objc.dg/comp-types-10.m @@ -0,0 +1,27 @@ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@protocol Foo +- (id)meth1; +- (id)meth2:(int)arg; +@end + +@interface Derived1: Object +@end + +@interface Derived2: Object ++ (Derived1 *)new; +@end + +id<Foo> func(void) { + Object *o = [Object new]; + return o; /* { dg-warning "class .Object. does not implement the .Foo. protocol" } */ +} + +@implementation Derived2 ++ (Derived1 *)new { + Derived2 *o = [super new]; + return o; /* { dg-warning "distinct Objective\\-C type in return" } */ +} +@end diff --git a/gcc/testsuite/objc.dg/comp-types-11.m b/gcc/testsuite/objc.dg/comp-types-11.m new file mode 100644 index 000000000..959cc049a --- /dev/null +++ b/gcc/testsuite/objc.dg/comp-types-11.m @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +#include "../objc-obj-c++-shared/Object1.h" + +@interface Derived: Object +@end + +extern Object* foo(void); +static Derived *test(void) +{ + Derived *m = foo(); /* { dg-warning "initialization from distinct Objective\\-C type" } */ + + return m; +} + diff --git a/gcc/testsuite/objc.dg/comp-types-12.m b/gcc/testsuite/objc.dg/comp-types-12.m new file mode 100644 index 000000000..3a919d5d0 --- /dev/null +++ b/gcc/testsuite/objc.dg/comp-types-12.m @@ -0,0 +1,19 @@ +/* When assigning function pointers, allow for covariant return types + and contravariant argument types. */ +/* { dg-do compile } */ +#include <objc/Object.h> + +@class Derived; + +Object *ExternFunc (Object *filePath, Object *key); +typedef id FuncSignature (Object *arg1, Derived *arg2); + +@interface Derived: Object ++ (void)registerFunc:(FuncSignature *)function; +@end + +void foo(void) +{ + [Derived registerFunc: ExternFunc]; +} + diff --git a/gcc/testsuite/objc.dg/comp-types-2.m b/gcc/testsuite/objc.dg/comp-types-2.m new file mode 100644 index 000000000..6e88df999 --- /dev/null +++ b/gcc/testsuite/objc.dg/comp-types-2.m @@ -0,0 +1,37 @@ +/* Test simple ObjC types casts. */ +/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */ +/* { dg-do compile } */ +#include <objc/objc.h> + +@protocol MyProtocol +- (void) foo; +@end + +@interface MyClass +@end + +int main() +{ + id obj = nil; + id<MyProtocol> obj_p = nil; + MyClass *obj_c = nil; + Class obj_C = Nil; + + /* All these casts should generate no warnings. */ + + obj = (id)obj_p; + obj = (id)obj_c; + obj = (id)obj_C; + obj_c = (MyClass *)obj; + obj_c = (MyClass *)obj_p; + obj_c = (MyClass *)obj_C; + obj_p = (id<MyProtocol>)obj; + obj_p = (id<MyProtocol>)obj_c; + obj_p = (id<MyProtocol>)obj_C; + obj_C = (Class)obj; + obj_C = (Class)obj_p; + obj_C = (Class)obj_c; + + + return 0; +} diff --git a/gcc/testsuite/objc.dg/comp-types-3.m b/gcc/testsuite/objc.dg/comp-types-3.m new file mode 100644 index 000000000..51f418ef5 --- /dev/null +++ b/gcc/testsuite/objc.dg/comp-types-3.m @@ -0,0 +1,63 @@ +/* Test assignments and comparisons between protocols (obscure case). */ +/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */ +/* { dg-do compile } */ +#include <objc/objc.h> + +@protocol MyProtocolA +- (void) methodA; +@end + +@protocol MyProtocolB +- (void) methodB; +@end + +@protocol MyProtocolAB <MyProtocolA, MyProtocolB> +@end + +@protocol MyProtocolAC <MyProtocolA> +- (void) methodC; +@end + +int main() +{ + id<MyProtocolA> obj_a = nil; + id<MyProtocolB> obj_b = nil; + id<MyProtocolAB> obj_ab = nil; + id<MyProtocolAC> obj_ac = nil; + + obj_a = obj_b; /* { dg-warning "does not conform" } */ + obj_a = obj_ab; /* Ok */ + obj_a = obj_ac; /* Ok */ + + obj_b = obj_a; /* { dg-warning "does not conform" } */ + obj_b = obj_ab; /* Ok */ + obj_b = obj_ac; /* { dg-warning "does not conform" } */ + + obj_ab = obj_a; /* { dg-warning "does not conform" } */ + obj_ab = obj_b; /* { dg-warning "does not conform" } */ + obj_ab = obj_ac; /* { dg-warning "does not conform" } */ + + obj_ac = obj_a; /* { dg-warning "does not conform" } */ + obj_ac = obj_b; /* { dg-warning "does not conform" } */ + obj_ac = obj_ab; /* { dg-warning "does not conform" } */ + + if (obj_a == obj_b) ; /* { dg-warning "lacks a cast" } */ + if (obj_b == obj_a) ; /* { dg-warning "lacks a cast" } */ + + if (obj_a == obj_ab) ; /* Ok */ + if (obj_ab == obj_a) ; /* Ok */ /* Spurious 2.95.4 warning here */ + + if (obj_a == obj_ac) ; /* Ok */ + if (obj_ac == obj_a) ; /* Ok */ /* Spurious 2.95.4 warning here */ + + if (obj_b == obj_ab) ; /* Ok */ + if (obj_ab == obj_b) ; /* Ok */ /* Spurious 2.95.4 warning here */ + + if (obj_b == obj_ac) ; /* { dg-warning "lacks a cast" } */ + if (obj_ac == obj_b) ; /* { dg-warning "lacks a cast" } */ + + if (obj_ab == obj_ac) ; /* { dg-warning "lacks a cast" } */ + if (obj_ac == obj_ab) ; /* { dg-warning "lacks a cast" } */ + + return 0; +} diff --git a/gcc/testsuite/objc.dg/comp-types-4.m b/gcc/testsuite/objc.dg/comp-types-4.m new file mode 100644 index 000000000..f15390a38 --- /dev/null +++ b/gcc/testsuite/objc.dg/comp-types-4.m @@ -0,0 +1,73 @@ +/* Test warnings for assignments and comparisons between ObjC and C types. */ +/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */ +/* { dg-do compile } */ +#include <objc/objc.h> + +/* The NeXT runtime headers do not define NULL. */ +#ifndef NULL +#define NULL ((void *)0) +#endif + +@protocol MyProtocol +- (void) method; +@end + +@interface MyClass +@end + +int main() +{ + id obj = nil; + id <MyProtocol> obj_p = nil; + MyClass *obj_c = nil; + Class obj_C = Nil; + + int i = 0; + int *j = NULL; + + /* These should all generate warnings. */ + + obj = i; /* { dg-warning "pointer from integer without a cast" } */ + obj = j; /* { dg-warning "incompatible pointer type" } */ + + obj_p = i; /* { dg-warning "pointer from integer without a cast" } */ + obj_p = j; /* { dg-warning "incompatible pointer type" } */ + + obj_c = i; /* { dg-warning "pointer from integer without a cast" } */ + obj_c = j; /* { dg-warning "incompatible pointer type" } */ + + obj_C = i; /* { dg-warning "pointer from integer without a cast" } */ + obj_C = j; /* { dg-warning "incompatible pointer type" } */ + + i = obj; /* { dg-warning "integer from pointer without a cast" } */ + i = obj_p; /* { dg-warning "integer from pointer without a cast" } */ + i = obj_c; /* { dg-warning "integer from pointer without a cast" } */ + i = obj_C; /* { dg-warning "integer from pointer without a cast" } */ + + j = obj; /* { dg-warning "incompatible pointer type" } */ + j = obj_p; /* { dg-warning "incompatible pointer type" } */ + j = obj_c; /* { dg-warning "incompatible pointer type" } */ + j = obj_C; /* { dg-warning "incompatible pointer type" } */ + + if (obj == i) ; /* { dg-warning "comparison between pointer and integer" } */ + if (i == obj) ; /* { dg-warning "comparison between pointer and integer" } */ + if (obj == j) ; /* { dg-warning "lacks a cast" } */ + if (j == obj) ; /* { dg-warning "lacks a cast" } */ + + if (obj_c == i) ; /*{ dg-warning "comparison between pointer and integer" }*/ + if (i == obj_c) ; /*{ dg-warning "comparison between pointer and integer" }*/ + if (obj_c == j) ; /* { dg-warning "lacks a cast" } */ + if (j == obj_c) ; /* { dg-warning "lacks a cast" } */ + + if (obj_p == i) ; /*{ dg-warning "comparison between pointer and integer" }*/ + if (i == obj_p) ; /*{ dg-warning "comparison between pointer and integer" }*/ + if (obj_p == j) ; /* { dg-warning "lacks a cast" } */ + if (j == obj_p) ; /* { dg-warning "lacks a cast" } */ + + if (obj_C == i) ; /*{ dg-warning "comparison between pointer and integer" }*/ + if (i == obj_C) ; /*{ dg-warning "comparison between pointer and integer" }*/ + if (obj_C == j) ; /* { dg-warning "lacks a cast" } */ + if (j == obj_C) ; /* { dg-warning "lacks a cast" } */ + + return 0; +} diff --git a/gcc/testsuite/objc.dg/comp-types-5.m b/gcc/testsuite/objc.dg/comp-types-5.m new file mode 100644 index 000000000..c112ecbe5 --- /dev/null +++ b/gcc/testsuite/objc.dg/comp-types-5.m @@ -0,0 +1,32 @@ +/* Test assignments and comparisons involving `one-off' protocols. */ +/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */ +/* { dg-do compile } */ +#include <objc/objc.h> + +@protocol MyProtocol +- (void) method; +@end + +@interface MyClass +@end + +int main() +{ + id obj = nil; + id <MyProtocol> obj_p = nil; + MyClass<MyProtocol> *obj_cp = nil; + + obj_cp = obj; /* Ok */ + obj = obj_cp; /* Ok */ + + obj_cp = obj_p; /* Ok */ + obj_p = obj_cp; /* Ok */ + + if (obj_cp == obj) ; /* Ok */ + if (obj == obj_cp) ; /* Ok */ + + if (obj_cp == obj_p) ; /* Ok */ + if (obj_p == obj_cp) ; /* Ok */ + + return 0; +} diff --git a/gcc/testsuite/objc.dg/comp-types-6.m b/gcc/testsuite/objc.dg/comp-types-6.m new file mode 100644 index 000000000..e23558114 --- /dev/null +++ b/gcc/testsuite/objc.dg/comp-types-6.m @@ -0,0 +1,38 @@ +/* Test assignments and comparisons involving category protocols. */ +/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@protocol MyProtocol +- (void) method; +@end + +@interface MyClass +@end + +@interface MyClass (Addition) <MyProtocol> +- (void) method; +@end + +@interface MyOtherClass : MyClass +@end + +int main() +{ + id <MyProtocol> obj_p = nil; + MyClass *obj_cp = nil; + MyOtherClass *obj_cp2 = nil; + + obj_cp = obj_p; /* { dg-warning "distinct Objective\\-C type" } */ + obj_cp2 = obj_p; /* { dg-warning "distinct Objective\\-C type" } */ + obj_p = obj_cp; /* Ok */ + obj_p = obj_cp2; /* Ok */ + + if (obj_cp == obj_p) ; /* Ok */ + if (obj_cp2 == obj_p) ; /* Ok */ + if (obj_p == obj_cp) ; /* Ok */ + if (obj_p == obj_cp2) ; /* Ok */ + + return 0; +} diff --git a/gcc/testsuite/objc.dg/comp-types-7.m b/gcc/testsuite/objc.dg/comp-types-7.m new file mode 100644 index 000000000..526934fbb --- /dev/null +++ b/gcc/testsuite/objc.dg/comp-types-7.m @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* We used to ICE because we removed the cast to List_linked* + in -[ListIndex_linked next]. */ + +@interface List +{ +@public + int firstLink; +} +@end + +@interface ListIndex_linked +{ +@public + List *collection; + int link; +} +@end + +@interface List_linked: List +@end + +@implementation List +@end + +@implementation ListIndex_linked +- next +{ + link = ((List_linked*)collection)->firstLink; +} +@end + diff --git a/gcc/testsuite/objc.dg/comp-types-8.m b/gcc/testsuite/objc.dg/comp-types-8.m new file mode 100644 index 000000000..bb7b136fb --- /dev/null +++ b/gcc/testsuite/objc.dg/comp-types-8.m @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* Another gimplifier ICE... */ + +#include "../objc-obj-c++-shared/Object1.h" + +@interface MyView: Object { + int _frame; +} +- (void)_finalize; +@end + +@interface MyViewTemplate: MyView { + void *_className; +} +- (id)createRealObject; +@end + +@implementation MyViewTemplate +- (id)createRealObject { + id realObj; + *(MyView *)realObj = *(MyView *)self; + return realObj; +} +@end diff --git a/gcc/testsuite/objc.dg/comp-types-9.m b/gcc/testsuite/objc.dg/comp-types-9.m new file mode 100644 index 000000000..3abcde5be --- /dev/null +++ b/gcc/testsuite/objc.dg/comp-types-9.m @@ -0,0 +1,19 @@ +/* Yet another mysterious gimplifier crasher. */ +/* { dg-do compile } */ +/* { dg-options "-O3" } */ + +@class NSString; +@protocol NSObject +@end +@interface NSObject <NSObject> { +} +@end +void __setRetained(id *ivar, id value) { + *ivar = value; +} +static NSString *_logProcessPrefix = 0; +@implementation NSObject (ScopeAdditions) ++ (void)setObjectLogProcessPrefix:(NSString *)processPrefix { + __setRetained(&_logProcessPrefix, processPrefix); +} +@end diff --git a/gcc/testsuite/objc.dg/conditional-1.m b/gcc/testsuite/objc.dg/conditional-1.m new file mode 100644 index 000000000..0aad62c55 --- /dev/null +++ b/gcc/testsuite/objc.dg/conditional-1.m @@ -0,0 +1,45 @@ +/* Testing conditional warnings (without headers). */ +/* Author: David Ayers */ + +/* { dg-do compile } */ + +#define nil ((id)0) +@interface MyObject +@end + +@protocol MyProtocol +@end + +@interface MyProtoObject <MyProtocol> +@end + + +int +main (int argc, char *argv[]) +{ + id var_id = nil; + id <MyProtocol> var_id_p = nil; + MyObject *var_obj = nil; + MyProtoObject *var_obj_p = nil; + + var_id = (var_id == var_obj) ? var_id : var_obj; + var_id = (var_id == var_obj) ? var_id : var_obj_p; + + /* Ayers: Currently, the following test case passes for + technically the wrong reason (see below). + */ + var_obj_p = (var_id == var_obj) ? var_obj_p : var_obj; /* { dg-warning "distinct Objective-C types" } */ + var_obj_p = (var_id == var_obj) ? var_obj_p : var_id_p; + + /* Ayers: The first of the following test cases + should probably warn for var_obj_p = var_obj, + yet that would require extensive changes to + build_conditional_expr to create a tree with + multiple types that the assignment would have + to evaluate both versions for correct diagnostics. + */ + var_obj_p = (var_id == var_obj) ? var_id : var_obj; + var_obj_p = (var_id == var_obj) ? var_id : var_obj_p; + + return 0; +} diff --git a/gcc/testsuite/objc.dg/defs.m b/gcc/testsuite/objc.dg/defs.m new file mode 100644 index 000000000..2ffde0035 --- /dev/null +++ b/gcc/testsuite/objc.dg/defs.m @@ -0,0 +1,70 @@ +/* Check if the @defs() construct preserves the correct + offsets of ivars. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "" } */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" +//#include <objc/objc.h> + +extern void abort(void); + +#define CHECK_IF(expr) if(!(expr)) abort(); + +@interface Base: Object { +@public + int a; + float b; + char c; +} +@end + +@interface Derived: Base { +@public + double d; + unsigned e; + id f; +} +- init; +@end + +struct Derived_defs { + @defs(Derived); +}; + +@implementation Base +@end +@implementation Derived +- init { + [super init]; + a = 123; + b = 1.23; + c = 'c'; + d = 123.456; + e = 456; + f = isa; + return self; +} +@end + +int main(void) { + Derived *derived = [[Derived alloc] init]; + struct Derived_defs *derived_defs = (struct Derived_defs *)derived; + + CHECK_IF(derived->a == derived_defs->a && derived_defs->a == 123); + CHECK_IF(derived->b == derived_defs->b && derived_defs->b == (float)1.23); + CHECK_IF(derived->c == derived_defs->c && derived_defs->c == 'c'); + CHECK_IF(derived->d == derived_defs->d && derived_defs->d == (double)123.456); + CHECK_IF(derived->e == derived_defs->e && derived_defs->e == 456); + CHECK_IF(derived->f == derived_defs->f && derived_defs->f == derived_defs->isa); + + /* Try out the "inline" notation as well. */ + CHECK_IF(((struct { @defs(Derived); } *)derived)->a == 123); + CHECK_IF(((struct { @defs(Derived); } *)derived)->c == 'c'); + CHECK_IF(((struct { @defs(Derived); } *)derived)->e == 456); + + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/demangle-1.m b/gcc/testsuite/objc.dg/demangle-1.m new file mode 100644 index 000000000..42b79a9eb --- /dev/null +++ b/gcc/testsuite/objc.dg/demangle-1.m @@ -0,0 +1,59 @@ +/* Test demangling an Objective-C method. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include <objc/objc.h> + +@interface DemangleTest +{ + Class isa; +} ++ (id) initialize; ++ (int) testFunction1; ++ (int) test_function2; ++ (int) __testFunction3: (int)unused andArgument: (char)unused2; +@end + +@implementation DemangleTest ++ (id) initialize { return self; } ++ (int) testFunction1 +{ + printf ("%s\n", __PRETTY_FUNCTION__); + return strcmp (__PRETTY_FUNCTION__, "+[DemangleTest testFunction1]"); +} +/* Note that in general, due to how mangling is done, it's impossible + to get the demangling right for all functions containing '_' in the + name. But at least we should be able to get that right for single + argument ones that don't end with '_', such as the following + one. */ ++ (int) test_function2 +{ + printf ("%s\n", __PRETTY_FUNCTION__); + return strcmp (__PRETTY_FUNCTION__, "+[DemangleTest test_function2]"); +} ++ (int) __testFunction3: (int)unused andArgument: (char)unused2 +{ + printf ("%s\n", __PRETTY_FUNCTION__); + return strcmp (__PRETTY_FUNCTION__, "+[DemangleTest __testFunction3:andArgument:]"); +} +@end + +int main () +{ + if ([DemangleTest testFunction1] != 0) + abort (); + + if ([DemangleTest test_function2] != 0) + abort (); + + if ([DemangleTest __testFunction3:0 andArgument: 'c'] != 0) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/desig-init-1.m b/gcc/testsuite/objc.dg/desig-init-1.m new file mode 100644 index 000000000..a07e72be1 --- /dev/null +++ b/gcc/testsuite/objc.dg/desig-init-1.m @@ -0,0 +1,51 @@ +/* Test Objective-C capability for handling GNU/C99 designated initializers, and distinguishing them + from message sends. Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-std=gnu99" } */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + + +#include "../objc-obj-c++-shared/Object1.h" +#include <stdio.h> +#include <stdlib.h> + +@interface Cls : Object ++ (int) meth1; ++ (int) meth2; ++ (void) doTests; +@end + +@implementation Cls ++ (int) meth1 { return 45; } ++ (int) meth2 { return 21; } ++ (void) doTests { + int arr[7] = { + 0, + [Cls meth1], + [2 + 1] = 3, + [2 * 2 ... 5] = (size_t)[0 meth4], /* { dg-warning "invalid receiver type" } */ + /* { dg-warning "no .\\-meth4. method found" "" { target *-*-* } 26 } */ + [2] [Cls meth2], + /* Since invalid receivers are treated as 'id' for purposes of message + lookup, we _should_ find a meth2 to call below. */ + [6] = (int)[0 meth2] /* { dg-warning "invalid receiver type" } */ + }; + + if (arr[0] != 0 || arr[1] != 45 || arr[2] != 21 || arr[3] != 3) + abort (); + + printf ("%s\n", [super name]); + printf ("%d %d %d %d %d %d\n", arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]); +} +@end + +int main(void) { + [Cls doTests]; + return 0; +} + +/* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */ +/* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 0 } */ +/* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 0 } */ + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/desig-init-2.m b/gcc/testsuite/objc.dg/desig-init-2.m new file mode 100644 index 000000000..cf8e0c1c3 --- /dev/null +++ b/gcc/testsuite/objc.dg/desig-init-2.m @@ -0,0 +1,7 @@ +/* Test handling of C99 designator lists in Objective-C. Test array + designators after structure member designators. */ +/* Origin: Joseph Myers <joseph@codesourcery.com> */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99" } */ + +struct s { int a[2]; } x = { .a[0] = 1 }; diff --git a/gcc/testsuite/objc.dg/dg.exp b/gcc/testsuite/objc.dg/dg.exp new file mode 100644 index 000000000..350c4b833 --- /dev/null +++ b/gcc/testsuite/objc.dg/dg.exp @@ -0,0 +1,42 @@ +# GCC Objective-C testsuite that uses the `dg.exp' driver. +# Copyright (C) 1997, 2001, 2007, 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Load support procs. +load_lib objc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS "" +} + +# Initialize `dg'. +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]] + +# Main loop. +dg-runtest $tests "-fgnu-runtime" $DEFAULT_CFLAGS + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { + dg-runtest $tests "-fnext-runtime" $DEFAULT_CFLAGS +} + +# All done. +dg-finish diff --git a/gcc/testsuite/objc.dg/duplicate-class-1.m b/gcc/testsuite/objc.dg/duplicate-class-1.m new file mode 100644 index 000000000..f86159211 --- /dev/null +++ b/gcc/testsuite/objc.dg/duplicate-class-1.m @@ -0,0 +1,31 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test that a duplicated @implementation for the same class does not + crash the compiler. */ + +@interface Test +{ + Class isa; +} +- (int) test; +@end + +@implementation Test +- (int) test +{ + return 4; +} +@end + +/* The most likely cause is that the programmer meant this to be a + category, so check what happens if we have some different methods + in there. */ +@implementation Test +- (int) test2 /* { dg-error "reimplementation of class .Test." } */ +{ + return [self test]; +} +@end +/* { dg-warning "incomplete implementation" "" { target *-*-* } 29 } */ +/* { dg-warning "not found" "" { target *-*-* } 29 } */ diff --git a/gcc/testsuite/objc.dg/dwarf-1.m b/gcc/testsuite/objc.dg/dwarf-1.m new file mode 100644 index 000000000..c04b61350 --- /dev/null +++ b/gcc/testsuite/objc.dg/dwarf-1.m @@ -0,0 +1,6 @@ +/* { dg-options "-gdwarf-2 -dA" } */ +/* { dg-final { scan-assembler "\"id.0\".*DW_AT_name" } } */ +/* { dg-skip-if "No Dwarf" { { *-*-aix* alpha*-dec-osf* hppa*-*-hpux* } && { ! hppa*64*-*-* } } { "*" } { "" } } */ +@interface foo + id x; +@end diff --git a/gcc/testsuite/objc.dg/dwarf-2.m b/gcc/testsuite/objc.dg/dwarf-2.m new file mode 100644 index 000000000..bedc520a6 --- /dev/null +++ b/gcc/testsuite/objc.dg/dwarf-2.m @@ -0,0 +1,4 @@ +/* { dg-options "-gdwarf-2 -dA -gno-strict-dwarf" } */ +/* { dg-final { scan-assembler "0x10\[^0-9a-f\].*DW_AT_language" } } */ +/* { dg-skip-if "No Dwarf" { { *-*-aix* alpha*-dec-osf* hppa*-*-hpux* } && { ! hppa*64*-*-* } } { "*" } { "" } } */ +int x; diff --git a/gcc/testsuite/objc.dg/encode-1.m b/gcc/testsuite/objc.dg/encode-1.m new file mode 100644 index 000000000..09cb6af19 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-1.m @@ -0,0 +1,23 @@ +/* Test if the Objective-C @encode machinery distinguishes between + 'BOOL *' (which should be encoded as a pointer to BOOL) and 'char *' (which + should be encoded as '*'). This is somewhat tricky wrt the NeXT runtime, + where we have 'typedef char BOOL'. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ +#include <string.h> +#include <stdlib.h> +#include <objc/objc.h> + +int main(void) { + const char *BOOL_ptr = @encode(BOOL *); + const char *BOOL_ = @encode(BOOL); + const char *char_ptr = @encode(char *); + + if(*BOOL_ptr != '^' || strcmp(BOOL_ptr + 1, BOOL_)) + abort(); + + if(strcmp(char_ptr, "*")) + abort(); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-10.m b/gcc/testsuite/objc.dg/encode-10.m new file mode 100644 index 000000000..bdfdb82b8 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-10.m @@ -0,0 +1,19 @@ +/* { dg-do compile } */ + +typedef struct Vec { + double x, y; + int z; +} xyz_t ; + +typedef struct { + float fscalar; + double dscalar; + xyz_t dv; + int iscalar; +} anonymous; + +const char *enc = @encode(xyz_t); +const char *enc2 = @encode(anonymous); + +/* { dg-final { scan-assembler "{Vec=ddi}" } } */ +/* { dg-final { scan-assembler "{?=fd{Vec=ddi}i}" } } */ diff --git a/gcc/testsuite/objc.dg/encode-11.m b/gcc/testsuite/objc.dg/encode-11.m new file mode 100644 index 000000000..2e5fc84c8 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-11.m @@ -0,0 +1,43 @@ +/* { dg-do run } */ + +extern void _exit(int); +extern int strcmp(const char *, const char *); + +typedef struct Vec { + double xv[10], yv[5]; + float fscal; + int z; +} xyz_t ; + +typedef struct { + float fscalar; + double dscalar; + xyz_t dv; + int iscalar; + long ln; + long long lln; +} anonymous; + +const char *enc = @encode(xyz_t); +const char *enc2 = @encode(anonymous); + +#ifdef __LP64__ +#define L "q" +#else +#define L "l" +#endif + +int main(void) { + const char *encode = @encode(long); + + if (strcmp (encode, L)) + _exit(-(__LINE__)); + + if (strcmp (enc, "{Vec=[10d][5d]fi}")) + _exit(-(__LINE__)); + + if (strcmp (enc2, "{?=fd{Vec=[10d][5d]fi}i" L "q}")) + _exit(-(__LINE__)); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-2.m b/gcc/testsuite/objc.dg/encode-2.m new file mode 100644 index 000000000..ea0ff6a7d --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-2.m @@ -0,0 +1,104 @@ +/* Test Objective-C method encodings. */ + +/* The _encoded_ parameter offsets for Objective-C methods are + computed inductively as follows: + - The first paramter (self) has offset 0; + - The k-th parameter (k > 1) has offset equal to the + sum of: + - the offset of the k-1-st paramter + - the (void *)-promoted size of the k-1-st parameter. + + Note that the encoded offsets need not correspond + to the actual placement of parameters (relative to 'self') + on the stack! Your target's ABI may have very different + opinions on the matter. */ + +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include "../objc-obj-c++-shared/next-mapping.h" + +#ifdef __NEXT_RUNTIME__ +#define METHOD Method +#else +#include <objc/objc-api.h> +#define METHOD Method_t +#define method_get_types(M) (M)->method_types +#endif + +extern int sscanf(const char *str, const char *format, ...); +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +@interface Foo: Object +typedef struct { float x, y; } XXPoint; +typedef struct { float width, height; } XXSize; +typedef struct _XXRect { XXPoint origin; XXSize size; } XXRect; +-(id)setRect:(XXRect)r withInt:(int)i; +-(void) char:(signed char)c float:(float)f double:(double)d long:(long)l; +@end + +XXRect my_rect; +unsigned offs1, offs2, offs3, offs4, offs5, offs6, offs7; + +@implementation Foo +-(id)setRect:(XXRect)r withInt:(int)i { + unsigned offs = sizeof(self); + CHECK_IF(offs == offs3); + offs += sizeof(_cmd); + CHECK_IF(offs == offs4); + offs += sizeof(r); + CHECK_IF(offs == offs5); + offs += sizeof(i); + CHECK_IF(offs == offs1); + return nil; +} +-(void) char:(signed char)c float:(float)f double:(double)d long:(long)l { + unsigned offs = sizeof(self); + CHECK_IF(offs == offs3); + offs += sizeof(_cmd); + CHECK_IF(offs == offs4); + offs += sizeof((int)c); + CHECK_IF(offs == offs5); + offs += sizeof(f); + CHECK_IF(offs == offs6); + offs += sizeof(d); + CHECK_IF(offs == offs7); + offs += sizeof(l); + CHECK_IF(offs == offs1); +} +@end + + +int main(void) { + Foo *foo = [[Foo alloc] init]; + Class fooClass = objc_get_class("Foo"); + METHOD meth; + const char *string; + + meth = class_get_instance_method(fooClass, @selector(setRect:withInt:)); + offs2 = 9999; + + sscanf(method_get_types(meth), "@%u@%u:%u{_XXRect={?=ff}{?=ff}}%ui%u", &offs1, &offs2, &offs3, + &offs4, &offs5); + + CHECK_IF(!offs2); + [foo setRect:my_rect withInt:123]; + + meth = class_get_instance_method(fooClass, @selector(char:float:double:long:)); + offs2 = 9999; + if (sizeof (long) == 8) + string = "v%u@%u:%uc%uf%ud%uq%u"; + else + string = "v%u@%u:%uc%uf%ud%ul%u"; + sscanf(method_get_types(meth), string, &offs1, &offs2, &offs3, + &offs4, &offs5, &offs6, &offs7); + CHECK_IF(!offs2); + [foo char:'c' float:2.3 double:3.5 long:2345L]; + + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/encode-3.m b/gcc/testsuite/objc.dg/encode-3.m new file mode 100644 index 000000000..c1327c1e6 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-3.m @@ -0,0 +1,113 @@ +/* Method encoding tests for stand-alone @protocol declarations. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef __NEXT_RUNTIME__ +# include <objc/objc-api.h> +#endif +#include "../objc-obj-c++-shared/objc-test-suite-types.h" +#include "../objc-obj-c++-shared/next-mapping.h" +#include <objc/Protocol.h> + +extern int sscanf(const char *str, const char *format, ...); +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +enum Enum { + zero, one, two, three +}; +typedef enum Enum Enum; +typedef signed char ObjCBool; /* as used by the NeXT runtime */ + +@protocol Proto +union __XXAngle { unsigned int alpha, beta; }; +typedef struct { float x, y; union __XXAngle a; } XXPoint; +typedef struct { double width, height; } XXSize; +typedef struct _XXRect { XXPoint origin; XXSize size; struct _XXRect *next; } XXRect; +- (void) char:(signed char)c float:(float)f double:(double)d unsigned:(unsigned)u short:(short)s long:(long)l; +- (void *)setRect:(XXRect)r withBool:(ProtoBool)b withInt:(int)i; ++ (Enum *)getEnum:(XXPoint *)pt enum:(enum Enum)e bool:(ObjCBool)b; ++ (ProtoBool **)getBool:(ObjCBool **)b; +@end + +Protocol *proto; +struct objc_method_description *meth; +#ifdef NEXT_OBJC_USE_NEW_INTERFACE +struct objc_method_description meth_object; +#endif +unsigned totsize, offs0, offs1, offs2, offs3, offs4, offs5, offs6, offs7; + +static void scan_initial(const char *pattern) { + totsize = offs0 = offs1 = offs2 = offs3 = offs4 = offs5 = offs6 = offs7 = (unsigned)-1; + sscanf(meth->types, pattern, &totsize, &offs0, &offs1, &offs2, &offs3, + &offs4, &offs5, &offs6, &offs7); + CHECK_IF(!offs0 && offs1 == sizeof(id) && offs2 == offs1 + sizeof(SEL) && totsize >= offs2); +} + +int main(void) { + const char *string; + proto = @protocol(Proto); +#ifdef NEXT_OBJC_USE_NEW_INTERFACE + meth_object = protocol_getMethodDescription (proto, + @selector(char:float:double:unsigned:short:long:), YES, YES); + meth = &meth_object; +#else + meth = [proto descriptionForInstanceMethod: @selector(char:float:double:unsigned:short:long:)]; +#endif + if (sizeof (long) == 8) + string = "v%u@%u:%uc%uf%ud%uI%us%uq%u"; + else + string = "v%u@%u:%uc%uf%ud%uI%us%ul%u"; + scan_initial(string); + CHECK_IF(offs3 == offs2 + sizeof(int) && offs4 == offs3 + sizeof(float)); + CHECK_IF(offs5 == offs4 + sizeof(double) && offs6 == offs5 + sizeof(unsigned)); + CHECK_IF(offs7 == offs6 + sizeof(int) && totsize == offs7 + sizeof(long)); +#ifdef NEXT_OBJC_USE_NEW_INTERFACE + meth_object = protocol_getMethodDescription (proto, + @selector(setRect:withBool:withInt:), YES, YES); + meth = &meth_object; +#else + meth = [proto descriptionForInstanceMethod: @selector(setRect:withBool:withInt:)]; +#endif + scan_initial("^v%u@%u:%u{_XXRect={?=ff(__XXAngle=II)}{?=dd}^{_XXRect}}%uB%ui%u"); + CHECK_IF(offs3 == offs2 + sizeof(XXRect) && offs4 == offs3 + sizeof(int)); + CHECK_IF(totsize == offs4 + sizeof(int)); +#ifdef NEXT_OBJC_USE_NEW_INTERFACE + meth_object = protocol_getMethodDescription (proto, + @selector(getEnum:enum:bool:), YES, NO); + meth = &meth_object; +#else + meth = [proto descriptionForClassMethod: @selector(getEnum:enum:bool:)]; +#endif + + /* Here we have the complication that 'enum Enum' could be encoded + as 'i' on __NEXT_RUNTIME_, and (most likely) as 'I' on the GNU + runtime. So we get the @encode(enum Enum), then put it into the + string in place of the traditional 'i'. + */ + /* scan_initial("^i%u@%u:%u^{?=ff(__XXAngle=II)}%ui%uc%u"); */ + { + char pattern[1024]; + + sprintf (pattern, "^%s%%u@%%u:%%u^{?=ff(__XXAngle=II)}%%u%s%%uc%%u", + @encode(enum Enum), @encode(enum Enum)); + scan_initial(pattern); + } + + CHECK_IF(offs3 == offs2 + sizeof(XXPoint *) && offs4 == offs3 + sizeof(enum Enum)); + CHECK_IF(totsize == offs4 + sizeof(int)); /* 'ObjCBool' is really 'char' */ +#ifdef NEXT_OBJC_USE_NEW_INTERFACE + meth_object = protocol_getMethodDescription (proto, + @selector(getBool:), YES, NO); + meth = &meth_object; +#else + meth = [proto descriptionForClassMethod: @selector(getBool:)]; +#endif + scan_initial("^^B%u@%u:%u^*%u"); + CHECK_IF(totsize == offs2 + sizeof(ObjCBool **)); + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-4.m b/gcc/testsuite/objc.dg/encode-4.m new file mode 100644 index 000000000..d74c0ba1c --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-4.m @@ -0,0 +1,93 @@ +/* Encoding tests for ObjC class layouts. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "" } */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include "../objc-obj-c++-shared/next-mapping.h" +#ifdef __NEXT_RUNTIME__ +#include <objc/objc-class.h> +#else +#include <objc/objc-api.h> +#endif + +extern void abort(void); +extern int strcmp(const char *s1, const char *s2); + +#define CHECK_IF(expr) if(!(expr)) abort() + +@class Int1, Int2; +struct Nested; + +struct Innermost { + unsigned char a, b; + struct Nested *encl; +}; + +struct Nested { + float a, b; + Int1 *next; + struct Innermost innermost; +}; + +@interface Int1: Object { + signed char a, b; + Int2 *int2; + struct Nested nested; +} +@end + +@interface Int2: Int1 { + struct Innermost *innermost; + Int1 *base; +} +@end + +@implementation Int1 +@end + +@implementation Int2 +@end + +#ifdef NEXT_OBJC_USE_NEW_INTERFACE +Ivar *ivar; +#else +struct objc_ivar *ivar; +#endif + +static void check_ivar(const char *name, const char *type) { +#ifdef NEXT_OBJC_USE_NEW_INTERFACE + CHECK_IF(!strcmp(ivar_getName(*ivar), name)); + CHECK_IF(!strcmp(ivar_getTypeEncoding(*ivar), type)); +#else + CHECK_IF(!strcmp(ivar->ivar_name, name)); + CHECK_IF(!strcmp(ivar->ivar_type, type)); +#endif + ivar++; +} + +int main(void) { +#ifdef NEXT_OBJC_USE_NEW_INTERFACE + ivar = class_copyIvarList ((Class)objc_get_class("Int1"), NULL); +#else + ivar = ((Class)objc_get_class("Int1"))->ivars->ivar_list; +#endif + check_ivar("a", "c"); + check_ivar("b", "c"); + check_ivar("int2", "@\"Int2\""); + check_ivar("nested", + "{Nested=\"a\"f\"b\"f\"next\"@\"Int1\"\"innermost\"{Innermost=\"a\"C\"b\"C\"encl\"^{Nested}}}"); + +#ifdef NEXT_OBJC_USE_NEW_INTERFACE + ivar = class_copyIvarList ((Class)objc_get_class("Int2"), NULL); +#else + ivar = ((Class)objc_get_class("Int2"))->ivars->ivar_list; +#endif + check_ivar("innermost", "^{Innermost=CC^{Nested}}"); + check_ivar("base", "@\"Int1\""); + + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/encode-5.m b/gcc/testsuite/objc.dg/encode-5.m new file mode 100644 index 000000000..523c7ce02 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-5.m @@ -0,0 +1,76 @@ +/* Check if array arguments of ObjC methods are decayed to pointer types + in a proper fashion: + (1) The _encodings_ for the array arguments should remain to be '[4i]' and + such, since this has been the case since at least gcc 3.3. + (2) However, when building the static C functions out of ObjC method signatures, + we need to decay the arrays into pointers (as C does). + (3) If array size is not known (e.g., 'int a[]'), then the type shall be + encoded as a pointer. */ + +/* Contributed by Alexander Malmberg <alexander@malmberg.org> */ + +#include "../objc-obj-c++-shared/Object1.h" +#include "../objc-obj-c++-shared/next-mapping.h" +#include <stdlib.h> +#include <stdio.h> +#define CHECK_IF(expr) if(!(expr)) abort() + +#ifdef __NEXT_RUNTIME__ +#define METHOD Method +#else +#include <objc/objc-api.h> +#define METHOD Method_t +#define method_get_types(M) (M)->method_types +#endif + +@interface Test : Object +{ float j; } +-(void) test2: (int [5])a with: (int [])b; +-(id) test3: (Test **)b; /* { dg-message "previous declaration of .\\-\\(id\\)test3:\\(Test \\*\\*\\)b." } */ +@end + +@implementation Test +-(void) test2: (int [5])a with: (int [])b +{ + a[3] = *b; +} +-(void) test3: (Test [3][4])b { /* { dg-warning "conflicting types for .\\-\\(void\\)test3:\\(Test \\\[3\\\]\\\[4\\\]\\)b." } */ +} +@end + +int bb[6] = { 0, 1, 2, 3, 4, 5 }; +int *b = bb; +Test *cc[4]; +Test **c = cc; + +int offs1, offs2, offs3, offs4, offs5, offs6; + +int main(int argc, char **argv) +{ + Class testClass = objc_get_class("Test"); + METHOD meth; + + cc[0] = [Test new]; + CHECK_IF (bb[3] == 3); + [*c test2: b with: bb + 4]; + CHECK_IF (bb[3] == 4); + bb[3] = 0; + [*c test2: bb with: bb + 5]; + CHECK_IF (bb[3] == 5); + + meth = class_get_instance_method(testClass, @selector(test2:with:)); + offs1 = offs2 = offs3 = offs4 = offs5 = offs6 = -1; + sscanf(method_get_types(meth), "v%d@%d:%d[%di]%d^i%d", &offs1, &offs2, &offs3, + &offs4, &offs5, &offs6); + CHECK_IF (!offs2 && offs4 == 5 && offs3 > 0); + CHECK_IF (offs5 == 2 * offs3 && offs6 == 3 * offs3 && offs1 == 4 * offs3); + + meth = class_get_instance_method(testClass, @selector(test3:)); + offs1 = offs2 = offs3 = offs4 = offs5 = offs6 = -1; + sscanf(method_get_types(meth), "v%d@%d:%d[%d[%d{Test=#f}]]%d", &offs1, &offs2, &offs3, + &offs4, &offs5, &offs6); + CHECK_IF (!offs2 && offs4 == 3 && offs5 == 4 && offs3 > 0); + CHECK_IF (offs6 == 2 * offs3 && offs1 == 3 * offs3); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-6-next.m b/gcc/testsuite/objc.dg/encode-6-next.m new file mode 100644 index 000000000..c3d922659 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-6-next.m @@ -0,0 +1,23 @@ +/* Test for graceful encoding of const-qualified fields and parameters. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ + +struct Cxx { + const struct Cxx *next; +}; + +@interface ObjC { + const struct Cxx *obj; +} +- (ObjC *)initWithCxx: (struct Cxx *const)c and: (const struct Cxx *)d; +@end + +@implementation ObjC +- (ObjC *)initWithCxx: (struct Cxx *const)c and: (const struct Cxx *)d { + obj = d; + return self; +} +@end + +/* { dg-final { scan-assembler "@\[0-9\]+@0:\[0-9\]+\\^{Cxx=\\^{Cxx}}\[0-9\]+r\\^{Cxx=\\^{Cxx}}" } } */ diff --git a/gcc/testsuite/objc.dg/encode-6.m b/gcc/testsuite/objc.dg/encode-6.m new file mode 100644 index 000000000..291a41e96 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-6.m @@ -0,0 +1,23 @@ +/* Test for graceful encoding of const-qualified fields and parameters. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +struct Cxx { + const struct Cxx *next; +}; + +@interface ObjC { + const struct Cxx *obj; +} +- (ObjC *)initWithCxx: (struct Cxx *const)c and: (const struct Cxx *)d; +@end + +@implementation ObjC +- (ObjC *)initWithCxx: (struct Cxx *const)c and: (const struct Cxx *)d { + obj = d; + return self; +} +@end + +/* { dg-final { scan-assembler "@\[0-9\]+@0:\[0-9\]+r\\^{Cxx=\\^r{Cxx}}\[0-9\]+\\^r{Cxx}" } } */ diff --git a/gcc/testsuite/objc.dg/encode-7-next-64bit.m b/gcc/testsuite/objc.dg/encode-7-next-64bit.m new file mode 100644 index 000000000..60129f9d2 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-7-next-64bit.m @@ -0,0 +1,270 @@ +/* Additional testing for the NeXT runtime. Encoding in -m64 mode */ + +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <objc/Object.h> +#include "../objc-obj-c++-shared/next-mapping.h" + +#define CHECK_IF(E) if (!(E)) abort () + +@class NSDictionary, NSFont, NSError, _NSATSTypesetterGuts, NSString, NSMenu, NSArray; + +typedef unsigned char UInt8; +typedef const signed long OSStatus; +typedef unsigned long CFIndex; +typedef unsigned int UInt32; +typedef UInt32 FourCharCode; +typedef FourCharCode OSType; + +struct FSRef { + UInt8 hidden[80]; +}; +typedef struct FSRef FSRef; + +typedef struct _NSPoint { + float x; + float y; +} NSPoint; + +typedef struct _NSSize { + float width; + float height; +} NSSize; + +typedef struct _NSRect { + NSPoint origin; + NSSize size; +} NSRect; + +typedef struct _NSRange { + unsigned int location; + unsigned int length; +} NSRange; + +typedef const char *NXAtom; + +typedef struct { + NSDictionary *_attributes; + NSFont *_font; + CFIndex _characterLength; + CFIndex _nominalGlyphLocation; + const CFIndex *p; + float _defaultLineHeight; + float _defaultBaselineOffset; + float _horizExpansion; + float _baselineDelta; + NSRect _attachmentBBox; + long ll, *llp; + unsigned long ull, *ullp; + id a; + const id a1; + const struct objc_object *a2; + SEL b; + const SEL b1; + const struct objc_selector *b2; + const char *str1; + char *str2; + char *const str3; + const char *const str4; + struct { + unsigned int _isAttachmentRun:1; + unsigned int _hasPositionalStake:1; + unsigned int _isDefaultFace:1; + unsigned int _hasCombiningMarks:1; + unsigned int _isScreenFont:1; + unsigned int _reserved:27; + } _rFlags; +} NSATSGlyphStorageRun; + +typedef struct __CFSet *CFMutableSetRef; +typedef const struct __CTLine * CTLineRef; +typedef const struct __NSAppleEventManagerSuspension* NSAppleEventManagerSuspensionID; + +struct ComponentInstanceRecord { + long data[1]; +}; +typedef struct ComponentInstanceRecord ComponentInstanceRecord; +typedef ComponentInstanceRecord *ComponentInstance; + +typedef NSString *(*NSErrorUserInfoFormatterFunc)(id objToBeDisplayed, NSError *err, char modifier); +typedef struct { + NSErrorUserInfoFormatterFunc formatterFunc; + NSString *userInfoKey; + unsigned int parameterMask; +} NSErrorUserInfoFormatter; + +typedef Object MyObj; +typedef Object *MyPtr; + +@interface Foo: Object { + NSATSGlyphStorageRun r; +} +- (NSError *)_errorWithOSStatus:(OSStatus)inOSStatus ref1:(const FSRef *)inRef1 ref2:(const struct FSRef *)inRef2 + reading:(BOOL)inReadingNotWriting; +- (const NSATSGlyphStorageRun *)_attributeRunForCharacterAtIndex:(const CFIndex)charIndex; +- (const _NSATSTypesetterGuts *)_getATSTypesetterGuts:(const struct objc_selector *)sel; +- (void)resumeWithSuspensionID:(NSAppleEventManagerSuspensionID)suspensionID and:(const CFIndex *)status; +- (const id)anotherMeth:(const SEL)sel and:(const Foo *)foo and:(const struct objc_object *)obj; +- (id)str1:(const char *)str1 str2:(char *)str2 str3:(char *const)str3 str4:(const char *const)str4; +- (oneway void)foo1:(Foo *)foo1 foo2:(const Foo *)foo2 foo3:(Foo *const)foo3 foo4:(const Foo *const)foo4; +- (in const char *)sel1:(const SEL)sel1 id1:(const id)id1; +- (inout id)obj1:(const MyPtr)obj1 obj2:(Object *const)obj2 obj3:(MyObj *const)obj3; ++ (ComponentInstance)_defaultScriptingComponent; +- (NSString *)_formatCocoaErrorString:(NSString *)formatString parameters:(const char *)parameters + applicableFormatters:(NSErrorUserInfoFormatter **)formatters count:(int)numFormatters; +- (NSErrorUserInfoFormatter *)formatter_func:(id)obj run:(const NSATSGlyphStorageRun **)run; +- (BOOL)_forgetWord:(bycopy in NSString *)word inDictionary:(bycopy in NSString *)language; +- (void)_registerServicesMenu:(NSMenu *)servicesMenu withSendTypes:(const NXAtom *)sendTypes + andReturnTypes:(const NXAtom *)returnTypes addToList:(BOOL)addToList; ++ (CFMutableSetRef *)_proxySharePointer; +- (NSRange)_checkGrammarInString:(in NSString *)stringToCheck language:(bycopy in NSString *)language details:(bycopy out NSArray **)details; +- (bool)_resolvePositionalStakeGlyphsForLineFragment:(CTLineRef)line lineFragmentRect:(NSRect)lineFragmentRect + minPosition:(float)minPosition maxPosition:(float)maxPosition maxLineFragmentWidth:(float)maxLineFragmentWidth + breakHint:(CFIndex *)charIndex; ++ (BOOL)findVoiceByIdentifier:(NSString *)identifier returningCreator:(OSType *)returnedCreator returningID:(OSType *)returnedID; +@end + +NSRange globalRange; + +@implementation Foo +- (NSError *)_errorWithOSStatus:(OSStatus)inOSStatus ref1:(const FSRef *)inRef1 ref2:(const struct FSRef *)inRef2 + reading:(BOOL)inReadingNotWriting { + return (NSError *)self; +} +- (const NSATSGlyphStorageRun *)_attributeRunForCharacterAtIndex:(CFIndex)charIndex { + return (const NSATSGlyphStorageRun *)self; +} +- (const _NSATSTypesetterGuts *)_getATSTypesetterGuts:(const struct objc_selector *)sel { + return (const _NSATSTypesetterGuts *)self; +} +- (void)resumeWithSuspensionID:(NSAppleEventManagerSuspensionID)suspensionID and:(const CFIndex *)status { +} +- (const id)anotherMeth:(const SEL)sel and:(const Foo *)foo and:(const struct objc_object *)obj { + return (const id)self; +} +- (id)str1:(const char *)str1 str2:(char *)str2 str3:(char *const)str3 str4:(const char *const)str4 { + return self; +} +- (oneway void)foo1:(Foo *)foo1 foo2:(const Foo *)foo2 foo3:(Foo *const)foo3 foo4:(const Foo *const)foo4 { +} +- (in const char *)sel1:(const SEL)sel1 id1:(const id)id1 { + return "Hello"; +} +- (inout id)obj1:(const MyPtr)obj1 obj2:(Object *const)obj2 obj3:(MyObj *const)obj3 { + return self; +} ++ (ComponentInstance)_defaultScriptingComponent { + return (ComponentInstance)0; +} +- (NSString *)_formatCocoaErrorString:(NSString *)formatString parameters:(const char *)parameters + applicableFormatters:(NSErrorUserInfoFormatter **)formatters count:(int)numFormatters { + return (NSString *)self; +} +- (NSErrorUserInfoFormatter *)formatter_func:(id)obj run:(const NSATSGlyphStorageRun **)run { + return (NSErrorUserInfoFormatter *)0; +} +- (BOOL)_forgetWord:(bycopy in NSString *)word inDictionary:(bycopy in NSString *)language { + return YES; +} +- (void)_registerServicesMenu:(NSMenu *)servicesMenu withSendTypes:(const NXAtom *)sendTypes + andReturnTypes:(const NXAtom *)returnTypes addToList:(BOOL)addToList { +} ++ (CFMutableSetRef *)_proxySharePointer { + return (CFMutableSetRef *)0; +} +- (NSRange)_checkGrammarInString:(in NSString *)stringToCheck language:(bycopy in NSString *)language details:(bycopy out NSArray **)details { + return globalRange; +} +- (bool)_resolvePositionalStakeGlyphsForLineFragment:(CTLineRef)line lineFragmentRect:(NSRect)lineFragmentRect + minPosition:(float)minPosition maxPosition:(float)maxPosition maxLineFragmentWidth:(float)maxLineFragmentWidth + breakHint:(CFIndex *)charIndex { + return false; +} ++ (BOOL)findVoiceByIdentifier:(NSString *)identifier returningCreator:(OSType *)returnedCreator returningID:(OSType *)returnedID { + return NO; +} +@end + +int main(void) { + Class fooClass = objc_getClass ("Foo"); + Method meth; + Ivar *ivars; + unsigned int ivar_count; + Ivar ivar; + + meth = class_getInstanceMethod (fooClass, @selector(_errorWithOSStatus:ref1:ref2:reading:)); + CHECK_IF (!strcmp (method_getTypeEncoding(meth), "@44@0:8q16r^{FSRef=[80C]}24r^{FSRef=[80C]}32c40")); + + meth = class_getInstanceMethod (fooClass, @selector(_attributeRunForCharacterAtIndex:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "r^{?=@@QQ^Qffff{_NSRect={_NSPoint=ff}{_NSSize=ff}}q^qQ^Q@@@:::****{?=b1b1b1b1b1b27}}24@0:8Q16")); + + meth = class_getInstanceMethod (fooClass, @selector(_getATSTypesetterGuts:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "r@24@0:8r:16")); + + meth = class_getInstanceMethod (fooClass, @selector(resumeWithSuspensionID:and:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "v32@0:8^{__NSAppleEventManagerSuspension=}16r^Q24")); + + meth = class_getInstanceMethod (fooClass, @selector(anotherMeth:and:and:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "r@40@0:8r:16r@24r@32")); + + meth = class_getInstanceMethod (fooClass, @selector(str1:str2:str3:str4:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "@48@0:8r*16*24*32r*40")); + + meth = class_getInstanceMethod (fooClass, @selector(foo1:foo2:foo3:foo4:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "Vv48@0:8@16r@24@32r@40")); + + meth = class_getInstanceMethod (fooClass, @selector(sel1:id1:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "rn*32@0:8r:16r@24")); + + meth = class_getInstanceMethod (fooClass, @selector(obj1:obj2:obj3:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "N@40@0:8r@16@24^{Object=#}32")); + + meth = class_getClassMethod (fooClass, @selector(_defaultScriptingComponent)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "^{ComponentInstanceRecord=[1q]}16@0:8")); + + meth = class_getInstanceMethod (fooClass, @selector(_formatCocoaErrorString:parameters:applicableFormatters:count:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "@44@0:8@16r*24^^{?}32i40")); + + meth = class_getInstanceMethod (fooClass, @selector(formatter_func:run:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "^{?=^?@I}32@0:8@16r^^{?}24")); + + meth = class_getInstanceMethod (fooClass, @selector(_forgetWord:inDictionary:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "c32@0:8nO@16nO@24")); + + meth = class_getInstanceMethod (fooClass, @selector(_registerServicesMenu:withSendTypes:andReturnTypes:addToList:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "v44@0:8@16r^*24r^*32c40")); + + meth = class_getClassMethod (fooClass, @selector(_proxySharePointer)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "^^{__CFSet}16@0:8")); + + meth = class_getInstanceMethod (fooClass, @selector(_checkGrammarInString:language:details:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "{_NSRange=II}40@0:8n@16nO@24oO^@32")); + + meth = class_getInstanceMethod (fooClass, @selector(_resolvePositionalStakeGlyphsForLineFragment:lineFragmentRect:minPosition:maxPosition:maxLineFragmentWidth:breakHint:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "B60@0:8^{__CTLine=}16{_NSRect={_NSPoint=ff}{_NSSize=ff}}24f40f44f48^Q52")); + + meth = class_getClassMethod (fooClass, @selector(findVoiceByIdentifier:returningCreator:returningID:)); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "c40@0:8@16^I24^I32")); + + ivars = class_copyIvarList (fooClass, &ivar_count); + CHECK_IF (ivar_count == 1); + + ivar = ivars[0]; + CHECK_IF (!strcmp (ivar_getName(ivar), "r")); + CHECK_IF (!strcmp (ivar_getTypeEncoding(ivar), + "{?=\"_attributes\"@\"NSDictionary\"\"_font\"@\"NSFont\"\"_characterLength\"" + "Q\"_nominalGlyphLocation\"Q\"p\"^Q\"_defaultLineHeight\"f\"_defaultBaselineOffset\"" + "f\"_horizExpansion\"f\"_baselineDelta\"f\"_attachmentBBox\"{_NSRect=\"origin\"" + "{_NSPoint=\"x\"f\"y\"f}\"size\"{_NSSize=\"width\"f\"height\"f}}\"ll\"q\"llp\"^q\"ull\"" + "Q\"ullp\"^Q\"a\"@\"a1\"@\"a2\"@\"b\":\"b1\":\"b2\":\"str1\"*\"str2\"*\"str3\"*\"str4\"" + "*\"_rFlags\"{?=\"_isAttachmentRun\"b1\"_hasPositionalStake\"b1\"_isDefaultFace\"" + "b1\"_hasCombiningMarks\"b1\"_isScreenFont\"b1\"_reserved\"b27}}")); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-7-next.m b/gcc/testsuite/objc.dg/encode-7-next.m new file mode 100644 index 000000000..2768e115f --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-7-next.m @@ -0,0 +1,269 @@ +/* Additional testing for the NeXT runtime. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-require-effective-target ilp32 } */ +/* { dg-options "-Wno-deprecated-declarations" } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include "../objc-obj-c++-shared/next-mapping.h" +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#define CHECK_IF(E) if (!(E)) abort () + +@class NSDictionary, NSFont, NSError, _NSATSTypesetterGuts, NSString, NSMenu, NSArray; + +typedef unsigned char UInt8; +typedef const signed long OSStatus; +typedef unsigned long CFIndex; +typedef unsigned int UInt32; +typedef UInt32 FourCharCode; +typedef FourCharCode OSType; + +struct FSRef { + UInt8 hidden[80]; +}; +typedef struct FSRef FSRef; + +typedef struct _NSPoint { + float x; + float y; +} NSPoint; + +typedef struct _NSSize { + float width; + float height; +} NSSize; + +typedef struct _NSRect { + NSPoint origin; + NSSize size; +} NSRect; + +typedef struct _NSRange { + unsigned int location; + unsigned int length; +} NSRange; + +typedef const char *NXAtom; + +typedef struct { + NSDictionary *_attributes; + NSFont *_font; + CFIndex _characterLength; + CFIndex _nominalGlyphLocation; + const CFIndex *p; + float _defaultLineHeight; + float _defaultBaselineOffset; + float _horizExpansion; + float _baselineDelta; + NSRect _attachmentBBox; + long ll, *llp; + unsigned long ull, *ullp; + id a; + const id a1; + const struct objc_object *a2; + SEL b; + const SEL b1; + const struct objc_selector *b2; + const char *str1; + char *str2; + char *const str3; + const char *const str4; + struct { + unsigned int _isAttachmentRun:1; + unsigned int _hasPositionalStake:1; + unsigned int _isDefaultFace:1; + unsigned int _hasCombiningMarks:1; + unsigned int _isScreenFont:1; + unsigned int _reserved:27; + } _rFlags; +} NSATSGlyphStorageRun; + +typedef struct __CFSet *CFMutableSetRef; +typedef const struct __CTLine * CTLineRef; +typedef const struct __NSAppleEventManagerSuspension* NSAppleEventManagerSuspensionID; + +struct ComponentInstanceRecord { + long data[1]; +}; +typedef struct ComponentInstanceRecord ComponentInstanceRecord; +typedef ComponentInstanceRecord *ComponentInstance; + +typedef NSString *(*NSErrorUserInfoFormatterFunc)(id objToBeDisplayed, NSError *err, char modifier); +typedef struct { + NSErrorUserInfoFormatterFunc formatterFunc; + NSString *userInfoKey; + unsigned int parameterMask; +} NSErrorUserInfoFormatter; + +typedef Object MyObj; +typedef Object *MyPtr; + +@interface Foo: Object { + NSATSGlyphStorageRun r; +} +- (NSError *)_errorWithOSStatus:(OSStatus)inOSStatus ref1:(const FSRef *)inRef1 ref2:(const struct FSRef *)inRef2 + reading:(BOOL)inReadingNotWriting; +- (const NSATSGlyphStorageRun *)_attributeRunForCharacterAtIndex:(const CFIndex)charIndex; +- (const _NSATSTypesetterGuts *)_getATSTypesetterGuts:(const struct objc_selector *)sel; +- (void)resumeWithSuspensionID:(NSAppleEventManagerSuspensionID)suspensionID and:(const CFIndex *)status; +- (const id)anotherMeth:(const SEL)sel and:(const Foo *)foo and:(const struct objc_object *)obj; +- (id)str1:(const char *)str1 str2:(char *)str2 str3:(char *const)str3 str4:(const char *const)str4; +- (oneway void)foo1:(Foo *)foo1 foo2:(const Foo *)foo2 foo3:(Foo *const)foo3 foo4:(const Foo *const)foo4; +- (in const char *)sel1:(const SEL)sel1 id1:(const id)id1; +- (inout id)obj1:(const MyPtr)obj1 obj2:(Object *const)obj2 obj3:(MyObj *const)obj3; ++ (ComponentInstance)_defaultScriptingComponent; +- (NSString *)_formatCocoaErrorString:(NSString *)formatString parameters:(const char *)parameters + applicableFormatters:(NSErrorUserInfoFormatter **)formatters count:(int)numFormatters; +- (NSErrorUserInfoFormatter *)formatter_func:(id)obj run:(const NSATSGlyphStorageRun **)run; +- (BOOL)_forgetWord:(bycopy in NSString *)word inDictionary:(bycopy in NSString *)language; +- (void)_registerServicesMenu:(NSMenu *)servicesMenu withSendTypes:(const NXAtom *)sendTypes + andReturnTypes:(const NXAtom *)returnTypes addToList:(BOOL)addToList; ++ (CFMutableSetRef *)_proxySharePointer; +- (NSRange)_checkGrammarInString:(in NSString *)stringToCheck language:(bycopy in NSString *)language details:(bycopy out NSArray **)details; +- (bool)_resolvePositionalStakeGlyphsForLineFragment:(CTLineRef)line lineFragmentRect:(NSRect)lineFragmentRect + minPosition:(float)minPosition maxPosition:(float)maxPosition maxLineFragmentWidth:(float)maxLineFragmentWidth + breakHint:(CFIndex *)charIndex; ++ (BOOL)findVoiceByIdentifier:(NSString *)identifier returningCreator:(OSType *)returnedCreator returningID:(OSType *)returnedID; +@end + +NSRange globalRange; + +@implementation Foo +- (NSError *)_errorWithOSStatus:(OSStatus)inOSStatus ref1:(const FSRef *)inRef1 ref2:(const struct FSRef *)inRef2 + reading:(BOOL)inReadingNotWriting { + return (NSError *)self; +} +- (const NSATSGlyphStorageRun *)_attributeRunForCharacterAtIndex:(CFIndex)charIndex { + return (const NSATSGlyphStorageRun *)self; +} +- (const _NSATSTypesetterGuts *)_getATSTypesetterGuts:(const struct objc_selector *)sel { + return (const _NSATSTypesetterGuts *)self; +} +- (void)resumeWithSuspensionID:(NSAppleEventManagerSuspensionID)suspensionID and:(const CFIndex *)status { +} +- (const id)anotherMeth:(const SEL)sel and:(const Foo *)foo and:(const struct objc_object *)obj { + return (const id)self; +} +- (id)str1:(const char *)str1 str2:(char *)str2 str3:(char *const)str3 str4:(const char *const)str4 { + return self; +} +- (oneway void)foo1:(Foo *)foo1 foo2:(const Foo *)foo2 foo3:(Foo *const)foo3 foo4:(const Foo *const)foo4 { +} +- (in const char *)sel1:(const SEL)sel1 id1:(const id)id1 { + return "Hello"; +} +- (inout id)obj1:(const MyPtr)obj1 obj2:(Object *const)obj2 obj3:(MyObj *const)obj3 { + return self; +} ++ (ComponentInstance)_defaultScriptingComponent { + return (ComponentInstance)0; +} +- (NSString *)_formatCocoaErrorString:(NSString *)formatString parameters:(const char *)parameters + applicableFormatters:(NSErrorUserInfoFormatter **)formatters count:(int)numFormatters { + return (NSString *)self; +} +- (NSErrorUserInfoFormatter *)formatter_func:(id)obj run:(const NSATSGlyphStorageRun **)run { + return (NSErrorUserInfoFormatter *)0; +} +- (BOOL)_forgetWord:(bycopy in NSString *)word inDictionary:(bycopy in NSString *)language { + return YES; +} +- (void)_registerServicesMenu:(NSMenu *)servicesMenu withSendTypes:(const NXAtom *)sendTypes + andReturnTypes:(const NXAtom *)returnTypes addToList:(BOOL)addToList { +} ++ (CFMutableSetRef *)_proxySharePointer { + return (CFMutableSetRef *)0; +} +- (NSRange)_checkGrammarInString:(in NSString *)stringToCheck language:(bycopy in NSString *)language details:(bycopy out NSArray **)details { + return globalRange; +} +- (bool)_resolvePositionalStakeGlyphsForLineFragment:(CTLineRef)line lineFragmentRect:(NSRect)lineFragmentRect + minPosition:(float)minPosition maxPosition:(float)maxPosition maxLineFragmentWidth:(float)maxLineFragmentWidth + breakHint:(CFIndex *)charIndex { + return false; +} ++ (BOOL)findVoiceByIdentifier:(NSString *)identifier returningCreator:(OSType *)returnedCreator returningID:(OSType *)returnedID { + return NO; +} +@end + +int main(void) { + Class fooClass = objc_getClass ("Foo"); + Method meth; + struct objc_ivar_list *ivars; + struct objc_ivar *ivar; + + meth = class_getInstanceMethod (fooClass, @selector(_errorWithOSStatus:ref1:ref2:reading:)); + CHECK_IF (!strcmp (meth->method_types, "@24@0:4l8r^{FSRef=[80C]}12r^{FSRef=[80C]}16c20")); + + meth = class_getInstanceMethod (fooClass, @selector(_attributeRunForCharacterAtIndex:)); + CHECK_IF (!strcmp (meth->method_types, "r^{?=@@II^Iffff{_NSRect={_NSPoint=ff}{_NSSize=ff}}l^lL^L@@@:::****{?=b1b1b1b1b1b27}}12@0:4L8")); + + meth = class_getInstanceMethod (fooClass, @selector(_getATSTypesetterGuts:)); + CHECK_IF (!strcmp (meth->method_types, "r@12@0:4r:8")); + + meth = class_getInstanceMethod (fooClass, @selector(resumeWithSuspensionID:and:)); + CHECK_IF (!strcmp (meth->method_types, "v16@0:4^{__NSAppleEventManagerSuspension=}8r^I12")); + + meth = class_getInstanceMethod (fooClass, @selector(anotherMeth:and:and:)); + CHECK_IF (!strcmp (meth->method_types, "r@20@0:4r:8r@12r@16")); + + meth = class_getInstanceMethod (fooClass, @selector(str1:str2:str3:str4:)); + CHECK_IF (!strcmp (meth->method_types, "@24@0:4r*8*12*16r*20")); + + meth = class_getInstanceMethod (fooClass, @selector(foo1:foo2:foo3:foo4:)); + CHECK_IF (!strcmp (meth->method_types, "Vv24@0:4@8r@12@16r@20")); + + meth = class_getInstanceMethod (fooClass, @selector(sel1:id1:)); + CHECK_IF (!strcmp (meth->method_types, "rn*16@0:4r:8r@12")); + + meth = class_getInstanceMethod (fooClass, @selector(obj1:obj2:obj3:)); + CHECK_IF (!strcmp (meth->method_types, "N@20@0:4r@8@12^{Object=#}16")); + + meth = class_getClassMethod (fooClass, @selector(_defaultScriptingComponent)); + CHECK_IF (!strcmp (meth->method_types, "^{ComponentInstanceRecord=[1l]}8@0:4")); + + meth = class_getInstanceMethod (fooClass, @selector(_formatCocoaErrorString:parameters:applicableFormatters:count:)); + CHECK_IF (!strcmp (meth->method_types, "@24@0:4@8r*12^^{?}16i20")); + + meth = class_getInstanceMethod (fooClass, @selector(formatter_func:run:)); + CHECK_IF (!strcmp (meth->method_types, "^{?=^?@I}16@0:4@8r^^{?}12")); + + meth = class_getInstanceMethod (fooClass, @selector(_forgetWord:inDictionary:)); + CHECK_IF (!strcmp (meth->method_types, "c16@0:4nO@8nO@12")); + + meth = class_getInstanceMethod (fooClass, @selector(_registerServicesMenu:withSendTypes:andReturnTypes:addToList:)); + CHECK_IF (!strcmp (meth->method_types, "v24@0:4@8r^*12r^*16c20")); + + meth = class_getClassMethod (fooClass, @selector(_proxySharePointer)); + CHECK_IF (!strcmp (meth->method_types, "^^{__CFSet}8@0:4")); + + meth = class_getInstanceMethod (fooClass, @selector(_checkGrammarInString:language:details:)); + CHECK_IF (!strcmp (meth->method_types, "{_NSRange=II}20@0:4n@8nO@12oO^@16")); + + meth = class_getInstanceMethod (fooClass, @selector(_resolvePositionalStakeGlyphsForLineFragment:lineFragmentRect:minPosition:maxPosition:maxLineFragmentWidth:breakHint:)); + CHECK_IF (!strcmp (meth->method_types, "B44@0:4^{__CTLine=}8{_NSRect={_NSPoint=ff}{_NSSize=ff}}12f28f32f36^I40")); + + meth = class_getClassMethod (fooClass, @selector(findVoiceByIdentifier:returningCreator:returningID:)); + CHECK_IF (!strcmp (meth->method_types, "c20@0:4@8^I12^I16")); + + ivars = fooClass->ivars; + CHECK_IF (ivars->ivar_count == 1); + + ivar = ivars->ivar_list; + CHECK_IF (!strcmp (ivar->ivar_name, "r")); + CHECK_IF (!strcmp (ivar->ivar_type, + "{?=\"_attributes\"@\"NSDictionary\"\"_font\"@\"NSFont\"\"_characterLength\"" + "I\"_nominalGlyphLocation\"I\"p\"^I\"_defaultLineHeight\"f\"_defaultBaselineOffset\"" + "f\"_horizExpansion\"f\"_baselineDelta\"f\"_attachmentBBox\"{_NSRect=\"origin\"" + "{_NSPoint=\"x\"f\"y\"f}\"size\"{_NSSize=\"width\"f\"height\"f}}\"ll\"l\"llp\"^l\"ull\"" + "L\"ullp\"^L\"a\"@\"a1\"@\"a2\"@\"b\":\"b1\":\"b2\":\"str1\"*\"str2\"*\"str3\"*\"str4\"" + "*\"_rFlags\"{?=\"_isAttachmentRun\"b1\"_hasPositionalStake\"b1\"_isDefaultFace\"" + "b1\"_hasCombiningMarks\"b1\"_isScreenFont\"b1\"_reserved\"b27}}")); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-7.m b/gcc/testsuite/objc.dg/encode-7.m new file mode 100644 index 000000000..1fe0b2424 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-7.m @@ -0,0 +1,18 @@ +/* { dg-do run } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +#include <objc/encoding.h> +#include <stdlib.h> + +struct f +{ + _Bool a; +}; + + +int main(void) +{ + if (objc_sizeof_type (@encode (struct f)) != sizeof(struct f)) + abort (); + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-8.m b/gcc/testsuite/objc.dg/encode-8.m new file mode 100644 index 000000000..a992e3150 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-8.m @@ -0,0 +1,31 @@ +/* { dg-do run } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +#include <objc/encoding.h> +#include <stdlib.h> + +union f +{ + char i; + double f1; + short t; +}; + +union g +{ + int i; +}; + + +int main(void) +{ + if (objc_sizeof_type (@encode (union f)) != sizeof(union f)) + abort (); + if (objc_alignof_type (@encode (union f)) != __alignof__(union f)) + abort (); + if (objc_sizeof_type (@encode (union g)) != sizeof(union g)) + abort (); + if (objc_alignof_type (@encode (union g)) != __alignof__(union g)) + abort (); + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-9.m b/gcc/testsuite/objc.dg/encode-9.m new file mode 100644 index 000000000..1ff2a6b0e --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-9.m @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +/* There was an ICE due to diving by zero in the objc front-end. */ + +struct f +{ + int i; + struct{} g[4]; + int tt; +}; + +char *e = @encode(struct f); diff --git a/gcc/testsuite/objc.dg/enhanced-proto-1.m b/gcc/testsuite/objc.dg/enhanced-proto-1.m new file mode 100644 index 000000000..fef4c97b5 --- /dev/null +++ b/gcc/testsuite/objc.dg/enhanced-proto-1.m @@ -0,0 +1,19 @@ +/* APPLE LOCAL file C* language */ +/* Test use of @optional/@required keywords in @protocol class. */ +/* { dg-do compile } */ + +@protocol MyProto1 +@optional +- (void) FOO; +@optional +- (void) FOO; +@required +- (void) REQ; +@optional +@end + +@protocol MyProto2 <MyProto1> +- (void) FOO2; +@optional +- (void) FOO3; +@end diff --git a/gcc/testsuite/objc.dg/enhanced-proto-2.m b/gcc/testsuite/objc.dg/enhanced-proto-2.m new file mode 100644 index 000000000..c196b5151 --- /dev/null +++ b/gcc/testsuite/objc.dg/enhanced-proto-2.m @@ -0,0 +1,24 @@ +/* Test use of @optional/@required keywords in @protocol class. */ +/* { dg-do compile } */ + +@protocol MyProto1 +@optional +- (void) FOO; +@optional +- (void) FOO; +@optional +- (void) REQ; +@optional +@end + +@interface MyProto2 <MyProto1> +@required /* { dg-error ".@required. is allowed in @protocol context only" } */ +- (void) FOO2; +@optional /* { dg-error ".@optional. is allowed in @protocol context only" } */ +- (void) FOO3; +@end + +@implementation MyProto2 +- (void) FOO2{} +- (void) FOO3{} +@end diff --git a/gcc/testsuite/objc.dg/error-1.m b/gcc/testsuite/objc.dg/error-1.m new file mode 100644 index 000000000..86b9d7faa --- /dev/null +++ b/gcc/testsuite/objc.dg/error-1.m @@ -0,0 +1,6 @@ +/* { dg-options "-w" } */ +/* { dg-do compile } */ +@implementation A ++B ++C {} /* { dg-error "expected '\{' before '\\\+' token" } */ +@end diff --git a/gcc/testsuite/objc.dg/exceptions-1.m b/gcc/testsuite/objc.dg/exceptions-1.m new file mode 100644 index 000000000..0f3b7e8ae --- /dev/null +++ b/gcc/testsuite/objc.dg/exceptions-1.m @@ -0,0 +1,42 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +/* This test checks the syntax @catch (...) which catches any + exceptions. At the moment, @catch (...) is identical to @catch (id + exception). */ + +#include <objc/objc.h> + +@interface MyObject +{ + Class isa; +} +@end + +@implementation MyObject +@end + +int test (id object) +{ + int i = 0; + + @try + { + @throw object; + } + @catch (MyObject *o) + { + i += 1; + } + @catch (...) + { + i += 2; + } + @finally + { + i += 4; + } + + return i; +} diff --git a/gcc/testsuite/objc.dg/exceptions-2.m b/gcc/testsuite/objc.dg/exceptions-2.m new file mode 100644 index 000000000..3e4227cb9 --- /dev/null +++ b/gcc/testsuite/objc.dg/exceptions-2.m @@ -0,0 +1,52 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m" } */ + +/* This test checks the syntax @catch (...) which catches any + exceptions. Check that code using it runs correctly. */ + +#include "../objc-obj-c++-shared/Object1.h" +#include <stdlib.h> + +@interface MyObject : Object +@end + +@implementation MyObject +@end + +int test (id object) +{ + int i = 0; + + @try + { + @throw object; + } + @catch (MyObject *o) + { + i += 1; + } + @catch (...) + { + i += 2; + } + @finally + { + i += 4; + } + + return i; +} + +int main (void) +{ + if (test ([MyObject new]) != 5) + abort (); + + if (test ([Object new]) != 6) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/exceptions-3.m b/gcc/testsuite/objc.dg/exceptions-3.m new file mode 100644 index 000000000..fe9dbfbfa --- /dev/null +++ b/gcc/testsuite/objc.dg/exceptions-3.m @@ -0,0 +1,114 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +/* Test that the compiler is checking the argument of @catch(), and + produce errors when invalid types are used. */ + +#include <objc/objc.h> + +@interface MyObject +{ + Class isa; +} +@end + +@implementation MyObject +@end + +@protocol MyProtocol; + +typedef MyObject MyObjectTypedef; +typedef MyObject *MyObjectPtrTypedef; +typedef int intTypedef; + +int test (id object) +{ + int dummy = 0; + + @try { @throw object; } + @catch (int x) /* { dg-error "@catch parameter is not a known Objective-C class type" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (intTypedef x) /* { dg-error "@catch parameter is not a known Objective-C class type" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (int *x) /* { dg-error "@catch parameter is not a known Objective-C class type" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (id x) /* Ok */ + { + dummy++; + } + + @try { @throw object; } + @catch (id <MyProtocol> x) /* { dg-error "@catch parameter can not be protocol-qualified" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObject *x) /* Ok */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObject <MyProtocol> *x) /* { dg-error "@catch parameter can not be protocol-qualified" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObject x) /* { dg-error "@catch parameter is not a known Objective-C class type" } */ + { /* { dg-error "conversion to non-scalar type requested" "" { target *-*-* } 72 } */ + dummy++; + } + + @try { @throw object; } + @catch (static MyObject *x) /* { dg-error "storage class specified for" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObjectTypedef *x) /* Ok */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObjectTypedef <MyProtocol> *x) /* { dg-error "@catch parameter can not be protocol-qualified" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObjectPtrTypedef x) /* Ok */ + { + dummy++; + } + + @try { @throw object; } + @catch (Class x) /* { dg-error "@catch parameter is not a known Objective-C class type" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (...) /* Ok */ + { + dummy++; + } + + return dummy; +} diff --git a/gcc/testsuite/objc.dg/exceptions-4.m b/gcc/testsuite/objc.dg/exceptions-4.m new file mode 100644 index 000000000..fc07e4f42 --- /dev/null +++ b/gcc/testsuite/objc.dg/exceptions-4.m @@ -0,0 +1,64 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +/* Test warnings when parsing syntax errors in @catch(). */ + +#include <objc/objc.h> + +@interface MyObject +{ + Class isa; +} +@end + +@implementation MyObject +@end + +@interface MyObject2 +{ + Class isa; +} +@end + +@implementation MyObject2 +@end + +@protocol MyProtocol; + +int test (id object) +{ + int dummy = 0; + + @try { @throw object; } + @catch + { /* { dg-error "expected ... before ... token" } */ + dummy++; + } + @catch () /* { dg-error "expected declaration specifiers or ..... before ..." } */ + { + dummy++; + } + @catch (i) /* { dg-error "unknown type name .i." } */ + { + dummy++; + } + @catch (id <MyProtocol x) /* { dg-error "expected ... before .x." } */ + { /* { dg-error "@catch parameter can not be protocol-qualified" "" { target *-*-* } 46 } */ + dummy++; + } + @catch MyObject *x /* { dg-error "expected ... before .MyObject." } */ + { + dummy++; + } + @catch MyObject2 *x) /* { dg-error "expected ... before .MyObject2." } */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObject *x) + @catch (MyObject2 *y) /* { dg-error "expected ... before .catch." } */ + + return dummy; +} diff --git a/gcc/testsuite/objc.dg/exceptions-5.m b/gcc/testsuite/objc.dg/exceptions-5.m new file mode 100644 index 000000000..d89ad2967 --- /dev/null +++ b/gcc/testsuite/objc.dg/exceptions-5.m @@ -0,0 +1,114 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +/* Test that you can use an unnamed argument with @catch. This test is the same + as exceptions-3.m, but with no name for @catch arguments. */ + +#include <objc/objc.h> + +@interface MyObject +{ + Class isa; +} +@end + +@implementation MyObject +@end + +@protocol MyProtocol; + +typedef MyObject MyObjectTypedef; +typedef MyObject *MyObjectPtrTypedef; +typedef int intTypedef; + +int test (id object) +{ + int dummy = 0; + + @try { @throw object; } + @catch (int) /* { dg-error "@catch parameter is not a known Objective-C class type" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (intTypedef) /* { dg-error "@catch parameter is not a known Objective-C class type" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (int *) /* { dg-error "@catch parameter is not a known Objective-C class type" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (id) /* Ok */ + { + dummy++; + } + + @try { @throw object; } + @catch (id <MyProtocol>) /* { dg-error "@catch parameter can not be protocol-qualified" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObject *) /* Ok */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObject <MyProtocol> *) /* { dg-error "@catch parameter can not be protocol-qualified" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObject) /* { dg-error "@catch parameter is not a known Objective-C class type" } */ + { /* { dg-error "conversion to non-scalar type requested" "" { target *-*-* } 72 } */ + dummy++; + } + + @try { @throw object; } + @catch (static MyObject *) /* { dg-error "storage class specified for" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObjectTypedef *) /* Ok */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObjectTypedef <MyProtocol> *) /* { dg-error "@catch parameter can not be protocol-qualified" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (MyObjectPtrTypedef) /* Ok */ + { + dummy++; + } + + @try { @throw object; } + @catch (Class) /* { dg-error "@catch parameter is not a known Objective-C class type" } */ + { + dummy++; + } + + @try { @throw object; } + @catch (...) /* Ok */ + { + dummy++; + } + + return dummy; +} diff --git a/gcc/testsuite/objc.dg/exceptions-6.m b/gcc/testsuite/objc.dg/exceptions-6.m new file mode 100644 index 000000000..58882fed8 --- /dev/null +++ b/gcc/testsuite/objc.dg/exceptions-6.m @@ -0,0 +1,29 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +/* Test warnings when parsing syntax errors in @throw. */ + +#include <objc/objc.h> + +void test (id object) +{ + @throw object; /* Ok */ + @throw; /* { dg-error ".@throw. .rethrow. used outside of a @catch block" } */ + @throw (object); /* Ok. */ + @throw (id)0 +} /* { dg-error "expected" } */ + +void test2 (id object) +{ + @throw object); /* { dg-error "expected" } */ + @throw (...); /* { dg-error "expected" } */ + @throw (); /* { dg-error "expected" } */ + @throw +} /* { dg-error "expected" } */ + +void test3 (id object1, id object2) +{ + /* This is apparently valid. */ + @throw object1, object2; /* Ok. */ +} diff --git a/gcc/testsuite/objc.dg/exceptions-7.m b/gcc/testsuite/objc.dg/exceptions-7.m new file mode 100644 index 000000000..1f5adfc89 --- /dev/null +++ b/gcc/testsuite/objc.dg/exceptions-7.m @@ -0,0 +1,18 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +/* Test warnings when the argument of @throw is invalid. */ + +#include <objc/objc.h> + +void test (id object) +{ + struct x { int i; } invalid_1, *invalid_2; + + @throw object; /* Ok */ + @throw 1; /* { dg-error ".@throw. argument is not an object" } */ + @throw "string"; /* { dg-error ".@throw. argument is not an object" } */ + @throw invalid_1; /* { dg-error ".@throw. argument is not an object" } */ + @throw invalid_2; /* { dg-error ".@throw. argument is not an object" } */ +} diff --git a/gcc/testsuite/objc.dg/extra-semi.m b/gcc/testsuite/objc.dg/extra-semi.m new file mode 100644 index 000000000..ad555962d --- /dev/null +++ b/gcc/testsuite/objc.dg/extra-semi.m @@ -0,0 +1,10 @@ +/* Allow extra semicolons in between method declarations, + for old times' sake. */ + +/* { dg-do compile } */ + +@interface Foo + -(Foo *) expiration; + -(void) setExpiration:(Foo *) date;; + -(int) getVersion; +@end diff --git a/gcc/testsuite/objc.dg/fix-and-continue-1.m b/gcc/testsuite/objc.dg/fix-and-continue-1.m new file mode 100644 index 000000000..1560beac4 --- /dev/null +++ b/gcc/testsuite/objc.dg/fix-and-continue-1.m @@ -0,0 +1,93 @@ +/* Fix and continue should not interfere with computation of + local (static) function addresses. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-options "-mfix-and-continue" } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include <stdlib.h> + +@class MyTarget, MySet; + +int global_value = 0; + +@interface MyTargetBuildContext : Object +{ + MyTarget * _target; + unsigned _cacheInvalDisableCount; + BOOL _cacheInvalidationNeeded; + unsigned short _isCreatingDependencies:1; + unsigned short _isCreatingHeadermap:1; + unsigned short _haveAddedIdleTimeInvoc:1; + BOOL _hasSetUpBuildSettings; +} +- (id)initWithTarget:(MyTarget *)target; +- (MyTarget *)target; +@end + +@interface MyTargetBuildContext (PrivateMethods) ++ (MySet *)_headerFileExtensions; +@end + +@interface MyCountedSet: Object { +@public + int cardinality; +} +- (id)init; +- (id)sortedArrayUsingFunction:(int (*)(id, id, void *))comparator with:(int)value; +@end + +@implementation MyCountedSet +- (id)init { + cardinality = 5; + global_value = 17; + return self; +} +- (id)sortedArrayUsingFunction:(int (*)(id, id, void *))comparator with:(int)value { + if(value == comparator(self, self, self)) + return self; + return nil; +} +@end + +@implementation MyTargetBuildContext : Object +- (id)initWithTarget:(MyTarget *)target +{ + self = [super init]; + return self; +} +- (MyTarget *)target +{ + return _target; +} + +static int _MyCompareObjectsByDecreasingSetCount (id object1, id object2, MyCountedSet * countedSet) +{ + global_value = 5; + return countedSet->cardinality; +} ++ (MySet *)_headerFileExtensions +{ + MySet * _headerFileExtensions = 0; + return _headerFileExtensions; +} +- (void)_recomputeHeadermap +{ + MyCountedSet *set = [MyCountedSet new]; + int (*functionPointer)(id, id, void *) = (int (*)(id, id, void *))_MyCompareObjectsByDecreasingSetCount; + id result = [set sortedArrayUsingFunction:functionPointer with:5]; +} +@end + +int main(void) { + MyTargetBuildContext *ctx = [MyTargetBuildContext new]; + [ctx _recomputeHeadermap]; + if (global_value != 5) + abort(); + + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/fix-and-continue-2.m b/gcc/testsuite/objc.dg/fix-and-continue-2.m new file mode 100644 index 000000000..fdfbcbd0c --- /dev/null +++ b/gcc/testsuite/objc.dg/fix-and-continue-2.m @@ -0,0 +1,24 @@ +/* Static variables, even if local, require indirect access through a stub + if -mfix-and-continue is enabled. */ + +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do assemble { target *-*-darwin* } } */ +/* { dg-options "-mfix-and-continue" } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@interface Foo: Object ++ (Object *)indexableFileTypes; +@end + +@implementation Foo ++ (Object *)indexableFileTypes +{ + static Object *fileTypes = 0; + if(!fileTypes) { + fileTypes = [Object new]; + } + return fileTypes; +} +@end diff --git a/gcc/testsuite/objc.dg/fobjc-exceptions-1.m b/gcc/testsuite/objc.dg/fobjc-exceptions-1.m new file mode 100644 index 000000000..8cee4d849 --- /dev/null +++ b/gcc/testsuite/objc.dg/fobjc-exceptions-1.m @@ -0,0 +1,28 @@ +/* Test that Objective-C exceptions cause an error with -fobjc-exceptions. */ +/* { dg-do compile } */ + +@class Object; + +int dummy (int number, Object *o) +{ + @try { /* { dg-error ".-fobjc-exceptions. is required to enable Objective-C exception syntax" } */ + number++; + @throw o; /* Nothing, error has already been produced. */ + } + @catch (id object) + { + number++; + @throw; /* Nothing, error has already been produced. */ + } + @finally + { + number++; + } + + @synchronized (o) /* Nothing, error has already been produced. */ + { + number++; + } + + return number; +} diff --git a/gcc/testsuite/objc.dg/fobjc-exceptions-2.m b/gcc/testsuite/objc.dg/fobjc-exceptions-2.m new file mode 100644 index 000000000..32b3506ec --- /dev/null +++ b/gcc/testsuite/objc.dg/fobjc-exceptions-2.m @@ -0,0 +1,29 @@ +/* Test that Objective-C exceptions cause an error with -fobjc-exceptions. */ +/* { dg-do compile } */ + +@class Object; + +int dummy (int number, Object *o) +{ + @synchronized (o) /* { dg-error ".-fobjc-exceptions. is required to enable Objective-C exception syntax" } */ + { + number++; + } + + @try { /* Nothing, error has already been produced. */ + number++; + @throw o; /* Nothing, error has already been produced. */ + } + @catch (id object) + { + number++; + @throw; /* Nothing, error has already been produced. */ + } + @finally + { + number++; + } + + + return number; +} diff --git a/gcc/testsuite/objc.dg/fobjc-exceptions-3.m b/gcc/testsuite/objc.dg/fobjc-exceptions-3.m new file mode 100644 index 000000000..d3d6453df --- /dev/null +++ b/gcc/testsuite/objc.dg/fobjc-exceptions-3.m @@ -0,0 +1,30 @@ +/* Test that Objective-C exceptions cause an error with -fobjc-exceptions. */ +/* { dg-do compile } */ + +@class Object; + +int dummy (int number, Object *o) +{ + @throw o; /* { dg-error ".-fobjc-exceptions. is required to enable Objective-C exception syntax" } */ + + @try { /* Nothing, error has already been produced. */ + number++; + @throw o; /* Nothing, error has already been produced. */ + } + @catch (id object) + { + number++; + @throw; /* Nothing, error has already been produced. */ + } + @finally + { + number++; + } + + @synchronized (o) /* Nothing, error has already been produced. */ + { + number++; + } + + return number; +} diff --git a/gcc/testsuite/objc.dg/fobjc-std-1.m b/gcc/testsuite/objc.dg/fobjc-std-1.m new file mode 100644 index 000000000..9a15b8af5 --- /dev/null +++ b/gcc/testsuite/objc.dg/fobjc-std-1.m @@ -0,0 +1,76 @@ +/* Test warnings when using -fobjc-std=objc1. */ +/* { dg-do compile } */ +/* { dg-options "-fobjc-std=objc1" } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +@package /* { dg-error "not available in Objective.C 1.0" } */ + int a; + int b; +} ++ (id) alloc __attribute__ ((deprecated)); /* { dg-error "not available in Objective.C 1.0" } */ ++ (id) name; +- (id) init; +- (id) testMe: (id) __attribute__((unused)) argument; /* { dg-error "not available in Objective.C 1.0" } */ +@property (nonatomic) int a; /* { dg-error "not available in Objective.C 1.0" } */ +@property (nonatomic) int b; /* { dg-error "not available in Objective.C 1.0" } */ +@end + +@implementation MyRootClass ++ (id) alloc { return self; } ++ (id) name { return self; } +- (id) init { return self; } +- (id) testMe: (id) __attribute__((unused)) argument { return self; } /* { dg-error "not available in Objective.C 1.0" } */ +@synthesize a; /* { dg-error "not available in Objective.C 1.0" } */ +@dynamic b; /* { dg-error "not available in Objective.C 1.0" } */ +@end + +__attribute__ ((deprecated)) +@interface MyRootClass2 +{ /* { dg-error "class attributes are not available in Objective.C 1.0" } */ + Class isa; +} +@end + +__attribute__ ((deprecated)) +@protocol MyProtocol +- (id) test; /* { dg-error "protocol attributes are not available in Objective.C 1.0" } */ +@required /* { dg-error "not available in Objective.C 1.0" } */ +- (id) variable __attribute__ ((deprecated)); /* { dg-error "not available in Objective.C 1.0" } */ +@optional /* { dg-error "not available in Objective.C 1.0" } */ +@end + +@interface MyRootClass (NSFastEnumeration) +- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state + objects:(id *)stackbuf + count:(unsigned int)len; +@end + +@class NSArray; + +int array_length (NSArray *array) +{ + int i = 0; + + for (id object in array) /* { dg-error "not available in Objective.C 1.0" } */ + i++; + + return i; +} + +id test (void) +{ + return MyRootClass.name; /* { dg-error "not available in Objective.C 1.0" } */ +} + +@interface MyRootClass3 +{ + Class isa; +} +@end + +@interface MyRootClass3 () +@end /* { dg-error "not available in Objective.C 1.0" } */ diff --git a/gcc/testsuite/objc.dg/foreach-1.m b/gcc/testsuite/objc.dg/foreach-1.m new file mode 100644 index 000000000..bc9a21a09 --- /dev/null +++ b/gcc/testsuite/objc.dg/foreach-1.m @@ -0,0 +1,83 @@ +/* Test basic Objective-C foreach syntax. This tests iterations that + do nothing. +*/ +/* { dg-do run } */ +/* { dg-skip-if "No NeXT fast enum. pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m" } */ +/* { dg-options "-Wall" } */ + +#import "../objc-obj-c++-shared/Object1.h" + +extern void abort (void); +/* +struct __objcFastEnumerationState +{ + unsigned long state; + id *itemsPtr; + unsigned long *mutationsPtr; + unsigned long extra[5]; +}; +*/ +@interface Object (NSFastEnumeration) +- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state + objects:(id *)stackbuf + count:(unsigned int)len; +@end + +int main (void) +{ + int test_variable = 0; + int counter = 0; + id array = nil; + id object = nil; + + /* Test that 'for (object in array)' is recognized and that nothing + happens if array is nil. */ + for (object in array) + test_variable = 8; + + if (test_variable == 8) + abort (); + + if (object != nil) + abort (); + + /* Test that if nothing is done, object is set to nil. */ + object = [Object new]; + + for (object in array) + ; + + if (object != nil) + abort (); + + /* Test that you can reference 'object' inside the body. */ + for (object in array) + object = nil; + + if (object != nil) + abort (); + + /* Test that 'for (id element in array) is recognized (and works). */ + for (id element in array) + test_variable = 8; + + if (test_variable == 8) + abort (); + + /* Test that you can reference 'object' inside the body. */ + for (id element in array) + element = nil; + + /* Test that C for loops still work. */ + test_variable = 0; + + for (counter = 0; counter < 4; counter++) + test_variable++; + + if (test_variable != 4) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/foreach-2.m b/gcc/testsuite/objc.dg/foreach-2.m new file mode 100644 index 000000000..a319a4bc7 --- /dev/null +++ b/gcc/testsuite/objc.dg/foreach-2.m @@ -0,0 +1,288 @@ +/* Test basic Objective-C foreach syntax. This tests iterations, with + the basic syntax 'for (object in array) statements' +*/ +/* { dg-do run } */ +/* { dg-skip-if "No NeXT fast enum. pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-options "-mno-constant-cfstrings" { target *-*-darwin* } } */ +/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m ../objc-obj-c++-shared/nsconstantstring-class-impl.m" } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include "../objc-obj-c++-shared/next-mapping.h" +#ifndef __NEXT_RUNTIME__ +#include <objc/NXConstStr.h> +#else +#include "../objc-obj-c++-shared/nsconstantstring-class.h" +#endif + +extern int printf (const char *, ...); +#include <stdlib.h> + +/* +struct __objcFastEnumerationState +{ + unsigned long state; + id *itemsPtr; + unsigned long *mutationsPtr; + unsigned long extra[5]; +}; +*/ + + /* A mini-array implementation that can be used to test fast + enumeration. You create the array with some objects; you can + mutate the array, and you can fast-enumerate it. + */ +@interface MyArray : Object +{ + unsigned int length; + id *objects; + unsigned long mutated; +} +- (id) initWithLength: (unsigned int)l objects: (id *)o; +- (void) mutate; +- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state + objects:(id *)stackbuf + count:(unsigned long)len; +@end + +@implementation MyArray : Object +- (id) initWithLength: (unsigned int)l + objects: (id *)o +{ + length = l; + objects = o; + mutated = 0; + return self; +} +- (void) mutate +{ + mutated = 1; +} +- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState*)state + objects: (id*)stackbuf + count: (unsigned long)len +{ + unsigned long i, batch_size; + + /* We keep how many objects we served in the state->state counter. So the next batch + will contain up to length - state->state objects. */ + batch_size = length - state->state; + + /* Make obvious adjustments. */ + if (batch_size < 0) + batch_size = 0; + + if (batch_size > len) + batch_size = len; + + /* Copy the objects. */ + for (i = 0; i < batch_size; i++) + stackbuf[i] = objects[i]; + + state->state += batch_size; + state->itemsPtr = stackbuf; + state->mutationsPtr = &mutated; + + return batch_size; +} +@end + +int main (void) +{ + MyArray *array; + Object *object; + int test_variable, counter, i; + id *objects; + + array = [[MyArray alloc] initWithLength: 0 + objects: NULL]; + + /* Test that an empty array does nothing. */ + for (object in array) + abort (); + + if (object != nil) + abort (); + + /* Test iterating over 1 object. */ + objects = malloc (sizeof (id) * 1); + objects[0] = @"One Object"; + + array = [[MyArray alloc] initWithLength: 1 + objects: objects]; + + for (object in array) + printf ("%p\n", object); + + /* Test iterating over 20 objects. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + + for (object in array) + printf ("%p\n", object); + + /* Test iterating over 200 objects. */ + objects = malloc (sizeof (id) * 200); + for (i = 0; i < 200; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 200 + objects: objects]; + + counter = 0; + for (object in array) + { + if (object != nil) + counter++; + } + + if (counter != 200) + abort (); + + printf ("Counter was %d (should be 200)\n", counter); + + /* Test iterating again over the same array. */ + counter = 0; + for (object in array) + { + if (object != nil) + counter++; + } + + if (counter != 200) + abort (); + + printf ("Counter was %d (should be 200)\n", counter); + + /* Test nested iterations. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + counter = 0; + for (object in array) + { + id another_object; + for (another_object in array) + if (another_object != nil) + counter++; + } + + printf ("Counter was %d (should be 400)\n", counter); + + if (counter != 400) + abort (); + + /* Test 'continue'. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + counter = 0; + for (object in array) + { + if (counter == 15) + continue; + + counter++; + } + + printf ("Counter was %d (should be 15)\n", counter); + + if (counter != 15) + abort (); + + /* Test 'break'. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + counter = 0; + for (object in array) + { + counter++; + + if (counter == 15) + break; + } + + printf ("Counter was %d (should be 15)\n", counter); + + if (counter != 15) + abort (); + + /* Test 'break' and 'continue' in nested iterations. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + counter = 0; + for (object in array) + { + int local_counter = 0; + id another_object; + + /* Each internal loop should increase counter by 24. */ + for (another_object in array) + { + local_counter++; + + if (local_counter == 10) + { + counter = counter + 20; + break; + } + + if (local_counter >= 5) + continue; + + counter++; + } + + /* Exit after 4 iterations. */ + if (counter == 96) + break; + } + + printf ("Counter was %d (should be 96)\n", counter); + + if (counter != 96) + abort (); + + /* Test that if we 'break', the object is set to the last one, while + if we run out of objects, it is set to 'nil'. */ + for (object in array) + ; + + if (object != nil) + abort (); + + for (object in array) + break; + + if (object == nil) + abort (); + + /* Test that C for loops still work. */ + test_variable = 0; + + for (counter = 0; counter < 4; counter++) + test_variable++; + + if (test_variable != 4) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/foreach-3.m b/gcc/testsuite/objc.dg/foreach-3.m new file mode 100644 index 000000000..ac08a4095 --- /dev/null +++ b/gcc/testsuite/objc.dg/foreach-3.m @@ -0,0 +1,118 @@ +/* Test basic Objective-C foreach syntax. This tests the mutation. +*/ +/* { dg-do compile } */ + +/* FIXME: This test should be run, and it succeeds if the program + aborts at the right time (when the mutation happens). It currently + works, but how do we tell the testsuite to test for it ? +*/ + +#import "../objc-obj-c++-shared/Object1.h" +#import "../objc-obj-c++-shared/next-mapping.h" +#ifndef __NEXT_RUNTIME__ +#include <objc/NXConstStr.h> +#endif + +extern int printf (const char *, ...); +#include <stdlib.h> + +/* +struct __objcFastEnumerationState +{ + unsigned long state; + id *itemsPtr; + unsigned long *mutationsPtr; + unsigned long extra[5]; +}; +*/ + + /* A mini-array implementation that can be used to test fast + enumeration. You create the array with some objects; you can + mutate the array, and you can fast-enumerate it. + */ +@interface MyArray : Object +{ + unsigned int length; + id *objects; + unsigned long mutated; +} +- (id) initWithLength: (unsigned int)l objects: (id *)o; +- (void) mutate; +- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state + objects:(id *)stackbuf + count:(unsigned long)len; +@end + +@implementation MyArray : Object +- (id) initWithLength: (unsigned int)l + objects: (id *)o +{ + length = l; + objects = o; + mutated = 0; + return self; +} +- (void) mutate +{ + mutated = 1; +} +- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState*)state + objects: (id*)stackbuf + count: (unsigned long)len +{ + unsigned long i, batch_size; + + /* Change the mutationsPtr if 'mutate' is called. */ + state->mutationsPtr = &mutated; + + /* We keep how many objects we served in the state->state counter. So the next batch + will contain up to length - state->state objects. */ + batch_size = length - state->state; + + /* Make obvious adjustments. */ + if (batch_size < 0) + batch_size = 0; + + if (batch_size > len) + batch_size = len; + + /* Copy the objects. */ + for (i = 0; i < batch_size; i++) + stackbuf[i] = objects[i]; + + state->state += batch_size; + state->itemsPtr = stackbuf; + + return batch_size; +} +@end + +int main (void) +{ + MyArray *array; + Object *object; + int counter, i; + id *objects; + + /* Test iterating over 20 objects, mutating after 15. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + + counter = 0; + for (object in array) + { + counter++; + printf ("%d\n", counter); + if (counter == 14) + { + printf ("Mutating (should abort at next iteration)\n"); + [array mutate]; + } + } + + return 0; +} diff --git a/gcc/testsuite/objc.dg/foreach-4.m b/gcc/testsuite/objc.dg/foreach-4.m new file mode 100644 index 000000000..13b9b0bb9 --- /dev/null +++ b/gcc/testsuite/objc.dg/foreach-4.m @@ -0,0 +1,268 @@ +/* Test basic Objective-C foreach syntax. This tests iterations, with + the declaration syntax 'for (id object in array) statements' +*/ +/* { dg-do run } */ +/* { dg-skip-if "No NeXT fast enum. pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-options "-mno-constant-cfstrings" { target *-*-darwin* } } */ +/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m ../objc-obj-c++-shared/nsconstantstring-class-impl.m" } */ + +#import "../objc-obj-c++-shared/Object1.h" +#import "../objc-obj-c++-shared/next-mapping.h" +#ifndef __NEXT_RUNTIME__ +#include <objc/NXConstStr.h> +#else +#include "../objc-obj-c++-shared/nsconstantstring-class.h" +#endif + +extern int printf (const char *, ...); +#include <stdlib.h> + +/* +struct __objcFastEnumerationState +{ + unsigned long state; + id *itemsPtr; + unsigned long *mutationsPtr; + unsigned long extra[5]; +}; +*/ + + /* A mini-array implementation that can be used to test fast + enumeration. You create the array with some objects; you can + mutate the array, and you can fast-enumerate it. + */ +@interface MyArray : Object +{ + unsigned int length; + id *objects; + unsigned long mutated; +} +- (id) initWithLength: (unsigned int)l objects: (id *)o; +- (void) mutate; +- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state + objects:(id *)stackbuf + count:(unsigned long)len; +@end + +@implementation MyArray : Object +- (id) initWithLength: (unsigned int)l + objects: (id *)o +{ + length = l; + objects = o; + mutated = 0; + return self; +} +- (void) mutate +{ + mutated = 1; +} +- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState*)state + objects: (id*)stackbuf + count: (unsigned long)len +{ + unsigned long i, batch_size; + + /* We keep how many objects we served in the state->state counter. So the next batch + will contain up to length - state->state objects. */ + batch_size = length - state->state; + + /* Make obvious adjustments. */ + if (batch_size < 0) + batch_size = 0; + + if (batch_size > len) + batch_size = len; + + /* Copy the objects. */ + for (i = 0; i < batch_size; i++) + stackbuf[i] = objects[i]; + + state->state += batch_size; + state->itemsPtr = stackbuf; + state->mutationsPtr = &mutated; + + return batch_size; +} +@end + +int main (void) +{ + MyArray *array; + int test_variable, counter, i; + id *objects; + + array = [[MyArray alloc] initWithLength: 0 + objects: NULL]; + + /* Test that an empty array does nothing. */ + for (id object in array) + abort (); + + /* Test iterating over 1 object. */ + objects = malloc (sizeof (id) * 1); + objects[0] = @"One Object"; + + array = [[MyArray alloc] initWithLength: 1 + objects: objects]; + + for (id object in array) + printf ("%p\n", object); + + /* Test iterating over 20 objects. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + + for (id object in array) + printf ("%p\n", object); + + /* Test iterating over 200 objects. */ + objects = malloc (sizeof (id) * 200); + for (i = 0; i < 200; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 200 + objects: objects]; + + counter = 0; + for (id object in array) + { + if (object != nil) + counter++; + } + + if (counter != 200) + abort (); + + printf ("Counter was %d (should be 200)\n", counter); + + /* Test iterating again over the same array. */ + counter = 0; + for (id object in array) + { + if (object != nil) + counter++; + } + + if (counter != 200) + abort (); + + printf ("Counter was %d (should be 200)\n", counter); + + /* Test nested iterations. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + counter = 0; + for (id object in array) + { + for (id another_object in array) + if (another_object != nil) + counter++; + } + + printf ("Counter was %d (should be 400)\n", counter); + + if (counter != 400) + abort (); + + /* Test 'continue'. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + counter = 0; + for (id object in array) + { + if (counter == 15) + continue; + + counter++; + } + + printf ("Counter was %d (should be 15)\n", counter); + + if (counter != 15) + abort (); + + /* Test 'break'. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + counter = 0; + for (id object in array) + { + counter++; + + if (counter == 15) + break; + } + + printf ("Counter was %d (should be 15)\n", counter); + + if (counter != 15) + abort (); + + /* Test 'break' and 'continue' in nested iterations. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + counter = 0; + for (id object in array) + { + int local_counter = 0; + + /* Each internal loop should increase counter by 24. */ + for (id another_object in array) + { + local_counter++; + + if (local_counter == 10) + { + counter = counter + 20; + break; + } + + if (local_counter >= 5) + continue; + + counter++; + } + + /* Exit after 4 iterations. */ + if (counter == 96) + break; + } + + printf ("Counter was %d (should be 96)\n", counter); + + if (counter != 96) + abort (); + + /* Test that C for loops still work. */ + test_variable = 0; + + for (counter = 0; counter < 4; counter++) + test_variable++; + + if (test_variable != 4) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/foreach-5.m b/gcc/testsuite/objc.dg/foreach-5.m new file mode 100644 index 000000000..c715b2d82 --- /dev/null +++ b/gcc/testsuite/objc.dg/foreach-5.m @@ -0,0 +1,266 @@ +/* Test basic Objective-C foreach syntax. This tests that if you + define your own NSFastEnumeration struct, the compiler picks it up. +*/ +/* { dg-do run } */ +/* { dg-skip-if "No NeXT fast enum. pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-options "-mno-constant-cfstrings" { target *-*-darwin* } } */ +/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m ../objc-obj-c++-shared/nsconstantstring-class-impl.m" } */ + +#import "../objc-obj-c++-shared/Object1.h" +#import "../objc-obj-c++-shared/next-mapping.h" +#ifndef __NEXT_RUNTIME__ +#include <objc/NXConstStr.h> +#else +#include "../objc-obj-c++-shared/nsconstantstring-class.h" +#endif + +extern int printf (const char *, ...); +#include <stdlib.h> + +typedef struct +{ + unsigned long state; + id *itemsPtr; + unsigned long *mutationsPtr; + unsigned long extra[5]; +} NSFastEnumerationState; + +/* A mini-array implementation that can be used to test fast + enumeration. You create the array with some objects; you can + mutate the array, and you can fast-enumerate it. +*/ +@interface MyArray : Object +{ + unsigned int length; + id *objects; + unsigned long mutated; +} +- (id) initWithLength: (unsigned int)l objects: (id *)o; +- (void) mutate; +- (unsigned long)countByEnumeratingWithState: (NSFastEnumerationState *)state + objects:(id *)stackbuf + count:(unsigned long)len; +@end + +@implementation MyArray : Object +- (id) initWithLength: (unsigned int)l + objects: (id *)o +{ + length = l; + objects = o; + mutated = 0; + return self; +} +- (void) mutate +{ + mutated = 1; +} +- (unsigned long)countByEnumeratingWithState: (NSFastEnumerationState*)state + objects: (id*)stackbuf + count: (unsigned long)len +{ + unsigned long i, batch_size; + + /* We keep how many objects we served in the state->state counter. So the next batch + will contain up to length - state->state objects. */ + batch_size = length - state->state; + + /* Make obvious adjustments. */ + if (batch_size < 0) + batch_size = 0; + + if (batch_size > len) + batch_size = len; + + /* Copy the objects. */ + for (i = 0; i < batch_size; i++) + stackbuf[i] = objects[i]; + + state->state += batch_size; + state->itemsPtr = stackbuf; + state->mutationsPtr = &mutated; + + return batch_size; +} +@end + +int main (void) +{ + MyArray *array; + int test_variable, counter, i; + id *objects; + + array = [[MyArray alloc] initWithLength: 0 + objects: NULL]; + + /* Test that an empty array does nothing. */ + for (id object in array) + abort (); + + /* Test iterating over 1 object. */ + objects = malloc (sizeof (id) * 1); + objects[0] = @"One Object"; + + array = [[MyArray alloc] initWithLength: 1 + objects: objects]; + + for (id object in array) + printf ("%p\n", object); + + /* Test iterating over 20 objects. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + + for (id object in array) + printf ("%p\n", object); + + /* Test iterating over 200 objects. */ + objects = malloc (sizeof (id) * 200); + for (i = 0; i < 200; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 200 + objects: objects]; + + counter = 0; + for (id object in array) + { + if (object != nil) + counter++; + } + + if (counter != 200) + abort (); + + printf ("Counter was %d (should be 200)\n", counter); + + /* Test iterating again over the same array. */ + counter = 0; + for (id object in array) + { + if (object != nil) + counter++; + } + + if (counter != 200) + abort (); + + printf ("Counter was %d (should be 200)\n", counter); + + /* Test nested iterations. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + counter = 0; + for (id object in array) + { + for (id another_object in array) + if (another_object != nil) + counter++; + } + + printf ("Counter was %d (should be 400)\n", counter); + + if (counter != 400) + abort (); + + /* Test 'continue'. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + counter = 0; + for (id object in array) + { + if (counter == 15) + continue; + + counter++; + } + + printf ("Counter was %d (should be 15)\n", counter); + + if (counter != 15) + abort (); + + /* Test 'break'. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + counter = 0; + for (id object in array) + { + counter++; + + if (counter == 15) + break; + } + + printf ("Counter was %d (should be 15)\n", counter); + + if (counter != 15) + abort (); + + /* Test 'break' and 'continue' in nested iterations. */ + objects = malloc (sizeof (id) * 20); + for (i = 0; i < 20; i++) + objects[i] = @"object"; + + array = [[MyArray alloc] initWithLength: 20 + objects: objects]; + counter = 0; + for (id object in array) + { + int local_counter = 0; + + /* Each internal loop should increase counter by 24. */ + for (id another_object in array) + { + local_counter++; + + if (local_counter == 10) + { + counter = counter + 20; + break; + } + + if (local_counter >= 5) + continue; + + counter++; + } + + /* Exit after 4 iterations. */ + if (counter == 96) + break; + } + + printf ("Counter was %d (should be 96)\n", counter); + + if (counter != 96) + abort (); + + /* Test that C for loops still work. */ + test_variable = 0; + + for (counter = 0; counter < 4; counter++) + test_variable++; + + if (test_variable != 4) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/foreach-6.m b/gcc/testsuite/objc.dg/foreach-6.m new file mode 100644 index 000000000..96b145365 --- /dev/null +++ b/gcc/testsuite/objc.dg/foreach-6.m @@ -0,0 +1,61 @@ +/* Test basic Objective-C foreach syntax. This tests warnings and errors. */ +/* { dg-do compile } */ + +#import "../objc-obj-c++-shared/Object1.h" +#import "../objc-obj-c++-shared/next-mapping.h" + +/* +struct __objcFastEnumerationState +{ + unsigned long state; + id *itemsPtr; + unsigned long *mutationsPtr; + unsigned long extra[5]; +}; +*/ +@interface Object (NSFastEnumeration) +- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state + objects:(id *)stackbuf + count:(unsigned int)len; +- (id) enumerator; +- (Class) classEnumerator; +@end + +int main (void) +{ + id array = nil; + id object = nil; + id *invalid = 0; + + for (object in array) /* Ok */ + ; + + for (object in nil) /* Ok */ + ; + + for (object in) /* { dg-error "missing collection in fast enumeration" } */ + ; + + for (object = nil in array) /* { dg-error "invalid iterating variable in fast enumeration" } */ + ; + + for (object in [object enumerator]) /* Ok */ + ; + + for (object in [object classEnumerator]) /* Ok */ + ; + + for (12 in array) /* { dg-error "invalid iterating variable in fast enumeration" } */ + ; /* { dg-error "iterating variable in fast enumeration is not an object" "" { target *-*-* } 48 } */ + + for (object in 12) /* { dg-error "collection in fast enumeration is not an object" } */ + ; + + for (object in invalid) /* { dg-error "collection in fast enumeration is not an object" } */ + ; + + for (invalid in [object enumerator]) /* { dg-error "iterating variable in fast enumeration is not an object" } */ + ; + + return 0; +} diff --git a/gcc/testsuite/objc.dg/foreach-7.m b/gcc/testsuite/objc.dg/foreach-7.m new file mode 100644 index 000000000..4629d61e1 --- /dev/null +++ b/gcc/testsuite/objc.dg/foreach-7.m @@ -0,0 +1,58 @@ +/* Test basic Objective-C foreach syntax. This tests warnings and errors. */ +/* { dg-do compile } */ + +#import "../objc-obj-c++-shared/Object1.h" +#import "../objc-obj-c++-shared/next-mapping.h" + +/* +struct __objcFastEnumerationState +{ + unsigned long state; + id *itemsPtr; + unsigned long *mutationsPtr; + unsigned long extra[5]; +}; +*/ +@interface Object (NSFastEnumeration) +- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state + objects:(id *)stackbuf + count:(unsigned int)len; +- (id) enumerator; +@end + +void function (void) +{ + return; +} + +id object_function (void) +{ + return nil; +} + +int main (void) +{ + id array = nil; + id object = nil; + + for (typedef int my_typedef in array) /* { dg-error "declaration of non-variable" } */ + ; /* { dg-error "iterating variable in fast enumeration is not an object" "" { target *-*-* } 38 } */ + + for (function () in nil) /* { dg-error "invalid iterating variable in fast enumeration" } */ + ; /* { dg-error "iterating variable in fast enumeration is not an object" "" { target *-*-* } 41 } */ + + for (object_function () in nil) /* { dg-error "invalid iterating variable in fast enumeration" } */ + ; + + for ([object enumerator] in array) /* { dg-error "invalid iterating variable in fast enumeration" } */ + ; + + for (object = nil in array) /* { dg-error "invalid iterating variable in fast enumeration" } */ + ; + + for (id key, value in array) /* { dg-error "multiple iterating variables in fast enumeration" } */ + ; + + return 0; +} + diff --git a/gcc/testsuite/objc.dg/foreach-8.m b/gcc/testsuite/objc.dg/foreach-8.m new file mode 100644 index 000000000..9a68e9ffb --- /dev/null +++ b/gcc/testsuite/objc.dg/foreach-8.m @@ -0,0 +1,51 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-options "-Wall" } */ +/* { dg-do compile } */ + +/* Test that fast enumeration loops where the iterating variable is declared + but not used do not generate warnings. */ + +/* +struct __objcFastEnumerationState +{ + unsigned long state; + id *itemsPtr; + unsigned long *mutationsPtr; + unsigned long extra[5]; +}; +*/ +@interface Object +{ + Class isa; +} +- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state + objects:(id *)stackbuf + count:(unsigned int)len; +- (id) enumerator; +- (Class) classEnumerator; +@end + +unsigned int count_objects_in_collection (id collection) +{ + unsigned int count = 0; + + /* The following line should generate no warnings even with + -Wall. */ + for (id object in collection) + count++; + + return count; +} + +unsigned int count_objects_in_collection_2 (id collection) +{ + unsigned int count = 0; + id object; + + /* The following line should generate no warnings even with + -Wall. */ + for (object in collection) + count++; + + return count; +} diff --git a/gcc/testsuite/objc.dg/fsf-nsstring-format-1.m b/gcc/testsuite/objc.dg/fsf-nsstring-format-1.m new file mode 100644 index 000000000..0921bb33b --- /dev/null +++ b/gcc/testsuite/objc.dg/fsf-nsstring-format-1.m @@ -0,0 +1,44 @@ +/* Check NSString format extensions. */ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-Wall" } */ + +extern int printf (const char *fmt, ...); + +#ifndef __CONSTANT_CFSTRINGS__ +#error requires CFString +#endif + +typedef const struct __CFString * CFStringRef; +@class NSString; + +int s1 (NSString *fmt, ...) __attribute__((format(NSString, 1, 2))) ; /* OK */ +/* A CFString can represent an NSString. */ +int s1a (CFStringRef fmt, ...) __attribute__((format(NSString, 1, 2))) ; /* OK */ +/* But... it is possible that a CFString format might imply functionality that + is not present in objective-c. */ +int s1b (NSString *fmt, ...) __attribute__((format(CFString, 1, 2))) ; /* { dg-error "format argument should be a .CFString. reference" } */ + +int s2 (int a, NSString *fmt, ... ) __attribute__((format(__NSString__, 2, 3))) ; /* OK */ + +int s2a (int a, NSString *fmt, ... ) __attribute__((format(NSString, 2, 2))) ; /* { dg-error "format string argument follows the args to be formatted" } */ + +int s3 (const char *fmt, ... ) __attribute__((format(__NSString__, 1, 2))) ; /* { dg-error "format argument should be a .NSString. reference but a string was found" } */ +int s4 (NSString *fmt, ... ) __attribute__((format(printf, 1, 2))) ; /* { dg-error "found a .NSString. reference but the format argument should be a string" } */ + +char *s5 (char dum, char *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */ +NSString *s6 (NSString *dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */ + +char *s7 (int dum, void *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "format string argument is not a string type" } */ +int s8 (NSString *dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "function does not return string type" } */ + +char *s9 (int dum, char *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */ +NSString *s10 (int dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */ + +void foo (void) +{ + s1 (@"format not checked %d %s", 3, 4); + printf("this one is checked %d %s", 3, 4, 5); /* { dg-warning "format '%s' expects argument of type 'char .', but argument 3 has type 'int'" } */ + /* { dg-warning "too many arguments for format" "" { target *-*-* } 41 } */ + printf(s9 (1, "and so is this %d %d %s", 3, 4), 5, 6, 12); /* { dg-warning "format '%s' expects argument of type 'char .', but argument 4 has type 'int'" } */ +} diff --git a/gcc/testsuite/objc.dg/fsf-package-0.m b/gcc/testsuite/objc.dg/fsf-package-0.m new file mode 100644 index 000000000..d6b4db217 --- /dev/null +++ b/gcc/testsuite/objc.dg/fsf-package-0.m @@ -0,0 +1,37 @@ +/* { dg-do compile } */ + +#import "../objc-obj-c++-shared/Object1.h" +#include <objc/objc-api.h> + +@interface obj : Object +{ +@public + int v1; +@package /* { dg-warning ".@package. presently has the same effect as .@public." } */ + int v2; +@protected + int v3; +@private + int v4; +} +- (int) value; +- (void) setValue: (int)number; +@end + +@implementation obj : Object + +- (int) value { return v1; } +- (void) setValue: (int)number { v1 = number; } + +@end + +void foo (void) +{ + obj *a; + + [a setValue:2]; + a->v2 = 1; + a->v3 = [a value] - a->v2; /* { dg-warning ".v3. is @protected" } */ + a->v4 = a->v3 - 1; /* { dg-warning ".v4. is @private" } */ + /* { dg-warning ".v3. is @protected" "" { target *-*-* } 35 } */ +} diff --git a/gcc/testsuite/objc.dg/fsyntax-only.m b/gcc/testsuite/objc.dg/fsyntax-only.m new file mode 100644 index 000000000..54a879e22 --- /dev/null +++ b/gcc/testsuite/objc.dg/fsyntax-only.m @@ -0,0 +1,11 @@ +/* Test -fsyntax-only compiler option */ +/* { dg-do compile } */ +/* { dg-options "-fsyntax-only" } */ + +@interface foo +-(void) my_method:(int) i with:(int) j; +@end + +@implementation foo +-(void) my_method:(int) i with:(int) j { } +@end diff --git a/gcc/testsuite/objc.dg/func-ptr-1.m b/gcc/testsuite/objc.dg/func-ptr-1.m new file mode 100644 index 000000000..4bdb344a3 --- /dev/null +++ b/gcc/testsuite/objc.dg/func-ptr-1.m @@ -0,0 +1,51 @@ +/* Test for handling of function pointer ivars */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" + +extern int strcmp(const char *, const char *); +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +typedef float (*floatfunc)(float, float); + +@interface MyObject : Object +{ +@public + int (*ivar)(int, int, int); + floatfunc ffunc; +} +- init; +@end + +int foo(int a, int b, int c) { + return a + b + c; +} + +float bar(float a, float b) { + return a * b; +} + +@implementation MyObject +- init { + [super init]; + ivar = foo; + ffunc = bar; + return self; +} +@end + +int main () +{ + MyObject *obj = [[MyObject alloc] init]; + const char *enc = @encode(MyObject); + + CHECK_IF(obj->ivar(4, 5, 6) == 15); + CHECK_IF(obj->ffunc(34.0, 45.0) == 34.0 * 45.0); + CHECK_IF(!strcmp(enc, "{MyObject=#^?^?}")); + return(0); +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" + diff --git a/gcc/testsuite/objc.dg/func-ptr-2.m b/gcc/testsuite/objc.dg/func-ptr-2.m new file mode 100644 index 000000000..e68c71b70 --- /dev/null +++ b/gcc/testsuite/objc.dg/func-ptr-2.m @@ -0,0 +1,41 @@ +/* Check if method parameters that are functions are gracefully decayed + into pointers. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <stdlib.h> +/* provide an Object class for NeXT runtimes 10.5 and above */ +#include "../objc-obj-c++-shared/Object1.h" + +@interface Func: Object ++ (int) processNumber:(int)a and:(int)b usingFunction:(int(int,int))func; +@end + +@implementation Func ++ (int) processNumber:(int)a and:(int)b usingFunction:(int(int,int))func { + return func (a, b); +} +@end + +static int my_computation(int a, int b) { + return a * 2 + b * 3; +} + +static int processNumber(int a, int b, int func(int, int)) { + return func(a, b); +} + +int main(void) { + int result = processNumber (6, 8, my_computation); + if (result != 36) + abort (); + + result = [Func processNumber:8 and:6 usingFunction:my_computation]; + if (result != 34) + abort (); + + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/fwd-proto-1.m b/gcc/testsuite/objc.dg/fwd-proto-1.m new file mode 100644 index 000000000..3b21c513c --- /dev/null +++ b/gcc/testsuite/objc.dg/fwd-proto-1.m @@ -0,0 +1,29 @@ +/* Test forward-decls for @protocols. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +/* One-line substitute for objc/objc.h */ +typedef struct objc_object { struct objc_class *class_pointer; } *id; + +@protocol Bar; +@protocol Boo; + +@protocol Foo +- (id <Bar>)someMethod; +- (id <Baz>)anotherMethod; /* { dg-error "annot find protocol declaration" } */ +@end + +@protocol Bar <Boo> +- (id <Foo>)someOtherMethod; +- (id <Baz>)anotherMethod; /* { dg-error "annot find protocol declaration" } */ +- (id <Boo>)yetAnotherMethod; +@end + +/* The following worthy test is stubbed out until we can get the + harness to match correctly on the "compilation terminated" message + when running on GNU/Linux. sts 2001-08-01 */ +#if 0 +@protocol Boo <Bar> /* { /*dg*/-error "has circular dependency" } */ +@end +#endif + diff --git a/gcc/testsuite/objc.dg/gnu-api-2-class.m b/gcc/testsuite/objc.dg/gnu-api-2-class.m new file mode 100644 index 000000000..f3469f6ed --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-api-2-class.m @@ -0,0 +1,488 @@ +/* Test the Modern GNU Objective-C Runtime API. + + This is test 'class', covering all functions starting with 'class'. */ + +/* { dg-do run } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* To get the modern GNU Objective-C Runtime API, you include + objc/runtime.h. */ +#include <objc/runtime.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +@interface MyRootClass +{ Class isa; } ++ alloc; +- init; ++ initialize; +@end + +@implementation MyRootClass ++ alloc { return class_createInstance (self, 0); } +- init { return self; } ++ initialize { return self; } +@end + +@protocol MyProtocol +- (id) variable; +@end + +@protocol MySecondProtocol +- (id) setVariable: (id)value; +@end + +@interface MySubClass : MyRootClass <MyProtocol> +{ id variable_ivar; } +- (void) setVariable: (id)value; +- (id) variable; +@end + +@implementation MySubClass +- (void) setVariable: (id)value { variable_ivar = value; } +- (id) variable { return variable_ivar; } +@end + +@interface MyOtherSubClass : MySubClass +@end + +@implementation MyOtherSubClass +@end + +@interface DifferentClass : MyRootClass +- (id) myClass; +- (id) self; +@end + +@implementation DifferentClass +- (id) myClass { return object_getClass (self); } +- (id) self { return self; } +@end + +@interface MySubClass (MySelf) +- (id) mySelf; +@end + +/* Hack to calculate the log2 of a byte alignment. */ +unsigned char +log_2_of (unsigned int x) +{ + unsigned char result = 0; + + /* We count how many times we need to divide by 2 before we reach 1. + This algorithm is good enough for the small numbers (such as 8, + 16 or 64) that we have to deal with. */ + while (x > 1) + { + x = x / 2; + result++; + } + + return result; +} + +int main(int argc, void **args) +{ + /* Functions are tested in alphabetical order. */ + + printf ("Testing class_addIvar ()...\n"); + { + Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0); + + if (new_class == Nil) + abort (); + + if (! class_addIvar (new_class, "variable2_ivar", sizeof (id), + log_2_of (__alignof__ (id)), @encode (id))) + abort (); + + if (! class_addIvar (new_class, "variable3_ivar", sizeof (unsigned char), + log_2_of (__alignof__ (unsigned char)), @encode (unsigned char))) + abort (); + + if (! class_addIvar (new_class, "variable4_ivar", sizeof (unsigned long), + log_2_of (__alignof__ (unsigned long)), @encode (unsigned long))) + abort (); + + objc_registerClassPair (new_class); + + { + MySubClass *o = [[objc_getClass ("MySubSubClass") alloc] init]; + Ivar variable2 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable2_ivar"); + Ivar variable3 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable3_ivar"); + Ivar variable4 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable4_ivar"); + + if (variable2 == NULL || variable3 == NULL || variable4 == NULL) + abort (); + + if (strcmp (ivar_getName (variable2), "variable2_ivar") != 0) + abort (); + + if (strcmp (ivar_getName (variable3), "variable3_ivar") != 0) + abort (); + + if (strcmp (ivar_getName (variable4), "variable4_ivar") != 0) + abort (); + + { + unsigned char *var3 = (unsigned char *)((char *)o + ivar_getOffset (variable3)); + unsigned long *var4 = (unsigned long *)((char *)o + ivar_getOffset (variable4)); + + object_setIvar (o, variable2, new_class); + *var3 = 230; + *var4 = 89000L; + + if (object_getIvar (o, variable2) != new_class) + abort (); + + if (*var3 != 230) + abort (); + + if (*var4 != 89000L) + abort (); + } + } + } + + printf ("Testing class_addMethod ()...\n"); + { + Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass2", 0); + Method method1 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:)); + Method method2 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (variable)); + + if (new_class == Nil) + abort (); + + if (! class_addIvar (new_class, "variable_ivar", sizeof (id), + log_2_of (__alignof__ (id)), @encode (id))) + abort (); + + if (! class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method1), + method_getTypeEncoding (method1))) + abort (); + + if (! class_addMethod (new_class, @selector (variable), method_getImplementation (method2), + method_getTypeEncoding (method2))) + abort (); + + /* Test that if the method already exists in the class, + class_addMethod() returns NO. */ + if (class_addMethod (new_class, @selector (variable), method_getImplementation (method2), + method_getTypeEncoding (method2))) + abort (); + + objc_registerClassPair (new_class); + + /* Now, MySubClass2 is basically the same as MySubClass! We'll + use the variable and setVariable: methods on it. */ + { + MySubClass *o = (MySubClass *)[[objc_getClass ("MySubClass2") alloc] init]; + + [o setVariable: o]; + + if ([o variable] != o) + abort (); + } + + /* Now, try that if you take an existing class and try to add an + already existing method, class_addMethod returns NO. This is + subtly different from before, when 'new_class' was still in + construction. Now it's a real class and the libobjc internals + differ between the two cases. */ + if (class_addMethod (new_class, @selector (variable), method_getImplementation (method2), + method_getTypeEncoding (method2))) + abort (); + } + + printf ("Testing class_addProtocol ()...\n"); + { + if (!class_addProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol))) + abort (); + + if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol))) + abort (); + + if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol))) + abort (); + } + + printf ("Testing class_conformsToProtocol ()...\n"); + { + if (class_conformsToProtocol (objc_getClass ("MyRootClass"), @protocol (MyProtocol))) + abort (); + + if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol))) + abort (); + + /* Test that class_conformsToProtocol checks the class, but not + superclasses. */ + if (class_conformsToProtocol (objc_getClass ("MyOtherSubClass"), @protocol (MyProtocol))) + abort (); + } + + printf ("Testing class_copyIvarList ()...\n"); + { + unsigned int count; + Ivar * list = class_copyIvarList (objc_getClass ("MySubClass"), &count); + + if (count != 1) + abort (); + + if (strcmp (ivar_getName (list[0]), "variable_ivar") != 0) + abort (); + + if (list[1] != NULL) + abort (); + } + + printf ("Testing class_copyMethodList ()...\n"); + { + unsigned int count; + Method * list = class_copyMethodList (objc_getClass ("MySubClass"), &count); + + if (count != 2) + abort (); + + if (! ((strcmp (sel_getName (method_getName (list[0])), "variable") == 0 + && strcmp (sel_getName (method_getName (list[1])), "setVariable:") == 0) + || (strcmp (sel_getName (method_getName (list[0])), "setVariable:") == 0 + && strcmp (sel_getName (method_getName (list[1])), "variable") == 0))) + abort (); + + if (list[2] != NULL) + abort (); + } + + /* TODO: Test new ABI (when available). */ + printf ("Testing class_copyPropertyList ()...\n"); + { + unsigned int count; + objc_property_t * list = class_copyPropertyList (objc_getClass ("MySubClass"), &count); + + if (count != 0 || list != NULL) + abort (); + } + + printf ("Testing class_copyProtocolList ()...\n"); + { + unsigned int count; + Protocol ** list = class_copyProtocolList (objc_getClass ("MySubClass"), &count); + + /* Remember that we added MySecondProtocol in the test above. */ + if (count != 2) + abort (); + + if (! ((strcmp (protocol_getName (list[0]), "MyProtocol") == 0 + && strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0) + || (strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0 + && strcmp (protocol_getName (list[1]), "MyProtocol") == 0))) + abort (); + + if (list[2] != NULL) + abort (); + } + + printf ("Testing class_createInstance ()...\n"); + { + MySubClass *object = [[MySubClass alloc] init]; + + [object setVariable: object]; + if ([object variable] != object) + abort (); + } + + printf ("Testing class_getClassMethod ()...\n"); + { + Method method = class_getClassMethod (objc_getClass ("MySubClass"), + @selector(alloc)); + + if (method == NULL) + abort (); + + if (strcmp (sel_getName (method_getName (method)), "alloc") != 0) + abort (); + + if (class_getClassMethod (objc_getClass ("MySubClass"), + @selector(variable))) + abort (); + } + + printf ("Testing class_getClassVariable ()...\n"); + { + if (class_getClassVariable (objc_getClass ("MySubClass"), "variable_ivar")) + abort (); + } + + printf ("Testing class_getInstanceMethod ()...\n"); + { + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector(variable)); + + if (method == NULL) + abort (); + + if (strcmp (sel_getName (method_getName (method)), "variable") != 0) + abort (); + + if (class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector(alloc))) + abort (); + } + + printf ("Testing class_getInstanceSize ()...\n"); + { + if (class_getInstanceSize (objc_getClass ("MyRootClass")) != sizeof (struct objc_object)) + abort (); + } + + printf ("Testing class_getInstanceVariable ()...\n"); + { + Ivar variable = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar"); + + if (variable == NULL) + abort (); + + if (strcmp (ivar_getName (variable), "variable_ivar") != 0) + abort (); + + if (class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar_no")) + abort (); + } + + printf ("Testing class_getIvarLayout ()...\n"); + { + if (class_getIvarLayout (objc_getClass ("MyRootClass")) != NULL) + abort (); + } + + printf ("Testing class_getMethodImplementation ()...\n"); + { + MySubClass *object = [[MySubClass alloc] init]; + IMP imp = class_getMethodImplementation (objc_getClass ("MySubClass"), + @selector(variable)); + + if (imp == NULL) + abort (); + + [object setVariable: object]; + + if ((*imp)(object, @selector(variable)) != object) + abort (); + } + + /* This function does not exist with the GNU runtime. */ + /* printf ("Testing class_getMethodImplementation_stret ()...\n"); */ + + printf ("Testing class_getName ()...\n"); + { + if (strcmp (class_getName (objc_getClass ("MyRootClass")), + "MyRootClass") != 0) + abort (); + } + + /* TODO: Test new ABI (when available). */ + printf ("Testing class_getProperty ()...\n"); + { + if (class_getProperty (objc_getClass ("MyRootClass"), "property") != NULL) + abort (); + } + + printf ("Testing class_getSuperclass ()...\n"); + { + MySubClass *object = [[MySubClass alloc] init]; + if (class_getSuperclass (object_getClass (object)) != objc_getClass ("MyRootClass")) + abort (); + } + + printf ("Testing class_getVersion ()...\n"); + { + if (class_getVersion (objc_getClass ("MySubClass")) != 0) + abort (); + } + + printf ("Testing class_getWeakIvarLayout ()...\n"); + { + if (class_getWeakIvarLayout (objc_getClass ("MyRootClass")) != NULL) + abort (); + } + + printf ("Testing class_isMetaClass ()...\n"); + { + MySubClass *object = [[MySubClass alloc] init]; + if (class_isMetaClass (object_getClass (object)) + || ! class_isMetaClass (object_getClass (object_getClass (object)))) + abort (); + } + + printf ("Testing class_replaceMethod ()...\n"); + { + Method new_method = class_getInstanceMethod (objc_getClass ("DifferentClass"), + @selector (myClass)); + Method old_method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (variable)); + const char *new_types = method_getTypeEncoding (new_method); + IMP new_imp = method_getImplementation (new_method); + const char *old_types = method_getTypeEncoding (old_method); + IMP old_imp = class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable), + method_getImplementation (new_method), + method_getTypeEncoding (new_method)); + MySubClass *o = [[MySubClass alloc] init]; + + [o setVariable: o]; + + /* Try the new method implementation. */ + if ([o variable] != objc_getClass ("MySubClass")) + abort (); + + /* Put the original method back. */ + class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable), + old_imp, old_types); + + /* Test it's back to what it was. */ + if ([o variable] != o) + abort (); + + { + DifferentClass *o = [[DifferentClass alloc] init]; + + /* Finally, try adding a new method. */ + class_replaceMethod (objc_getClass ("DifferentClass"), @selector (mySelf), + new_imp, new_types); + + if ([(MySubClass*)o mySelf] != objc_getClass ("DifferentClass")) + abort (); + } + } + + printf ("Testing class_respondsToSelector ()...\n"); + { + if (! class_respondsToSelector (objc_getClass ("MySubClass"), @selector(setVariable:))) + abort (); + + if (class_respondsToSelector (objc_getClass ("MyRootClass"), @selector(setVariable:))) + abort (); + } + + /* This is not really implemented with the GNU runtime. */ + /* printf ("Testing class_setIvarLayout ()...\n"); */ + + printf ("Testing class_setVersion ()...\n"); + { + class_setVersion (objc_getClass ("MySubClass"), 45); + + if (class_getVersion (objc_getClass ("MySubClass")) != 45) + abort (); + + class_setVersion (objc_getClass ("MySubClass"), 46); + + if (class_getVersion (objc_getClass ("MySubClass")) != 46) + abort (); + } + + /* This is not really implemented with the GNU runtime. */ + /* printf ("Testing class_setWeakIvarLayout ()...\n"); */ + + return 0; +} diff --git a/gcc/testsuite/objc.dg/gnu-api-2-ivar.m b/gcc/testsuite/objc.dg/gnu-api-2-ivar.m new file mode 100644 index 000000000..19ac004e7 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-api-2-ivar.m @@ -0,0 +1,83 @@ +/* Test the Modern GNU Objective-C Runtime API. + + This is test 'ivar', covering all functions starting with 'ivar'. */ + +/* { dg-do run } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* To get the modern GNU Objective-C Runtime API, you include + objc/runtime.h. */ +#include <objc/runtime.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +@interface MyRootClass +{ Class isa; } ++ alloc; +- init; ++ initialize; +@end + +@implementation MyRootClass ++ alloc { return class_createInstance (self, 0); } +- init { return self; } ++ initialize { return self; } +@end + +@protocol MyProtocol +- (id) variable; +@end + +@protocol MySecondProtocol +- (id) setVariable: (id)value; +@end + +@interface MySubClass : MyRootClass <MyProtocol> +{ id variable_ivar; } +- (void) setVariable: (id)value; +- (id) variable; +@end + +@implementation MySubClass +- (void) setVariable: (id)value { variable_ivar = value; } +- (id) variable { return variable_ivar; } +@end + + +int main(int argc, void **args) +{ + /* Functions are tested in alphabetical order. */ + + printf ("Testing ivar_getName () ...\n"); + { + Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"), + "variable_ivar"); + if (strcmp (ivar_getName (ivar), "variable_ivar") != 0) + abort (); + + ivar = class_getInstanceVariable (objc_getClass ("MySubClass"), + "variable"); + if (ivar != 0) + abort (); + } + + printf ("Testing ivar_getOffset () ...\n"); + { + Ivar ivar = class_getInstanceVariable (objc_getClass ("MyRootClass"), + "isa"); + if (ivar_getOffset (ivar) != 0) + abort (); + } + + printf ("Testing ivar_getTypeEncoding () ...\n"); + { + Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"), + "variable_ivar"); + if (strcmp (ivar_getTypeEncoding (ivar), "@") != 0) + abort (); + } + + return 0; +} diff --git a/gcc/testsuite/objc.dg/gnu-api-2-method.m b/gcc/testsuite/objc.dg/gnu-api-2-method.m new file mode 100644 index 000000000..fc447b69f --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-api-2-method.m @@ -0,0 +1,230 @@ +/* Test the Modern GNU Objective-C Runtime API. + + This is test 'method', covering all functions starting with 'method'. */ + +/* { dg-do run } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* To get the modern GNU Objective-C Runtime API, you include + objc/runtime.h. */ +#include <objc/runtime.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +@interface MyRootClass +{ Class isa; } ++ alloc; +- init; ++ initialize; +@end + +@implementation MyRootClass ++ alloc { return class_createInstance (self, 0); } +- init { return self; } ++ initialize { return self; } +@end + +@protocol MyProtocol +- (id) variable; +@end + +@protocol MySecondProtocol +- (id) setVariable: (id)value; +@end + +@interface MySubClass : MyRootClass <MyProtocol> +{ id variable_ivar; } +- (void) setVariable: (id)value; +- (id) variable; +- (id) constant; +@end + +@implementation MySubClass +- (void) setVariable: (id)value { variable_ivar = value; } +- (id) variable { return variable_ivar; } +- (id) constant { return nil; } +@end + + +int main(int argc, void **args) +{ + /* Functions are tested in alphabetical order. */ + + printf ("Testing method_copyArgumentType () ...\n"); + { + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (setVariable:)); + char *type = method_copyArgumentType (method, 2); + + if (type == NULL || type[0] != '@') + abort (); + } + + printf ("Testing method_copyReturnType () ...\n"); + { + Method method = class_getClassMethod (objc_getClass ("MyRootClass"), + @selector (alloc)); + char *type = method_copyReturnType (method); + + /* Check that it returns an object. */ + if (type == NULL || type[0] != '@') + abort (); + } + + printf ("Testing method_exchangeImplementations () ...\n"); + { + Method method_a = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (variable)); + Method method_b = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (constant)); + MySubClass *object = [[MySubClass alloc] init]; + + /* Check that things work as expected before the swap. */ + [object setVariable: object]; + + if ([object variable] != object || [object constant] != nil) + abort (); + + /* Swap the methods. */ + method_exchangeImplementations (method_a, method_b); + + /* Check that behaviour has changed. */ + if ([object variable] != nil || [object constant] != object) + abort (); + + /* Swap the methods again. */ + method_exchangeImplementations (method_a, method_b); + + /* Check that behaviour is back to normal. */ + if ([object variable] != object || [object constant] != nil) + abort (); + } + + printf ("Testing method_getArgumentType () ...\n"); + { + Method method = class_getInstanceMethod (objc_getClass ("MyRootClass"), + @selector (init)); + char type[16]; + + method_getArgumentType (method, 1, type, 16); + + /* Check the second argument (_cmd), which should be a SEL. */ + if (type[0] != ':') + abort (); + } + + printf ("Testing method_getDescription () ...\n"); + { + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (variable)); + struct objc_method_description *description = method_getDescription (method); + + if (strcmp (sel_getName (description->name), "variable") != 0) + abort (); + + if (method_getDescription (NULL) != NULL) + abort (); + } + + printf ("Testing method_getImplementation () ...\n"); + { + typedef void (*set_variable_function) (id receiver, SEL _cmd, id variable); + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (setVariable:)); + set_variable_function imp; + MySubClass *object = [[MySubClass alloc] init]; + + imp = (set_variable_function)(method_getImplementation (method)); + + (*imp)(object, @selector (setVariable:), object); + + if ([object variable] != object) + abort (); + } + + printf ("Testing method_getName () ...\n"); + { + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (setVariable:)); + if (strcmp (sel_getName (method_getName (method)), "setVariable:") != 0) + abort (); + } + + printf ("Testing method_getNumberOfArguments () ...\n"); + { + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (setVariable:)); + if (method_getNumberOfArguments (method) != 3) + abort (); + + method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (variable)); + if (method_getNumberOfArguments (method) != 2) + abort (); + } + + printf ("Testing method_getTypeEncoding () ...\n"); + { + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (setVariable:)); + const char *types = method_getTypeEncoding (method); + + /* Check that method type string starts with 'v' (void) */ + if (types == NULL || types[0] != 'v') + abort (); + } + + printf ("Testing method_getReturnType () ...\n"); + { + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (setVariable:)); + char type[16]; + + method_getReturnType (method, type, 16); + + if (type[0] != 'v') + abort (); + + method_getReturnType (NULL, type, 16); + + if (type[0] != 0) + abort (); + } + + printf ("Testing method_setImplementation () ...\n"); + { + Method method_a = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (variable)); + Method method_b = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (constant)); + IMP original_imp_a = method_getImplementation (method_a); + IMP original_imp_b = method_getImplementation (method_b); + MySubClass *object = [[MySubClass alloc] init]; + + /* Check that things work as expected before the swap. */ + [object setVariable: object]; + + if ([object variable] != object || [object constant] != nil) + abort (); + + /* Have 'variable' use the same implementation as 'constant'. */ + if (method_setImplementation (method_a, original_imp_b) != original_imp_a) + abort (); + + /* Check that behaviour has changed. */ + if ([object variable] != nil || [object constant] != nil) + abort (); + + /* Put the original method back. */ + if (method_setImplementation (method_a, original_imp_a) != original_imp_b) + abort (); + + /* Check that behaviour is back to normal. */ + if ([object variable] != object || [object constant] != nil) + abort (); + } + + return 0; +} diff --git a/gcc/testsuite/objc.dg/gnu-api-2-objc.m b/gcc/testsuite/objc.dg/gnu-api-2-objc.m new file mode 100644 index 000000000..59344efaf --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-api-2-objc.m @@ -0,0 +1,248 @@ +/* Test the Modern GNU Objective-C Runtime API. + + This is test 'objc', covering all functions starting with 'objc'. */ + +/* { dg-do run } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* To get the modern GNU Objective-C Runtime API, you include + objc/runtime.h. */ +#include <objc/runtime.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +@interface MyRootClass +{ Class isa; } ++ alloc; +- init; ++ initialize; +@end + +@implementation MyRootClass ++ alloc { return class_createInstance (self, 0); } +- init { return self; } ++ initialize { return self; } +@end + +@protocol MyProtocol +- (id) variable; +@end + +@protocol MySecondProtocol +- (id) setVariable: (id)value; +@end + +@interface MySubClass : MyRootClass <MyProtocol> +{ id variable_ivar; } +- (void) setVariable: (id)value; +- (id) variable; +@end + +@implementation MySubClass +- (void) setVariable: (id)value { variable_ivar = value; } +- (id) variable { return variable_ivar; } +@end + + +int main(int argc, void **args) +{ + /* Functions are tested in alphabetical order. */ + + printf ("Testing objc_allocateClassPair ()...\n"); + { + Class new_root_class = objc_allocateClassPair (Nil, "MyNewRootClass", 0); + Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass", 0); + + /* A new root class would obviously need at least an 'isa' + instance variable. We don't add it so we never actually + instantiate an instance of the class, which wouldn't work. */ + + objc_registerClassPair (new_root_class); + objc_registerClassPair (new_class); + + if (strcmp (class_getName (new_class), "MyNewSubClass") != 0) + abort (); + + if (class_getSuperclass (new_class) != objc_getClass ("MyRootClass")) + abort (); + + if (strcmp (class_getName (new_root_class), "MyNewRootClass") != 0) + abort (); + + if (class_getSuperclass (new_root_class) != Nil) + abort (); + + { + MySubClass *o = [[objc_getClass ("MyNewSubClass") alloc] init]; + + if (object_getClass (o) != objc_getClass ("MyNewSubClass")) + abort (); + } + } + + printf ("Testing objc_copyProtocolList ()...\n"); + { + /* Make sure both our two protocols are known to the runtime. */ + id my_protocol = @protocol (MyProtocol); + id my_second_protocol = @protocol (MySecondProtocol); + unsigned int count; + Protocol ** list = objc_copyProtocolList (&count); + + if (count != 2) + abort (); + + if (! ((strcmp (protocol_getName (list[0]), "MyProtocol") == 0 + && strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0) + || (strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0 + && strcmp (protocol_getName (list[1]), "MyProtocol") == 0))) + abort (); + + if (list[2] != NULL) + abort (); + } + + printf ("Testing objc_disposeClassPair ()...\n"); + { + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:)); + Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass2", 0); + + if (new_class == Nil) + abort (); + + /* Add a bit of everything to the class to exercise undoing all these changes. */ + + /* Instance variable. */ + class_addIvar (new_class, "my_variable", sizeof (float), __alignof__ (float), @encode (float)); + + /* Instance method. */ + class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method), + method_getTypeEncoding (method)); + + /* Class method. */ + class_addMethod (object_getClass (new_class), @selector (setVariable:), method_getImplementation (method), + method_getTypeEncoding (method)); + + /* Protocol. */ + class_addProtocol (new_class, @protocol (MyProtocol)); + + objc_disposeClassPair (new_class); + } + + /* This function currently does not exist with the GNU runtime. */ + /* printf ("Testing objc_duplicateClass ()...\n"); */ + + /* TODO - Test it when implemented in the GNU Runtime */ + /* printf ("Testing objc_getAssociatedObject ()...\n"); */ + + printf ("Testing objc_getClass ()...\n"); + { + if (strcmp (class_getName (objc_getClass ("MySubClass")), + "MySubClass") != 0) + abort (); + } + + printf ("Testing objc_getClassList ()...\n"); + { + Class *list; + int i, count, other_count; + count = objc_getClassList (NULL, 0); + + /* count most likely will be 5, (MyRootClass, MySubClass, + Protocol, Object, NXConstantString). */ + if (count < 3) + abort (); + + list = malloc (sizeof (Class) * count); + other_count = objc_getClassList (list, count); + + if (other_count != count) + abort (); + + /* Spot-check: search for class 'MyRootClass' in the list. */ + for (i = 0; i < count; i++) + { + if (strcmp (class_getName (list[i]), "MyRootClass") == 0) + break; + } + if (i == count) + abort (); + + /* Spot-check: search for class 'MySubClass' in the list. */ + for (i = 0; i < count; i++) + { + if (strcmp (class_getName (list[i]), "MySubClass") == 0) + break; + } + if (i == count) + abort (); + + /* Spot-check: search for class 'Protocol' in the list. */ + for (i = 0; i < count; i++) + { + if (strcmp (class_getName (list[i]), "Protocol") == 0) + break; + } + if (i == count) + abort (); + } + + /* This function does not exist with the GNU runtime. */ + /* printf ("Testing objc_getFutureClass ()...\n"); */ + + printf ("Testing objc_getMetaClass ()...\n"); + { + if (! class_isMetaClass (objc_getMetaClass ("MyRootClass"))) + abort (); + } + + printf ("Testing objc_getProtocol ()...\n"); + { + if (! protocol_isEqual (objc_getProtocol ("MyProtocol"), @protocol (MyProtocol))) + abort (); + } + + printf ("Testing objc_getRequiredClass ()...\n"); + { + if (strcmp (class_getName (objc_getRequiredClass ("MyRootClass")), + "MyRootClass") != 0) + abort (); + } + + printf ("Testing objc_lookUpClass ()...\n"); + { + if (strcmp (class_getName (objc_lookUpClass ("MyRootClass")), + "MyRootClass") != 0) + abort (); + } + + /* This function does not exist with the GNU runtime. */ + /* printf ("Testing objc_setFutureClass ()...\n"); */ + + printf ("Testing objc_registerClassPair ()...\n"); + { + Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0); + + class_addProtocol (new_class, @protocol (MySecondProtocol)); + + objc_registerClassPair (new_class); + + if (strcmp (class_getName (new_class), "MySubSubClass") != 0) + abort (); + + if (class_getSuperclass (new_class) != objc_getClass ("MySubClass")) + abort (); + + if (! class_conformsToProtocol (new_class, @protocol (MySecondProtocol))) + abort (); + } + + /* TODO - Test it when implemented in the GNU Runtime */ + /* printf ("Testing objc_removeAssociatedObjects ()...\n"); */ + + /* TODO - Test it when implemented in the GNU Runtime */ + /* printf ("Testing objc_setAssociatedObject ()...\n"); */ + + return 0; +} diff --git a/gcc/testsuite/objc.dg/gnu-api-2-objc_msg_lookup.m b/gcc/testsuite/objc.dg/gnu-api-2-objc_msg_lookup.m new file mode 100644 index 000000000..5751f3fd2 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-api-2-objc_msg_lookup.m @@ -0,0 +1,77 @@ +/* Test the Modern GNU Objective-C Runtime API. + + This is test 'objc_msg_lookup', covering objc_msg_lookup(), + objc_msg_lookup_super() and struct objc_super. */ + +/* { dg-do run } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +/* To get the modern GNU Objective-C Runtime API, you include + objc/runtime.h. */ +#include <objc/runtime.h> + +/* For objc_msg_lookup(), objc_msg_lookup_super() and struct + objc_super. */ +#include <objc/message.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +@interface MyRootClass +{ Class isa; } ++ alloc; +- init; +- (int) test; +@end + +@implementation MyRootClass ++ alloc { return class_createInstance (self, 0); } +- init { return self; } +- (int) test { return 20; } +@end + +@interface MySubClass : MyRootClass +- (int) test; +@end + +@implementation MySubClass +- (int) test { return 11; } +@end + +int main (int argc, void **args) +{ + /* Functions are tested in alphabetical order. */ + + printf ("Testing objc_msg_lookup ()...\n"); + { + MySubClass *object = [[MySubClass alloc] init]; + int (* test_IMP) (id receiver, SEL selector); + + test_IMP = (int (*)(id, SEL))objc_msg_lookup (object, @selector (test)); + + if (test_IMP (object, @selector (test)) != 11) + abort (); + } + + printf ("Testing objc_msg_lookup_super ()...\n"); + { + MySubClass *object = [[MySubClass alloc] init]; + struct objc_super super = { 0, 0 }; + int (* test_IMP) (id receiver, SEL selector); + + /* Get the implementation of -test for the superclass of object - + as if we were calling [super test] inside a method + implementation of object. */ + super.self = object; + super.super_class = class_getSuperclass (object_getClass (object)); + test_IMP = (int (*)(id, SEL))objc_msg_lookup_super (&super, @selector (test)); + + /* Invoke it. The method in MyRootClass, not the one in + MySubClass, should be invoked. */ + if (test_IMP (object, @selector (test)) != 20) + abort (); + } + + return 0; +} diff --git a/gcc/testsuite/objc.dg/gnu-api-2-object.m b/gcc/testsuite/objc.dg/gnu-api-2-object.m new file mode 100644 index 000000000..3d4d444fe --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-api-2-object.m @@ -0,0 +1,164 @@ +/* Test the Modern GNU Objective-C Runtime API. + + This is test 'object', covering all functions starting with 'object'. */ + +/* { dg-do run } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* To get the modern GNU Objective-C Runtime API, you include + objc/runtime.h. */ +#include <objc/runtime.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +@interface MyRootClass +{ Class isa; } ++ alloc; +- init; ++ initialize; +@end + +@implementation MyRootClass ++ alloc { return class_createInstance (self, 0); } +- init { return self; } ++ initialize { return self; } +@end + +@protocol MyProtocol +- (id) variable; +@end + +@protocol MySecondProtocol +- (id) setVariable: (id)value; +@end + +@interface MySubClass : MyRootClass <MyProtocol> +{ id variable_ivar; } +- (void) setVariable: (id)value; +- (id) variable; +@end + +@implementation MySubClass +- (void) setVariable: (id)value { variable_ivar = value; } +- (id) variable { return variable_ivar; } +@end + +@interface MySubSubClass : MySubClass +- (id) test; +@end + +@implementation MySubSubClass +- (id) test { return self; } +@end + + + +int main(int argc, void **args) +{ + /* Functions are tested in alphabetical order. */ + + printf ("Testing object_copy () ...\n"); + { + MySubClass *object_a = [[MySubClass alloc] init]; + MySubClass *object_b = object_copy (object_a, 0); + + [object_b setVariable: object_a]; + if ([object_b variable] != object_a) + abort (); + } + + printf ("Testing object_dispose () ...\n"); + { + MySubClass *object = [[MySubClass alloc] init]; + + object_dispose (object); + } + + printf ("Testing object_getClass () ...\n"); + { + MyRootClass *o = [[MySubClass alloc] init]; + + if (object_getClass (o) != objc_getClass ("MySubClass")) + abort (); + } + + printf ("Testing object_getClassName () ...\n"); + { + MyRootClass *o = [[MyRootClass alloc] init]; + + if (strcmp (object_getClassName (o), "MyRootClass") != 0) + abort (); + } + + printf ("Testing object_getIndexedIvars () ...\n"); + { + if (object_getIndexedIvars ([[MyRootClass alloc] init]) == NULL) + abort (); + } + + printf ("Testing object_getInstanceVariable () ...\n"); + { + MySubClass *o = [[MySubClass alloc] init]; + id value; + + [o setVariable: o]; + + if (object_getInstanceVariable (o, "variable_ivar", (void **)&value) == NULL) + abort (); + + if (value != o) + abort (); + } + + printf ("Testing object_getIvar () ...\n"); + { + MySubClass *o = [[MySubClass alloc] init]; + Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar"); + + [o setVariable: o]; + + if (object_getIvar (o, ivar) != o) + abort (); + } + + printf ("Testing object_setClass () ...\n"); + { + MySubClass *o = [[MySubClass alloc] init]; + + object_setClass (o, objc_getClass ("MySubSubClass")); + + if ([(MySubSubClass *)o test] != o) + abort (); + } + + printf ("Testing object_setInstanceVariable () ...\n"); + { + MySubClass *o = [[MySubClass alloc] init]; + + [o setVariable: nil]; + + if (object_setInstanceVariable (o, "variable_ivar", (void *)o) == NULL) + abort (); + + if ([o variable] != o) + abort (); + } + + printf ("Testing object_setIvar () ...\n"); + { + MySubClass *o = [[MySubClass alloc] init]; + MySubClass *value = [[MySubClass alloc] init]; + Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar"); + + [o setVariable: o]; + + object_setIvar (o, ivar, value); + + if ([o variable] != value) + abort (); + } + + return 0; +} diff --git a/gcc/testsuite/objc.dg/gnu-api-2-property.m b/gcc/testsuite/objc.dg/gnu-api-2-property.m new file mode 100644 index 000000000..12c0d8b98 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-api-2-property.m @@ -0,0 +1,100 @@ +/* Test the Modern GNU Objective-C Runtime API. + + This is test 'property', covering all functions starting with 'property'. */ + +/* { dg-do run } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ + +/* To get the modern GNU Objective-C Runtime API, you include + objc/runtime.h. */ +#include <objc/runtime.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +@interface MyRootClass +{ Class isa; } ++ alloc; +- init; ++ initialize; +@end + +@implementation MyRootClass ++ alloc { return class_createInstance (self, 0); } +- init { return self; } ++ initialize { return self; } +@end + +@interface MySubClass : MyRootClass +{ + id propertyA; + id propertyB; +} +@property (assign, getter=getP, setter=setP:) id propertyA; +@property (assign, nonatomic) id propertyB; +@end + +@implementation MySubClass +@synthesize propertyA; +@synthesize propertyB; +@end + + +int main(int argc, void **args) +{ + /* Functions are tested in alphabetical order. */ + + printf ("Testing property_getAttributes () ...\n"); + { + /* The Apple/NeXT runtime seems to crash on the following. */ +#ifdef __GNU_LIBOBJC__ + if (property_getAttributes (NULL) != NULL) + abort (); +#endif + + /* The GNU runtime doesn't support looking up properties at + runtime yet. */ +#ifdef __OBJC2__ + { + objc_property_t property; + + property = class_getProperty (objc_getClass ("MySubClass"), "propertyA"); + if (strcmp (property_getAttributes (property), + "T@,GgetP,SsetP:,VpropertyA") != 0) + abort (); + + property = class_getProperty (objc_getClass ("MySubClass"), "propertyB"); + if (strcmp (property_getAttributes (property), + "T@,N,VpropertyB") != 0) + abort (); + } +#endif + } + + printf ("Testing property_getName () ...\n"); + { + /* The Apple/NeXT runtime seems to crash on the following. */ +#ifdef __GNU_LIBOBJC__ + if (property_getName (NULL) != NULL) + abort (); +#endif + + /* The GNU runtime doesn't support looking up properties at + runtime yet. */ +#ifdef __OBJC2__ + { + objc_property_t property; + + property = class_getProperty (objc_getClass ("MySubClass"), "propertyA"); + if (strcmp (property_getName (property), "propertyA") != 0) + abort (); + + property = class_getProperty (objc_getClass ("MySubClass"), "propertyB"); + if (strcmp (property_getName (property), "propertyB") != 0) + abort (); + } +#endif + } + + return 0; +} diff --git a/gcc/testsuite/objc.dg/gnu-api-2-protocol.m b/gcc/testsuite/objc.dg/gnu-api-2-protocol.m new file mode 100644 index 000000000..a34d74ce9 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-api-2-protocol.m @@ -0,0 +1,163 @@ +/* Test the Modern GNU Objective-C Runtime API. + + This is test 'protocol', covering all functions starting with 'protocol'. */ + +/* { dg-do run } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* To get the modern GNU Objective-C Runtime API, you include + objc/runtime.h. */ +#include <objc/runtime.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +@interface MyRootClass +{ Class isa; } ++ alloc; +- init; ++ initialize; +@end + +@implementation MyRootClass ++ alloc { return class_createInstance (self, 0); } +- init { return self; } ++ initialize { return self; } +@end + +@protocol MyProtocol +- (id) variable; +@end + +@protocol MySecondProtocol +- (id) setVariable: (id)value; +@end + +@protocol MyThirdProtocol <MySecondProtocol> +- (id) setAnotherVariable: (id)value; +@end + +@interface MySubClass : MyRootClass <MyProtocol> +{ id variable_ivar; } +- (void) setVariable: (id)value; +- (id) variable; +@end + +@implementation MySubClass +- (void) setVariable: (id)value { variable_ivar = value; } +- (id) variable { return variable_ivar; } +@end + + +int main(int argc, void **args) +{ + /* Functions are tested in alphabetical order. */ + + printf ("Testing protocol_conformsToProtocol ()...\n"); + { + if (!protocol_conformsToProtocol (@protocol (MyProtocol), + @protocol (MyProtocol))) + abort (); + + if (!protocol_conformsToProtocol (@protocol (MyThirdProtocol), + @protocol (MySecondProtocol))) + abort (); + + if (protocol_conformsToProtocol (@protocol (MyProtocol), + @protocol (MySecondProtocol))) + abort (); + } + + printf ("Testing protocol_copyMethodDescriptionList ()...\n"); + { + unsigned int count; + struct objc_method_description *list; + + list = protocol_copyMethodDescriptionList (@protocol (MyThirdProtocol), + YES, YES, &count); + + if (count != 1) + abort (); + + if (strcmp (sel_getName (list[0].name), "setAnotherVariable:") != 0) + abort (); + + if (list[1].name != NULL && list[1].types != NULL) + abort (); + } + + /* TODO: Test new ABI (when available). */ + printf ("Testing protocol_copyPropertyList ()...\n"); + { + unsigned int count; + objc_property_t *list; + + list = protocol_copyPropertyList (@protocol (MyProtocol), &count); + + if (count != 0 || list != NULL) + abort (); + } + + printf ("Testing protocol_copyProtocolList ()...\n"); + { + unsigned int count; + Protocol **list; + + list = protocol_copyProtocolList (@protocol (MyThirdProtocol), &count); + + if (count != 1) + abort (); + + if (strcmp (protocol_getName (list[0]), "MySecondProtocol") != 0) + abort (); + + if (list[1] != NULL) + abort (); + } + + printf ("Testing protocol_getMethodDescription ()...\n"); + { + struct objc_method_description description; + + description = protocol_getMethodDescription (@protocol (MySecondProtocol), + @selector (setVariable:), + YES, YES); + if (description.name == NULL && description.types == NULL) + abort (); + + if (strcmp (sel_getName (description.name), "setVariable:") != 0) + abort (); + } + + printf ("Testing protocol_getName ()...\n"); + { + if (strcmp (protocol_getName (@protocol (MyProtocol)), "MyProtocol") != 0) + abort (); + } + + /* TODO: Test new ABI (when available). */ + printf ("Testing protocol_getProperty ()...\n"); + { + objc_property_t property; + + property = protocol_getProperty (objc_getProtocol ("MyProtocol"), "someProperty", + YES, YES); + + if (property != NULL) + abort (); + } + + printf ("Testing protocol_isEqual ()...\n"); + { + if (!protocol_isEqual (@protocol (MyProtocol), + @protocol (MyProtocol))) + abort (); + + if (!protocol_isEqual (@protocol (MyProtocol), + objc_getProtocol ("MyProtocol"))) + abort (); + } + + return 0; +} diff --git a/gcc/testsuite/objc.dg/gnu-api-2-resolve-method.m b/gcc/testsuite/objc.dg/gnu-api-2-resolve-method.m new file mode 100644 index 000000000..a38770990 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-api-2-resolve-method.m @@ -0,0 +1,567 @@ +/* Test the Modern GNU Objective-C Runtime API. + + This is test 'resolve-method', covering +resolveClassMethod: and + +resolveInstanceMethod:. */ + +/* { dg-do run } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +/* To get the modern GNU Objective-C Runtime API, you include + objc/runtime.h. */ +#include <objc/runtime.h> + +/* For __objc_msg_forward2. */ +#include <objc/message.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +@interface MyRootClass +{ Class isa; } ++ alloc; +- init; +@end + +@implementation MyRootClass ++ alloc { return class_createInstance (self, 0); } +- init { return self; } +@end + + +/* A number of tests will try invoking methods that don't exist. We + want to record the fact, but not abort the program, so we supply + our own fowarding implementation which will invoke the following + function for any method that is not found. */ + +/* Keep track of how many times a non-existing method was executed. */ +static int nonExistingMethodCount = 0; + +/* Inspired by nil_method in libobjc. */ +id nonExisting_method (id receiver __attribute__ ((__unused__)), + SEL sel __attribute__ ((__unused__))) +{ + nonExistingMethodCount++; + return nil; +} + +/* Keep track of how many times the forwarding lookup was invoked. */ +static int forwardingCount = 0; + +/* We install this forwarding hook to cause all failed method lookups + to call our 'nonExisting_method' function. */ +IMP forward_everything_to_non_existing_method (id receiver __attribute__ ((__unused__)), + SEL sel __attribute__ ((__unused__))) +{ + forwardingCount++; + return (IMP)nonExisting_method; +} + + +/* 'CountClass' is used to test that +resolveClassMethod: and + +resolveInstanceMethod: are called when expected. They do nothing + other than recording that they are called. */ +@interface CountClass : MyRootClass ++ (BOOL) resolveClassMethod: (SEL)selector; ++ (BOOL) resolveInstanceMethod: (SEL)selector; ++ (void) existingClassMethod; +- (void) existingInstanceMethod; +@end + +/* Count how many times the methods are called for class + 'CountClass'. */ +static int resolveClassMethodCount = 0; +static int resolveInstanceMethodCount = 0; + +@implementation CountClass : MyRootClass ++ (BOOL) resolveClassMethod: (SEL)selector +{ + resolveClassMethodCount++; + return NO; +} ++ (BOOL) resolveInstanceMethod: (SEL)selector +{ + resolveInstanceMethodCount++; + return NO; +} ++ (void) existingClassMethod +{ + return; +} +- (void) existingInstanceMethod +{ + return; +} +@end + +@protocol NonExistingStuff ++ (void) nonExistingClassMethod; +- (void) nonExistingInstanceMethod; +@end + +/* Declare a category with some non existing methods, but don't + actually implement them. */ +@interface CountClass (NonExistingStuff) <NonExistingStuff> +@end + + +/* 'SelfExtendingClass' is used to test that +resolveClassMethod: and + +resolveInstanceMethod: can extend the class. Any time they are + called, they install the requested method, mapping it to the same + implementation as 'countHits'. */ +@interface SelfExtendingClass : MyRootClass ++ (int) countHits; ++ (BOOL) resolveClassMethod: (SEL)selector; ++ (BOOL) resolveInstanceMethod: (SEL)selector; +@end + +/* How many times the countHits method (or a clone) was called. */ +static int hitCount = 0; + +@implementation SelfExtendingClass : MyRootClass ++ (int) countHits +{ + hitCount++; + return hitCount; +} ++ (BOOL) resolveClassMethod: (SEL)selector +{ + /* Duplicate the 'countHits' method into the new method. */ + Method method = class_getClassMethod (self, @selector (countHits)); + class_addMethod (object_getClass (self), selector, + method_getImplementation (method), + method_getTypeEncoding (method)); + resolveClassMethodCount++; + return YES; +} ++ (BOOL) resolveInstanceMethod: (SEL)selector +{ + /* Duplicate the 'countHits' method into the new method. */ + Method method = class_getClassMethod (self, @selector (countHits)); + class_addMethod (self, selector, + method_getImplementation (method), + method_getTypeEncoding (method)); + resolveInstanceMethodCount++; + return YES; + +} +@end + +@protocol NonExistingStuff2 ++ (int) nonExistingCountHitsMethod; +- (int) nonExistingCountHitsMethod; + ++ (int) nonExistingCountHitsMethod2; +- (int) nonExistingCountHitsMethod2; + ++ (int) nonExistingCountHitsMethod3; +- (int) nonExistingCountHitsMethod3; +@end + +/* Declare a category with some non existing methods, but don't + actually implement them. */ +@interface SelfExtendingClass (NonExistingStuff) <NonExistingStuff2> +@end + + +int main (int argc, void **args) +{ + /* Functions are tested in alphabetical order. */ + + /* Install our test forwarding hook. */ + __objc_msg_forward2 = forward_everything_to_non_existing_method; + + printf ("Testing [+resolveClassMethod:]...\n"); + { + Method m; + IMP i; + + /** CountClass tests. **/ + + /* Call an existing method. No +resolveClassMethod and no + forwarding should be triggered. */ + [CountClass existingClassMethod]; + + if (resolveClassMethodCount != 0) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + /* Call a non-existing method. Both +resolveClassMethod and the + forwarding should be triggered. */ + [CountClass nonExistingClassMethod]; + + if (resolveClassMethodCount != 1) + abort (); + + if (forwardingCount != 1) + abort (); + + if (nonExistingMethodCount != 1) + abort (); + + /* Now try the same tests with class_getClassMethod(), which + should trigger the resolve methods too, but not the + forwarding. */ + m = class_getClassMethod (objc_getClass ("CountClass"), + @selector (existingClassMethod)); + if (resolveClassMethodCount != 1) + abort (); + + if (forwardingCount != 1) + abort (); + + if (nonExistingMethodCount != 1) + abort (); + + m = class_getClassMethod (objc_getClass ("CountClass"), + @selector (nonExistingClassMethod)); + if (resolveClassMethodCount != 2) + abort (); + + if (forwardingCount != 1) + abort (); + + if (nonExistingMethodCount != 1) + abort (); + + /* Now try the same tests with class_getMethodImplementation(), + which should trigger the resolve methods and the forwarding + (but not execute the forwarding, obviously). */ + i = class_getMethodImplementation (object_getClass (objc_getClass ("CountClass")), + @selector (existingClassMethod)); + if (resolveClassMethodCount != 2) + abort (); + + if (forwardingCount != 1) + abort (); + + if (nonExistingMethodCount != 1) + abort (); + + i = class_getMethodImplementation (object_getClass (objc_getClass ("CountClass")), + @selector (nonExistingClassMethod)); + if (resolveClassMethodCount != 3) + abort (); + + if (forwardingCount != 2) + abort (); + + if (nonExistingMethodCount != 1) + abort (); + + + /* Reset the counters for the next test. */ + resolveClassMethodCount = 0; + forwardingCount = 0; + nonExistingMethodCount = 0; + + + /** SelfExtendingClass tests. **/ + + /* Try the direct countHits method first. No resolving or + forwarding should be triggered. */ + if ([SelfExtendingClass countHits] != 1) + abort (); + + if (resolveClassMethodCount != 0) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + /* Now, try calling a non-existing count method; it should be + installed and invoked. */ + if ([SelfExtendingClass nonExistingCountHitsMethod] != 2) + abort (); + + if (resolveClassMethodCount != 1) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + /* Try it again. The method has now been installed, so it should + be used and work, but with no additional resolving + involved. */ + if ([SelfExtendingClass nonExistingCountHitsMethod] != 3) + abort (); + + if (resolveClassMethodCount != 1) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + + /* Now try the same tests with class_getClassMethod(). */ + m = class_getClassMethod (objc_getClass ("SelfExtendingClass"), + @selector (nonExistingCountHitsMethod2)); + if (resolveClassMethodCount != 2) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + /* Try it again. The method has now been installed, so it should + be used and work, but with no additional resolving + involved. */ + if ([SelfExtendingClass nonExistingCountHitsMethod2] != 4) + abort (); + + if (resolveClassMethodCount != 2) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + + /* Now try the same tests with class_getMethodImplementation(). */ + i = class_getMethodImplementation (object_getClass (objc_getClass ("SelfExtendingClass")), + @selector (nonExistingCountHitsMethod3)); + if (resolveClassMethodCount != 3) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + /* Try it again. The method has now been installed, so it should + be used and work, but with no additional resolving + involved. */ + if ([SelfExtendingClass nonExistingCountHitsMethod3] != 5) + abort (); + + if (resolveClassMethodCount != 3) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + } + + /* Reset the counters for the next test. */ + nonExistingMethodCount = 0; + forwardingCount = 0; + hitCount = 0; + + printf ("Testing [+resolveInstanceMethod:]...\n"); + { + Method m; + IMP i; + CountClass *object = [[CountClass alloc] init]; + SelfExtendingClass *object2 = [[SelfExtendingClass alloc] init]; + + /** CountClass tests. **/ + + /* Call an existing method. No +resolveInstanceMethod and no + forwarding should be triggered. */ + [object existingInstanceMethod]; + + if (resolveInstanceMethodCount != 0) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + /* Call a non-existing method. Both +resolveInstanceMethod and the + forwarding should be triggered. */ + [object nonExistingInstanceMethod]; + + if (resolveInstanceMethodCount != 1) + abort (); + + if (forwardingCount != 1) + abort (); + + if (nonExistingMethodCount != 1) + abort (); + + /* Now try the same tests with class_getInstanceMethod(), which + should trigger the resolve methods too, but not the + forwarding. */ + m = class_getInstanceMethod (objc_getClass ("CountClass"), + @selector (existingInstanceMethod)); + + if (resolveInstanceMethodCount != 1) + abort (); + + if (forwardingCount != 1) + abort (); + + if (nonExistingMethodCount != 1) + abort (); + + m = class_getInstanceMethod (objc_getClass ("CountClass"), + @selector (nonExistingInstanceMethod)); + + if (resolveInstanceMethodCount != 2) + abort (); + + if (forwardingCount != 1) + abort (); + + if (nonExistingMethodCount != 1) + abort (); + + /* Now try the same tests with class_getMethodImplementation(), + which should trigger the resolve methods and the + forwarding. */ + i = class_getMethodImplementation (objc_getClass ("CountClass"), + @selector (existingInstanceMethod)); + if (resolveInstanceMethodCount != 2) + abort (); + + if (forwardingCount != 1) + abort (); + + if (nonExistingMethodCount != 1) + abort (); + + i = class_getMethodImplementation (objc_getClass ("CountClass"), + @selector (nonExistingInstanceMethod)); + if (resolveInstanceMethodCount != 3) + abort (); + + if (forwardingCount != 2) + abort (); + + if (nonExistingMethodCount != 1) + abort (); + + /* Reset the counters for the next test. */ + resolveInstanceMethodCount = 0; + forwardingCount = 0; + nonExistingMethodCount = 0; + + + /** SelfExtendingClass tests. **/ + + /* Try the direct countHits method first. No resolving or + forwarding should be triggered. */ + if ([SelfExtendingClass countHits] != 1) + abort (); + + if (resolveInstanceMethodCount != 0) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + /* Now, try calling a non-existing count method; it should be + installed and invoked. */ + if ([object2 nonExistingCountHitsMethod] != 2) + abort (); + + if (resolveInstanceMethodCount != 1) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + /* Try it again. The method has now been installed, so it should + be used and work, but with no additional resolving + involved. */ + if ([object2 nonExistingCountHitsMethod] != 3) + abort (); + + if (resolveInstanceMethodCount != 1) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + /* Now try the same tests with class_getInstanceMethod(). */ + m = class_getInstanceMethod (objc_getClass ("SelfExtendingClass"), + @selector (nonExistingCountHitsMethod2)); + if (resolveInstanceMethodCount != 2) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + /* Try it again. The method has now been installed, so it should + be used and work, but with no additional resolving + involved. */ + if ([object2 nonExistingCountHitsMethod2] != 4) + abort (); + + if (resolveInstanceMethodCount != 2) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + + /* Now try the same tests with class_getMethodImplementation(). */ + i = class_getMethodImplementation (objc_getClass ("SelfExtendingClass"), + @selector (nonExistingCountHitsMethod3)); + if (resolveInstanceMethodCount != 3) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + + /* Try it again. The method has now been installed, so it should + be used and work, but with no additional resolving + involved. */ + if ([object2 nonExistingCountHitsMethod3] != 5) + abort (); + + if (resolveInstanceMethodCount != 3) + abort (); + + if (forwardingCount != 0) + abort (); + + if (nonExistingMethodCount != 0) + abort (); + } + + + return 0; +} diff --git a/gcc/testsuite/objc.dg/gnu-api-2-sel.m b/gcc/testsuite/objc.dg/gnu-api-2-sel.m new file mode 100644 index 000000000..b71fdfab4 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-api-2-sel.m @@ -0,0 +1,209 @@ +/* Test the Modern GNU Objective-C Runtime API. + + This is test 'sel', covering all functions starting with 'sel'. */ + +/* { dg-do run } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ + +/* To get the modern GNU Objective-C Runtime API, you include + objc/runtime.h. */ +#include <objc/runtime.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +@interface MyRootClass +{ Class isa; } ++ alloc; +- init; ++ initialize; +@end + +@implementation MyRootClass ++ alloc { return class_createInstance (self, 0); } +- init { return self; } ++ initialize { return self; } +@end + +@protocol MyProtocol +- (id) variable; +@end + +@protocol MySecondProtocol +- (id) setVariable: (id)value; +@end + +@interface MySubClass : MyRootClass <MyProtocol> +{ id variable_ivar; } +- (void) setVariable: (id)value; +- (id) variable; +- (void) method; +@end + +@implementation MySubClass +- (void) setVariable: (id)value { variable_ivar = value; } +- (id) variable { return variable_ivar; } +- (void) method { return; } +@end + +@interface ClassA : MyRootClass +- (id) conflictingSelectorMethod; +@end + +@implementation ClassA +- (id) conflictingSelectorMethod { return nil; } +@end + +@interface ClassB : MyRootClass +- (void) conflictingSelectorMethod; +@end + +@implementation ClassB +- (void) conflictingSelectorMethod { return; } +@end + +int main(int argc, void **args) +{ + /* Functions are tested in alphabetical order. */ + +#ifdef __GNU_LIBOBJC__ + printf ("Testing sel_copyTypedSelectorList ()...\n"); + { + unsigned int count; + SEL * list = sel_copyTypedSelectorList ("method", &count); + + /* There should only be two, since 'method' is referenced twice, + once with types and once without (in this very test). */ + if (count != 2) + abort (); + + /* Check that both selectors are not-NULL, and have the correct + name. We use @selector() here, which wouldn't really be + needed, just to register a second, untyped selector with name + 'method'. */ + if (strcmp (sel_getName (list[0]), sel_getName (@selector (method))) != 0) + abort (); + + if (strcmp (sel_getName (list[1]), sel_getName (@selector (method))) != 0) + abort (); + + if (list[2] != NULL) + abort (); + } +#endif + + printf ("Testing sel_getName () ...\n"); + { + if (strcmp (sel_getName (@selector (variable)), "variable") != 0) + abort (); + + if (strcmp (sel_getName (NULL), "<null selector>") != 0) + abort (); + } + +#ifdef __GNU_LIBOBJC__ + printf ("Testing sel_getTypeEncoding () ...\n"); + { + /* Get a selector from a real class, so it has interesting + types. */ + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (variable)); + + if (strcmp (sel_getTypeEncoding (method_getName (method)), + method_getTypeEncoding (method)) != 0) + abort (); + + if (sel_getTypeEncoding (NULL) != NULL) + abort (); + } +#endif + +#ifdef __GNU_LIBOBJC__ + printf ("Testing sel_getTypedSelector () ...\n"); + { + /* First try with a selector where we know that a typed one has + been registered. */ + SEL selector = sel_getTypedSelector ("variable"); + + if (selector == NULL) + abort (); + + if (sel_getTypeEncoding (selector) == NULL) + abort (); + + /* Now try a selector which was never registered. */ + selector = sel_getTypedSelector ("not_registered"); + + if (selector != NULL) + abort (); + + /* Now try registering a selector with no types. The following + line is just a way to have an unused '@selector()' expression + without the compiler complaining. */ + if (@selector (registered_with_no_types) == NULL) + abort (); + + /* Try getting it. Nothing should be returned because it is + untyped. */ + selector = sel_getTypedSelector ("registered_with_no_types"); + + if (selector != NULL) + abort (); + + /* Now try a selector with multiple, conflicting types. NULL + should be returned. */ + selector = sel_getTypedSelector ("conflictingSelectorMethod"); + + if (selector != NULL) + abort (); + } +#endif + + printf ("Testing sel_getUid () ...\n"); + { + if (strcmp (sel_getName (sel_getUid ("myMethod")), "myMethod") != 0) + abort (); + + if (sel_getUid (NULL) != NULL) + abort (); + } + + printf ("Testing sel_isEqual () ...\n"); + { + if (! sel_isEqual (@selector (setVariable:), @selector (setVariable:))) + abort (); + } + + printf ("Testing sel_registerName () ...\n"); + { + if (strcmp (sel_getName (sel_registerName ("myMethod")), "myMethod") != 0) + abort (); + + if (sel_registerName (NULL) != NULL) + abort (); + } + +#ifdef __GNU_LIBOBJC__ + printf ("Testing set_registerTypedName () ...\n"); + { + const char *types = method_getTypeEncoding (class_getInstanceMethod + (objc_getClass ("MySubClass"), + @selector (variable))); + SEL selector = sel_registerTypedName ("aMethod", types); + + if (strcmp (sel_getName (selector), "aMethod") != 0) + abort (); + + if (strcmp (sel_getTypeEncoding (selector), types) != 0) + abort (); + + if (sel_registerTypedName (NULL, NULL) != NULL) + abort (); + + if (sel_registerTypedName (NULL, types) != NULL) + abort (); + } +#endif + + return 0; +} diff --git a/gcc/testsuite/objc.dg/gnu-encoding/compat-common.h b/gcc/testsuite/objc.dg/gnu-encoding/compat-common.h new file mode 100644 index 000000000..635e7446d --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-encoding/compat-common.h @@ -0,0 +1,43 @@ +/* Several of the binary compatibility tests use these macros to + allow debugging the test or tracking down a failure by getting an + indication of whether each individual check passed or failed. + When DBG is defined, each check is shown by a dot (pass) or 'F' + (fail) rather than aborting as soon as a failure is detected. */ + +#ifdef DBG +#include <stdio.h> +#define DEBUG_INIT setbuf (stdout, NULL); +#define DEBUG_FPUTS(x) fputs (x, stdout) +#define DEBUG_DOT putc ('.', stdout) +#define DEBUG_NL putc ('\n', stdout) +#define DEBUG_FAIL putc ('F', stdout); fails++ +#define DEBUG_CHECK { DEBUG_FAIL; } else { DEBUG_DOT; } +#define DEBUG_FINI if (fails) DEBUG_FPUTS ("failed\n"); \ + else DEBUG_FPUTS ("passed\n"); +#else +#define DEBUG_INIT +#define DEBUG_FPUTS(x) +#define DEBUG_DOT +#define DEBUG_NL +#define DEBUG_FAIL abort () +#define DEBUG_CHECK abort (); +#define DEBUG_FINI +#endif + +#ifdef __GNUC__ +#define CINT(x, y) (x + y * __extension__ 1i) +#define CDBL(x, y) (x + y * __extension__ 1i) +#else +#ifdef __SUNPRO_C +/* ??? Complex support without <complex.h>. */ +#else +#include <complex.h> +#endif +#ifndef SKIP_COMPLEX_INT +#define CINT(x, y) ((_Complex int) (x + y * _Complex_I)) +#endif +#define CDBL(x, y) (x + y * _Complex_I) +#endif + +extern void abort (void); +extern int fails; diff --git a/gcc/testsuite/objc.dg/gnu-encoding/generate-random.c b/gcc/testsuite/objc.dg/gnu-encoding/generate-random.c new file mode 100644 index 000000000..c4b06db67 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-encoding/generate-random.c @@ -0,0 +1,265 @@ +/* Copyright (C) 1995, 2004 Free Software Foundation + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. */ + +/* + * This is derived from the Berkeley source: + * @(#)random.c 5.5 (Berkeley) 7/6/88 + * It was reworked for the GNU C Library by Roland McGrath. + * Rewritten to use reentrant functions by Ulrich Drepper, 1995. + */ + +/* + Copyright (C) 1983 Regents of the University of California. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE.*/ + +#include <limits.h> +#include <stdlib.h> +#include "generate-random.h" + + +/* An improved random number generation package. In addition to the standard + rand()/srand() like interface, this package also has a special state info + interface. The initstate() routine is called with a seed, an array of + bytes, and a count of how many bytes are being passed in; this array is + then initialized to contain information for random number generation with + that much state information. Good sizes for the amount of state + information are 32, 64, 128, and 256 bytes. The state can be switched by + calling the setstate() function with the same array as was initialized + with initstate(). By default, the package runs with 128 bytes of state + information and generates far better random numbers than a linear + congruential generator. If the amount of state information is less than + 32 bytes, a simple linear congruential R.N.G. is used. Internally, the + state information is treated as an array of longs; the zeroth element of + the array is the type of R.N.G. being used (small integer); the remainder + of the array is the state information for the R.N.G. Thus, 32 bytes of + state information will give 7 longs worth of state information, which will + allow a degree seven polynomial. (Note: The zeroth word of state + information also has some other information stored in it; see setstate + for details). The random number generation technique is a linear feedback + shift register approach, employing trinomials (since there are fewer terms + to sum up that way). In this approach, the least significant bit of all + the numbers in the state table will act as a linear feedback shift register, + and will have period 2^deg - 1 (where deg is the degree of the polynomial + being used, assuming that the polynomial is irreducible and primitive). + The higher order bits will have longer periods, since their values are + also influenced by pseudo-random carries out of the lower bits. The + total period of the generator is approximately deg*(2**deg - 1); thus + doubling the amount of state information has a vast influence on the + period of the generator. Note: The deg*(2**deg - 1) is an approximation + only good for large deg, when the period of the shift register is the + dominant factor. With deg equal to seven, the period is actually much + longer than the 7*(2**7 - 1) predicted by this formula. */ + + + +/* For each of the currently supported random number generators, we have a + break value on the amount of state information (you need at least this many + bytes of state info to support this random number generator), a degree for + the polynomial (actually a trinomial) that the R.N.G. is based on, and + separation between the two lower order coefficients of the trinomial. */ + +/* Linear congruential. */ +#define TYPE_0 0 +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +/* x**7 + x**3 + 1. */ +#define TYPE_1 1 +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +/* x**15 + x + 1. */ +#define TYPE_2 2 +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +/* x**31 + x**3 + 1. */ +#define TYPE_3 3 +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +/* x**63 + x + 1. */ +#define TYPE_4 4 +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + + +/* Array versions of the above information to make code run faster. + Relies on fact that TYPE_i == i. */ + +#define MAX_TYPES 5 /* Max number of types above. */ + + +/* Initially, everything is set up as if from: + initstate(1, randtbl, 128); + Note that this initialization takes advantage of the fact that srandom + advances the front and rear pointers 10*rand_deg times, and hence the + rear pointer which starts at 0 will also end up at zero; thus the zeroth + element of the state information, which contains info about the current + position of the rear pointer is just + (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ + +static int randtbl[DEG_3 + 1] = + { + TYPE_3, + + -1726662223, 379960547, 1735697613, 1040273694, 1313901226, + 1627687941, -179304937, -2073333483, 1780058412, -1989503057, + -615974602, 344556628, 939512070, -1249116260, 1507946756, + -812545463, 154635395, 1388815473, -1926676823, 525320961, + -1009028674, 968117788, -123449607, 1284210865, 435012392, + -2017506339, -911064859, -370259173, 1132637927, 1398500161, + -205601318, + }; + + +static struct generate_random_data unsafe_state = + { +/* FPTR and RPTR are two pointers into the state info, a front and a rear + pointer. These two pointers are always rand_sep places aparts, as they + cycle through the state information. (Yes, this does mean we could get + away with just one pointer, but the code for random is more efficient + this way). The pointers are left positioned as they would be from the call: + initstate(1, randtbl, 128); + (The position of the rear pointer, rptr, is really 0 (as explained above + in the initialization of randtbl) because the state table pointer is set + to point to randtbl[1] (as explained below).) */ + + &randtbl[SEP_3 + 1], /* fptr */ + &randtbl[1], /* rptr */ + +/* The following things are the pointer to the state information table, + the type of the current generator, the degree of the current polynomial + being used, and the separation between the two pointers. + Note that for efficiency of random, we remember the first location of + the state information, not the zeroth. Hence it is valid to access + state[-1], which is used to store the type of the R.N.G. + Also, we remember the last location, since this is more efficient than + indexing every time to find the address of the last element to see if + the front and rear pointers have wrapped. */ + + &randtbl[1], /* state */ + + TYPE_3, /* rand_type */ + DEG_3, /* rand_deg */ + SEP_3, /* rand_sep */ + + &randtbl[sizeof (randtbl) / sizeof (randtbl[0])] /* end_ptr */ +}; + +/* Initialize the random number generator based on the given seed. If the + type is the trivial no-state-information type, just remember the seed. + Otherwise, initializes state[] based on the given "seed" via a linear + congruential generator. Then, the pointers are set to known locations + that are exactly rand_sep places apart. Lastly, it cycles the state + information a given number of times to get rid of any initial dependencies + introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + for default usage relies on values produced by this routine. */ +void +generate_srandom (unsigned int x) +{ + (void) generate_srandom_r (x, &unsafe_state); +} + +/* Initialize the state information in the given array of N bytes for + future random number generation. Based on the number of bytes we + are given, and the break values for the different R.N.G.'s, we choose + the best (largest) one we can and set things up for it. srandom is + then called to initialize the state information. Note that on return + from srandom, we set state[-1] to be the type multiplexed with the current + value of the rear pointer; this is so successive calls to initstate won't + lose this information and will be able to restart with setstate. + Note: The first thing we do is save the current state, if any, just like + setstate so that it doesn't matter when initstate is called. + Returns a pointer to the old state. */ +char * +generate_initstate (unsigned int seed, char *arg_state, size_t n) +{ + int *ostate; + + ostate = &unsafe_state.state[-1]; + generate_initstate_r (seed, arg_state, n, &unsafe_state); + return (char *) ostate; +} + +/* Restore the state from the given state array. + Note: It is important that we also remember the locations of the pointers + in the current state information, and restore the locations of the pointers + from the old state information. This is done by multiplexing the pointer + location into the zeroth word of the state information. Note that due + to the order in which things are done, it is OK to call setstate with the + same state as the current state + Returns a pointer to the old state information. */ +char * +generate_setstate (char *arg_state) +{ + int *ostate; + + ostate = &unsafe_state.state[-1]; + if (generate_setstate_r (arg_state, &unsafe_state) < 0) + ostate = NULL; + return (char *) ostate; +} + +/* If we are using the trivial TYPE_0 R.N.G., just do the old linear + congruential bit. Otherwise, we do our fancy trinomial stuff, which is the + same in all the other cases due to all the global variables that have been + set up. The basic operation is to add the number at the rear pointer into + the one at the front pointer. Then both pointers are advanced to the next + location cyclically in the table. The value returned is the sum generated, + reduced to 31 bits by throwing away the "least random" low bit. + Note: The code takes advantage of the fact that both the front and + rear pointers can't wrap on the same call by not testing the rear + pointer if the front one has wrapped. Returns a 31-bit random number. */ + +long int +generate_random (void) +{ + int retval; + (void) generate_random_r (&unsafe_state, &retval); + return retval; +} diff --git a/gcc/testsuite/objc.dg/gnu-encoding/generate-random.h b/gcc/testsuite/objc.dg/gnu-encoding/generate-random.h new file mode 100644 index 000000000..e14f526bb --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-encoding/generate-random.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2004 Free Software Foundation + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. */ + +struct generate_random_data + { + int *fptr, *rptr, *state; + int rand_type, rand_deg, rand_sep; + int *end_ptr; + }; + +extern void generate_srandom (unsigned int); +extern char *generate_initstate (unsigned int, char *, size_t); +extern char *generate_setstate (char *); +extern long int generate_random (void); +extern int generate_random_r (struct generate_random_data *, int *); +extern int generate_srandom_r (unsigned int, struct generate_random_data *); +extern int generate_initstate_r (unsigned int, char *, size_t, + struct generate_random_data *); +extern int generate_setstate_r (char *, struct generate_random_data *); diff --git a/gcc/testsuite/objc.dg/gnu-encoding/generate-random_r.c b/gcc/testsuite/objc.dg/gnu-encoding/generate-random_r.c new file mode 100644 index 000000000..6e83f3596 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-encoding/generate-random_r.c @@ -0,0 +1,385 @@ +/* + Copyright (C) 1995, 2004 Free Software Foundation + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. */ + +/* + Copyright (C) 1983 Regents of the University of California. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE.*/ + +/* + * This is derived from the Berkeley source: + * @(#)random.c 5.5 (Berkeley) 7/6/88 + * It was reworked for the GNU C Library by Roland McGrath. + * Rewritten to be reentrant by Ulrich Drepper, 1995 + */ + +#include <limits.h> +#include <stdlib.h> +#include "generate-random.h" + + +/* An improved random number generation package. In addition to the standard + rand()/srand() like interface, this package also has a special state info + interface. The initstate() routine is called with a seed, an array of + bytes, and a count of how many bytes are being passed in; this array is + then initialized to contain information for random number generation with + that much state information. Good sizes for the amount of state + information are 32, 64, 128, and 256 bytes. The state can be switched by + calling the setstate() function with the same array as was initialized + with initstate(). By default, the package runs with 128 bytes of state + information and generates far better random numbers than a linear + congruential generator. If the amount of state information is less than + 32 bytes, a simple linear congruential R.N.G. is used. Internally, the + state information is treated as an array of longs; the zeroth element of + the array is the type of R.N.G. being used (small integer); the remainder + of the array is the state information for the R.N.G. Thus, 32 bytes of + state information will give 7 longs worth of state information, which will + allow a degree seven polynomial. (Note: The zeroth word of state + information also has some other information stored in it; see setstate + for details). The random number generation technique is a linear feedback + shift register approach, employing trinomials (since there are fewer terms + to sum up that way). In this approach, the least significant bit of all + the numbers in the state table will act as a linear feedback shift register, + and will have period 2^deg - 1 (where deg is the degree of the polynomial + being used, assuming that the polynomial is irreducible and primitive). + The higher order bits will have longer periods, since their values are + also influenced by pseudo-random carries out of the lower bits. The + total period of the generator is approximately deg*(2**deg - 1); thus + doubling the amount of state information has a vast influence on the + period of the generator. Note: The deg*(2**deg - 1) is an approximation + only good for large deg, when the period of the shift register is the + dominant factor. With deg equal to seven, the period is actually much + longer than the 7*(2**7 - 1) predicted by this formula. */ + + + +/* For each of the currently supported random number generators, we have a + break value on the amount of state information (you need at least this many + bytes of state info to support this random number generator), a degree for + the polynomial (actually a trinomial) that the R.N.G. is based on, and + separation between the two lower order coefficients of the trinomial. */ + +/* Linear congruential. */ +#define TYPE_0 0 +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +/* x**7 + x**3 + 1. */ +#define TYPE_1 1 +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +/* x**15 + x + 1. */ +#define TYPE_2 2 +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +/* x**31 + x**3 + 1. */ +#define TYPE_3 3 +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +/* x**63 + x + 1. */ +#define TYPE_4 4 +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + + +/* Array versions of the above information to make code run faster. + Relies on fact that TYPE_i == i. */ + +#define MAX_TYPES 5 /* Max number of types above. */ + +struct random_poly_info +{ + int seps[MAX_TYPES]; + int degrees[MAX_TYPES]; +}; + +static const struct random_poly_info random_poly_info = +{ + { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }, + { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 } +}; + + + + +/* Initialize the random number generator based on the given seed. If the + type is the trivial no-state-information type, just remember the seed. + Otherwise, initializes state[] based on the given "seed" via a linear + congruential generator. Then, the pointers are set to known locations + that are exactly rand_sep places apart. Lastly, it cycles the state + information a given number of times to get rid of any initial dependencies + introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + for default usage relies on values produced by this routine. */ +int +generate_srandom_r (unsigned int seed, struct generate_random_data *buf) +{ + int type; + int *state; + long int i; + long int word; + int *dst; + int kc; + + if (buf == NULL) + goto fail; + type = buf->rand_type; + if ((unsigned int) type >= MAX_TYPES) + goto fail; + + state = buf->state; + /* We must make sure the seed is not 0. Take arbitrarily 1 in this case. */ + if (seed == 0) + seed = 1; + state[0] = seed; + if (type == TYPE_0) + goto done; + + dst = state; + word = seed; + kc = buf->rand_deg; + for (i = 1; i < kc; ++i) + { + /* This does: + state[i] = (16807 * state[i - 1]) % 2147483647; + but avoids overflowing 31 bits. */ + long int hi = word / 127773; + long int lo = word % 127773; + word = 16807 * lo - 2836 * hi; + if (word < 0) + word += 2147483647; + *++dst = word; + } + + buf->fptr = &state[buf->rand_sep]; + buf->rptr = &state[0]; + kc *= 10; + while (--kc >= 0) + { + int discard; + (void) generate_random_r (buf, &discard); + } + + done: + return 0; + + fail: + return -1; +} + +/* Initialize the state information in the given array of N bytes for + future random number generation. Based on the number of bytes we + are given, and the break values for the different R.N.G.'s, we choose + the best (largest) one we can and set things up for it. srandom is + then called to initialize the state information. Note that on return + from srandom, we set state[-1] to be the type multiplexed with the current + value of the rear pointer; this is so successive calls to initstate won't + lose this information and will be able to restart with setstate. + Note: The first thing we do is save the current state, if any, just like + setstate so that it doesn't matter when initstate is called. + Returns a pointer to the old state. */ +int +generate_initstate_r (unsigned int seed, char *arg_state, size_t n, + struct generate_random_data *buf) +{ + int type; + int degree; + int separation; + int *state; + + if (buf == NULL) + goto fail; + + if (n >= BREAK_3) + type = n < BREAK_4 ? TYPE_3 : TYPE_4; + else if (n < BREAK_1) + { + if (n < BREAK_0) + { + goto fail; + } + type = TYPE_0; + } + else + type = n < BREAK_2 ? TYPE_1 : TYPE_2; + + degree = random_poly_info.degrees[type]; + separation = random_poly_info.seps[type]; + + buf->rand_type = type; + buf->rand_sep = separation; + buf->rand_deg = degree; + state = &((int *) arg_state)[1]; /* First location. */ + /* Must set END_PTR before srandom. */ + buf->end_ptr = &state[degree]; + + buf->state = state; + + generate_srandom_r (seed, buf); + + state[-1] = TYPE_0; + if (type != TYPE_0) + state[-1] = (buf->rptr - state) * MAX_TYPES + type; + + return 0; + + fail: + return -1; +} + +/* Restore the state from the given state array. + Note: It is important that we also remember the locations of the pointers + in the current state information, and restore the locations of the pointers + from the old state information. This is done by multiplexing the pointer + location into the zeroth word of the state information. Note that due + to the order in which things are done, it is OK to call setstate with the + same state as the current state + Returns a pointer to the old state information. */ +int +generate_setstate_r (char *arg_state, struct generate_random_data *buf) +{ + int *new_state = 1 + (int *) arg_state; + int type; + int old_type; + int *old_state; + int degree; + int separation; + + if (arg_state == NULL || buf == NULL) + goto fail; + + old_type = buf->rand_type; + old_state = buf->state; + if (old_type == TYPE_0) + old_state[-1] = TYPE_0; + else + old_state[-1] = (MAX_TYPES * (buf->rptr - old_state)) + old_type; + + type = new_state[-1] % MAX_TYPES; + if (type < TYPE_0 || type > TYPE_4) + goto fail; + + buf->rand_deg = degree = random_poly_info.degrees[type]; + buf->rand_sep = separation = random_poly_info.seps[type]; + buf->rand_type = type; + + if (type != TYPE_0) + { + int rear = new_state[-1] / MAX_TYPES; + buf->rptr = &new_state[rear]; + buf->fptr = &new_state[(rear + separation) % degree]; + } + buf->state = new_state; + /* Set end_ptr too. */ + buf->end_ptr = &new_state[degree]; + + return 0; + + fail: + return -1; +} + +/* If we are using the trivial TYPE_0 R.N.G., just do the old linear + congruential bit. Otherwise, we do our fancy trinomial stuff, which is the + same in all the other cases due to all the global variables that have been + set up. The basic operation is to add the number at the rear pointer into + the one at the front pointer. Then both pointers are advanced to the next + location cyclically in the table. The value returned is the sum generated, + reduced to 31 bits by throwing away the "least random" low bit. + Note: The code takes advantage of the fact that both the front and + rear pointers can't wrap on the same call by not testing the rear + pointer if the front one has wrapped. Returns a 31-bit random number. */ + +int +generate_random_r (struct generate_random_data *buf, int *result) +{ + int *state; + + if (buf == NULL || result == NULL) + goto fail; + + state = buf->state; + + if (buf->rand_type == TYPE_0) + { + int val = state[0]; + val = ((state[0] * 1103515245) + 12345) & 0x7fffffff; + state[0] = val; + *result = val; + } + else + { + int *fptr = buf->fptr; + int *rptr = buf->rptr; + int *end_ptr = buf->end_ptr; + int val; + + val = *fptr += *rptr; + /* Chucking least random bit. */ + *result = (val >> 1) & 0x7fffffff; + ++fptr; + if (fptr >= end_ptr) + { + fptr = state; + ++rptr; + } + else + { + ++rptr; + if (rptr >= end_ptr) + rptr = state; + } + buf->fptr = fptr; + buf->rptr = rptr; + } + return 0; + + fail: + return -1; +} diff --git a/gcc/testsuite/objc.dg/gnu-encoding/gnu-encoding.exp b/gcc/testsuite/objc.dg/gnu-encoding/gnu-encoding.exp new file mode 100644 index 000000000..b137b751a --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-encoding/gnu-encoding.exp @@ -0,0 +1,77 @@ +# GCC Objective-C testsuite that uses the `dg.exp' driver. +# Copyright (C) 1997, 2001, 2007, 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Load support procs. +load_lib objc-dg.exp +load_lib target-libpath.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS "-fgnu-runtime" +} + +# Initialize `dg'. +dg-init + +# +# gnu-encoding tests +# +set tstobjdir "$tmpdir/objc.dg-struct-layout-encoding-1" +set generator "$tmpdir/objc.dg-struct-layout-encoding-1_generate" + +set generator_src "$srcdir/$subdir/struct-layout-encoding-1_generate.c" +set generator_src "$generator_src $srcdir/$subdir/generate-random.c" +set generator_src "$generator_src $srcdir/$subdir/generate-random_r.c" +set generator_cmd "-o $generator $generator_src" +# Temporarily switch to the environment of the host compiler. +restore_ld_library_path_env_vars +set status [remote_exec build "$HOSTCC $HOSTCFLAGS $generator_cmd"] +set status [lindex $status 0] +set_ld_library_path_env_vars +if { $status == 0 } then { + file delete -force $tstobjdir + file mkdir $tstobjdir + set generator_args "-s $srcdir/$subdir -d $tstobjdir" +# set generator_args "$generator_args -n 15000" + set status [remote_exec host "$generator $generator_args"] + set status [lindex $status 0] + if { $status == 0 } then { + foreach src [lsort [find $tstobjdir *_main.m]] { + # If we're only testing specific files and this isn't one + # of them, skip it. + if ![runtest_file_p $runtests $src] then { + continue + } + + dg-runtest $src "" $DEFAULT_CFLAGS + } + } else { + warning "Could not execute objc.dg/gnu-encoding/struct-layout-encoding-1 generator" + } +} else { + warning "Could not compile objc.dg/gnu-encoding/struct-layout-encoding-1 generator" +} + + + + + + +# All done. +dg-finish + diff --git a/gcc/testsuite/objc.dg/gnu-encoding/struct-layout-1.h b/gcc/testsuite/objc.dg/gnu-encoding/struct-layout-1.h new file mode 100644 index 000000000..e165e203a --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-encoding/struct-layout-1.h @@ -0,0 +1,704 @@ +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "compat-common.h" + +#ifndef SKIP_ATTRIBUTE +# include "vector-defs.h" +#else +typedef int qi; +typedef int hi; +typedef int si; +typedef int di; +typedef float sf; +typedef float df; +typedef int v8qi; +typedef int v16qi; +typedef int v2hi; +typedef int v4hi; +typedef int v8hi; +typedef int v2si; +typedef int v4si; +typedef int v1di; +typedef int v2di; +typedef int v2sf; +typedef int v4sf; +typedef int v16sf; +typedef int v2df; +typedef int u8qi; +typedef int u16qi; +typedef int u2hi; +typedef int u4hi; +typedef int u8hi; +typedef int u2si; +typedef int u4si; +typedef int u1di; +typedef int u2di; +typedef int u2sf; +typedef int u4sf; +typedef int u16sf; +typedef int u2df; +#endif +#if (defined __i386__ || defined __x86_64__) && !defined SKIP_ATTRIBUTE +# ifdef __MMX__ +# include <mmintrin.h> +# else +typedef int __m64; +# endif +# ifdef __SSE__ +# include <xmmintrin.h> +# else +typedef int __m128; +# endif +#else +typedef int __m64; +typedef int __m128; +#endif + +#define FLDS_MAX 32 +extern struct Info +{ + int nfields, nbitfields; + void *sp, *a0p, *a3p; + void *flds[FLDS_MAX]; + size_t sz, sizes[FLDS_MAX]; + size_t als, ala0, ala3, aligns[FLDS_MAX]; +} info; + +extern int intarray[256]; +extern int fn0 (void), fn1 (void), fn2 (void), fn3 (void), fn4 (void); +extern int fn5 (void), fn6 (void), fn7 (void), fn8 (void), fn9 (void); + +#ifdef DBG +#define FAIL(n, m) printf ("fail %d.%d\n", n, m), ++fails +#else +#define FAIL(n, m) ++fails +#endif + +#ifdef SKIP_ATTRIBUTE +# define __attribute__(x) +#endif +#define atal __attribute__((aligned)) +#define atpa __attribute__((packed)) +#define atalpa __attribute__((aligned, packed)) +#define atpaal __attribute__((packed, aligned)) +#define atal1 __attribute__((aligned (1))) +#define atal2 __attribute__((aligned (2))) +#define atal4 __attribute__((aligned (4))) +#define atal8 __attribute__((aligned (8))) +#define atal16 __attribute__((aligned (16))) +#define atal1pa __attribute__((aligned (1), packed)) +#define atal2pa __attribute__((aligned (2), packed)) +#define atal4pa __attribute__((aligned (4), packed)) +#define atal8pa __attribute__((aligned (8), packed)) +#define atal16pa __attribute__((aligned (16), packed)) +#define atpaal1 __attribute__((packed, aligned (1))) +#define atpaal2 __attribute__((packed, aligned (2))) +#define atpaal4 __attribute__((packed, aligned (4))) +#define atpaal8 __attribute__((packed, aligned (8))) +#define atpaal16 __attribute__((packed, aligned (16))) + +#if UCHAR_MAX == 255 && USHORT_MAX == 65535 && UINT_MAX == 4294967295U \ + && ULLONG_MAX == 18446744073709551615ULL +/* For ILP32 and LP64 targets, assume float is at least 32-bit + and double plus long double at least 64-bit. */ +# define atalx1 atal1 +# define atalx2 atal2 +# define atalx4 atal4 +# define atalx8 atal8 +# define atalx16 atal16 +# define atalx1pa atal1pa +# define atalx2pa atal2pa +# define atalx4pa atal4pa +# define atalx8pa atal8pa +# define atalx16pa atal16pa +# define atpaalx1 atpaal1 +# define atpaalx2 atpaal2 +# define atpaalx4 atpaal4 +# define atpaalx8 atpaal8 +# define atpaalx16 atpaal16 +# if ULONG_MAX > 4294967295UL +# define ataly8 atal8 +# define ataly8pa atal8pa +# define atpaaly8 atpaal8 +# define ataly16 atal16 +# define ataly16pa atal16pa +# define atpaaly16 atpaal16 +# else +# define ataly8 +# define ataly8pa +# define atpaaly8 +# define ataly16 +# define ataly16pa +# define atpaaly16 +# endif +#else +# define atalx1 +# define atalx2 +# define atalx4 +# define atalx8 +# define atalx16 +# define atalx1pa +# define atalx2pa +# define atalx4pa +# define atalx8pa +# define atalx16pa +# define atpaalx1 +# define atpaalx2 +# define atpaalx4 +# define atpaalx8 +# define atpaalx16 +# define ataly8 +# define ataly8pa +# define atpaaly8 +# define ataly16 +# define ataly16pa +# define atpaaly16 +#endif + +#define atQI __attribute__((mode (QI))) +#define atHI __attribute__((mode (HI))) +#define atSI __attribute__((mode (SI))) +#define atDI __attribute__((mode (DI))) + +enum E0 { e0_0 }; +enum E1 { e1_0, e1_1 }; +enum E2 { e2_m3 = -3, e2_m2, e2_m1, e2_0, e2_1, e2_2, e2_3 }; +enum E3 { e3_m127 = -127, e3_m126, e3_m125, e3_0 = 0, e3_125 = 125, e3_126, e3_127 }; +enum E4 { e4_0, e4_1, e4_2, e4_3, e4_253 = 253, e4_254, e4_255 }; +enum E5 { e5_m32767 = -32767, e5_m32766, e5_m32765, e5_0 = 0, e5_32765 = 32765, e5_32766, e5_32767 }; +enum E6 { e6_0, e6_1, e6_2, e6_3, e6_65533 = 65533, e6_65534, e6_65535 }; +enum E7 { e7_m2147483647 = -2147483647, e7_m2147483646, e7_m2147483645, + e7_0, e7_2147483645 = 2147483645, e7_2147483646, e7_2147483647 }; +enum E8 { e8_0, e8_1, e8_2, e8_3, e8_4294967293 = 4294967293U, e8_4294967294, e8_4294967295 }; +enum E9 { e9_m1099511627775 = -1099511627775LL, e9_m1099511627774, e9_m1099511627773, + e9_0, e9_1099511627773 = 1099511627773LL, e9_1099511627774, e9_1099511627775 }; + +typedef char Tchar; +typedef signed char Tschar; +typedef unsigned char Tuchar; +typedef short int Tshort; +typedef unsigned short int Tushort; +typedef int Tint; +typedef unsigned int Tuint; +typedef long int Tlong; +typedef unsigned long int Tulong; +typedef long long int Tllong; +typedef unsigned long long int Tullong; +#ifndef SKIP_COMPLEX_INT +typedef _Complex char Tcchar; +typedef _Complex signed char Tcschar; +typedef _Complex unsigned char Tcuchar; +typedef _Complex short int Tcshort; +typedef _Complex unsigned short int Tcushort; +typedef _Complex int Tcint; +typedef _Complex unsigned int Tcuint; +typedef _Complex long int Tclong; +typedef _Complex unsigned long int Tculong; +typedef _Complex long long int Tcllong; +typedef _Complex unsigned long long int Tcullong; +#endif +typedef float Tfloat; +typedef double Tdouble; +typedef long double Tldouble; +typedef _Complex float Tcfloat; +typedef _Complex double Tcdouble; +typedef _Complex long double Tcldouble; +typedef bool Tbool; +typedef enum E0 TE0; +typedef enum E1 TE1; +typedef enum E2 TE2; +typedef enum E3 TE3; +typedef enum E4 TE4; +typedef enum E5 TE5; +typedef enum E6 TE6; +typedef enum E7 TE7; +typedef enum E8 TE8; +typedef enum E9 TE9; +typedef void *Tptr; +typedef char *Tcptr; +typedef int *Tiptr; +typedef char Talchar atal; +typedef signed char Talschar atal; +typedef unsigned char Taluchar atal; +typedef short int Talshort atal; +typedef unsigned short int Talushort atal; +typedef int Talint atal; +typedef unsigned int Taluint atal; +typedef long int Tallong atal; +typedef unsigned long int Talulong atal; +typedef long long int Talllong atal; +typedef unsigned long long int Talullong atal; +#ifndef SKIP_COMPLEX_INT +typedef _Complex char Talcchar atal; +typedef _Complex signed char Talcschar atal; +typedef _Complex unsigned char Talcuchar atal; +typedef _Complex short int Talcshort atal; +typedef _Complex unsigned short int Talcushort atal; +typedef _Complex int Talcint atal; +typedef _Complex unsigned int Talcuint atal; +typedef _Complex long int Talclong atal; +typedef _Complex unsigned long int Talculong atal; +typedef _Complex long long int Talcllong atal; +typedef _Complex unsigned long long int Talcullong atal; +#endif +typedef float Talfloat atal; +typedef double Taldouble atal; +typedef long double Talldouble atal; +typedef _Complex float Talcfloat atal; +typedef _Complex double Talcdouble atal; +typedef _Complex long double Talcldouble atal; +typedef bool Talbool atal; +typedef enum E0 TalE0 atal; +typedef enum E1 TalE1 atal; +typedef enum E2 TalE2 atal; +typedef enum E3 TalE3 atal; +typedef enum E4 TalE4 atal; +typedef enum E5 TalE5 atal; +typedef enum E6 TalE6 atal; +typedef enum E7 TalE7 atal; +typedef enum E8 TalE8 atal; +typedef enum E9 TalE9 atal; +typedef void *Talptr atal; +typedef char *Talcptr atal; +typedef int *Taliptr atal; +typedef char Tal1char atal1; +typedef signed char Tal1schar atal1; +typedef unsigned char Tal1uchar atal1; +typedef short int Tal1short atal1; +typedef unsigned short int Tal1ushort atal1; +typedef int Tal1int atal1; +typedef unsigned int Tal1uint atal1; +typedef long int Tal1long atal1; +typedef unsigned long int Tal1ulong atal1; +typedef long long int Tal1llong atal1; +typedef unsigned long long int Tal1ullong atal1; +#ifndef SKIP_COMPLEX_INT +typedef _Complex char Tal1cchar atal1; +typedef _Complex signed char Tal1cschar atal1; +typedef _Complex unsigned char Tal1cuchar atal1; +typedef _Complex short int Tal1cshort atal1; +typedef _Complex unsigned short int Tal1cushort atal1; +typedef _Complex int Tal1cint atal1; +typedef _Complex unsigned int Tal1cuint atal1; +typedef _Complex long int Tal1clong atal1; +typedef _Complex unsigned long int Tal1culong atal1; +typedef _Complex long long int Tal1cllong atal1; +typedef _Complex unsigned long long int Tal1cullong atal1; +#endif +typedef float Tal1float atal1; +typedef double Tal1double atal1; +typedef long double Tal1ldouble atal1; +typedef _Complex float Tal1cfloat atal1; +typedef _Complex double Tal1cdouble atal1; +typedef _Complex long double Tal1cldouble atal1; +typedef bool Tal1bool atal1; +typedef enum E0 Tal1E0 atal1; +typedef enum E1 Tal1E1 atal1; +typedef enum E2 Tal1E2 atal1; +typedef enum E3 Tal1E3 atal1; +typedef enum E4 Tal1E4 atal1; +typedef enum E5 Tal1E5 atal1; +typedef enum E6 Tal1E6 atal1; +typedef enum E7 Tal1E7 atal1; +typedef enum E8 Tal1E8 atal1; +typedef enum E9 Tal1E9 atal1; +typedef void *Tal1ptr atal1; +typedef char *Tal1cptr atal1; +typedef int *Tal1iptr atal1; +typedef char Tal2char atal2; +typedef signed char Tal2schar atal2; +typedef unsigned char Tal2uchar atal2; +typedef short int Tal2short atal2; +typedef unsigned short int Tal2ushort atal2; +typedef int Tal2int atal2; +typedef unsigned int Tal2uint atal2; +typedef long int Tal2long atal2; +typedef unsigned long int Tal2ulong atal2; +typedef long long int Tal2llong atal2; +typedef unsigned long long int Tal2ullong atal2; +#ifndef SKIP_COMPLEX_INT +typedef _Complex char Tal2cchar atal2; +typedef _Complex signed char Tal2cschar atal2; +typedef _Complex unsigned char Tal2cuchar atal2; +typedef _Complex short int Tal2cshort atal2; +typedef _Complex unsigned short int Tal2cushort atal2; +typedef _Complex int Tal2cint atal2; +typedef _Complex unsigned int Tal2cuint atal2; +typedef _Complex long int Tal2clong atal2; +typedef _Complex unsigned long int Tal2culong atal2; +typedef _Complex long long int Tal2cllong atal2; +typedef _Complex unsigned long long int Tal2cullong atal2; +#endif +typedef float Tal2float atal2; +typedef double Tal2double atal2; +typedef long double Tal2ldouble atal2; +typedef _Complex float Tal2cfloat atal2; +typedef _Complex double Tal2cdouble atal2; +typedef _Complex long double Tal2cldouble atal2; +typedef bool Tal2bool atal2; +typedef enum E0 Tal2E0 atal2; +typedef enum E1 Tal2E1 atal2; +typedef enum E2 Tal2E2 atal2; +typedef enum E3 Tal2E3 atal2; +typedef enum E4 Tal2E4 atal2; +typedef enum E5 Tal2E5 atal2; +typedef enum E6 Tal2E6 atal2; +typedef enum E7 Tal2E7 atal2; +typedef enum E8 Tal2E8 atal2; +typedef enum E9 Tal2E9 atal2; +typedef void *Tal2ptr atal2; +typedef char *Tal2cptr atal2; +typedef int *Tal2iptr atal2; +typedef char Tal4char atal4; +typedef signed char Tal4schar atal4; +typedef unsigned char Tal4uchar atal4; +typedef short int Tal4short atal4; +typedef unsigned short int Tal4ushort atal4; +typedef int Tal4int atal4; +typedef unsigned int Tal4uint atal4; +typedef long int Tal4long atal4; +typedef unsigned long int Tal4ulong atal4; +typedef long long int Tal4llong atal4; +typedef unsigned long long int Tal4ullong atal4; +#ifndef SKIP_COMPLEX_INT +typedef _Complex char Tal4cchar atal4; +typedef _Complex signed char Tal4cschar atal4; +typedef _Complex unsigned char Tal4cuchar atal4; +typedef _Complex short int Tal4cshort atal4; +typedef _Complex unsigned short int Tal4cushort atal4; +typedef _Complex int Tal4cint atal4; +typedef _Complex unsigned int Tal4cuint atal4; +typedef _Complex long int Tal4clong atal4; +typedef _Complex unsigned long int Tal4culong atal4; +typedef _Complex long long int Tal4cllong atal4; +typedef _Complex unsigned long long int Tal4cullong atal4; +#endif +typedef float Tal4float atal4; +typedef double Tal4double atal4; +typedef long double Tal4ldouble atal4; +typedef _Complex float Tal4cfloat atal4; +typedef _Complex double Tal4cdouble atal4; +typedef _Complex long double Tal4cldouble atal4; +typedef bool Tal4bool atal4; +typedef enum E0 Tal4E0 atal4; +typedef enum E1 Tal4E1 atal4; +typedef enum E2 Tal4E2 atal4; +typedef enum E3 Tal4E3 atal4; +typedef enum E4 Tal4E4 atal4; +typedef enum E5 Tal4E5 atal4; +typedef enum E6 Tal4E6 atal4; +typedef enum E7 Tal4E7 atal4; +typedef enum E8 Tal4E8 atal4; +typedef enum E9 Tal4E9 atal4; +typedef void *Tal4ptr atal4; +typedef char *Tal4cptr atal4; +typedef int *Tal4iptr atal4; +typedef char Tal8char atal8; +typedef signed char Tal8schar atal8; +typedef unsigned char Tal8uchar atal8; +typedef short int Tal8short atal8; +typedef unsigned short int Tal8ushort atal8; +typedef int Tal8int atal8; +typedef unsigned int Tal8uint atal8; +typedef long int Tal8long atal8; +typedef unsigned long int Tal8ulong atal8; +typedef long long int Tal8llong atal8; +typedef unsigned long long int Tal8ullong atal8; +#ifndef SKIP_COMPLEX_INT +typedef _Complex char Tal8cchar atal8; +typedef _Complex signed char Tal8cschar atal8; +typedef _Complex unsigned char Tal8cuchar atal8; +typedef _Complex short int Tal8cshort atal8; +typedef _Complex unsigned short int Tal8cushort atal8; +typedef _Complex int Tal8cint atal8; +typedef _Complex unsigned int Tal8cuint atal8; +typedef _Complex long int Tal8clong atal8; +typedef _Complex unsigned long int Tal8culong atal8; +typedef _Complex long long int Tal8cllong atal8; +typedef _Complex unsigned long long int Tal8cullong atal8; +#endif +typedef float Tal8float atal8; +typedef double Tal8double atal8; +typedef long double Tal8ldouble atal8; +typedef _Complex float Tal8cfloat atal8; +typedef _Complex double Tal8cdouble atal8; +typedef _Complex long double Tal8cldouble atal8; +typedef bool Tal8bool atal8; +typedef enum E0 Tal8E0 atal8; +typedef enum E1 Tal8E1 atal8; +typedef enum E2 Tal8E2 atal8; +typedef enum E3 Tal8E3 atal8; +typedef enum E4 Tal8E4 atal8; +typedef enum E5 Tal8E5 atal8; +typedef enum E6 Tal8E6 atal8; +typedef enum E7 Tal8E7 atal8; +typedef enum E8 Tal8E8 atal8; +typedef enum E9 Tal8E9 atal8; +typedef void *Tal8ptr atal8; +typedef char *Tal8cptr atal8; +typedef int *Tal8iptr atal8; +typedef char Tal16char atal16; +typedef signed char Tal16schar atal16; +typedef unsigned char Tal16uchar atal16; +typedef short int Tal16short atal16; +typedef unsigned short int Tal16ushort atal16; +typedef int Tal16int atal16; +typedef unsigned int Tal16uint atal16; +typedef long int Tal16long atal16; +typedef unsigned long int Tal16ulong atal16; +typedef long long int Tal16llong atal16; +typedef unsigned long long int Tal16ullong atal16; +#ifndef SKIP_COMPLEX_INT +typedef _Complex char Tal16cchar atal16; +typedef _Complex signed char Tal16cschar atal16; +typedef _Complex unsigned char Tal16cuchar atal16; +typedef _Complex short int Tal16cshort atal16; +typedef _Complex unsigned short int Tal16cushort atal16; +typedef _Complex int Tal16cint atal16; +typedef _Complex unsigned int Tal16cuint atal16; +typedef _Complex long int Tal16clong atal16; +typedef _Complex unsigned long int Tal16culong atal16; +typedef _Complex long long int Tal16cllong atal16; +typedef _Complex unsigned long long int Tal16cullong atal16; +#endif +typedef float Tal16float atal16; +typedef double Tal16double atal16; +typedef long double Tal16ldouble atal16; +typedef _Complex float Tal16cfloat atal16; +typedef _Complex double Tal16cdouble atal16; +typedef _Complex long double Tal16cldouble atal16; +typedef bool Tal16bool atal16; +typedef enum E0 Tal16E0 atal16; +typedef enum E1 Tal16E1 atal16; +typedef enum E2 Tal16E2 atal16; +typedef enum E3 Tal16E3 atal16; +typedef enum E4 Tal16E4 atal16; +typedef enum E5 Tal16E5 atal16; +typedef enum E6 Tal16E6 atal16; +typedef enum E7 Tal16E7 atal16; +typedef enum E8 Tal16E8 atal16; +typedef enum E9 Tal16E9 atal16; +typedef void *Tal16ptr atal16; +typedef char *Tal16cptr atal16; +typedef int *Tal16iptr atal16; +typedef char Talx1char atalx1; +typedef signed char Talx1schar atalx1; +typedef unsigned char Talx1uchar atalx1; +typedef short int Talx1short atalx1; +typedef unsigned short int Talx1ushort atalx1; +typedef int Talx1int atalx1; +typedef unsigned int Talx1uint atalx1; +typedef long int Talx1long atalx1; +typedef unsigned long int Talx1ulong atalx1; +typedef long long int Talx1llong atalx1; +typedef unsigned long long int Talx1ullong atalx1; +#ifndef SKIP_COMPLEX_INT +typedef _Complex char Talx1cchar atalx1; +typedef _Complex signed char Talx1cschar atalx1; +typedef _Complex unsigned char Talx1cuchar atalx1; +typedef _Complex short int Talx1cshort atalx1; +typedef _Complex unsigned short int Talx1cushort atalx1; +typedef _Complex int Talx1cint atalx1; +typedef _Complex unsigned int Talx1cuint atalx1; +typedef _Complex long int Talx1clong atalx1; +typedef _Complex unsigned long int Talx1culong atalx1; +typedef _Complex long long int Talx1cllong atalx1; +typedef _Complex unsigned long long int Talx1cullong atalx1; +#endif +typedef float Talx1float atalx1; +typedef double Talx1double atalx1; +typedef long double Talx1ldouble atalx1; +typedef _Complex float Talx1cfloat atalx1; +typedef _Complex double Talx1cdouble atalx1; +typedef _Complex long double Talx1cldouble atalx1; +typedef bool Talx1bool atalx1; +typedef enum E0 Talx1E0 atalx1; +typedef enum E1 Talx1E1 atalx1; +typedef enum E2 Talx1E2 atalx1; +typedef enum E3 Talx1E3 atalx1; +typedef enum E4 Talx1E4 atalx1; +typedef enum E5 Talx1E5 atalx1; +typedef enum E6 Talx1E6 atalx1; +typedef enum E7 Talx1E7 atalx1; +typedef enum E8 Talx1E8 atalx1; +typedef enum E9 Talx1E9 atalx1; +typedef void *Talx1ptr atalx1; +typedef char *Talx1cptr atalx1; +typedef int *Talx1iptr atalx1; +typedef short int Talx2short atalx2; +typedef unsigned short int Talx2ushort atalx2; +typedef int Talx2int atalx2; +typedef unsigned int Talx2uint atalx2; +typedef long int Talx2long atalx2; +typedef unsigned long int Talx2ulong atalx2; +typedef long long int Talx2llong atalx2; +typedef unsigned long long int Talx2ullong atalx2; +#ifndef SKIP_COMPLEX_INT +typedef _Complex char Talx2cchar atalx2; +typedef _Complex signed char Talx2cschar atalx2; +typedef _Complex unsigned char Talx2cuchar atalx2; +typedef _Complex short int Talx2cshort atalx2; +typedef _Complex unsigned short int Talx2cushort atalx2; +typedef _Complex int Talx2cint atalx2; +typedef _Complex unsigned int Talx2cuint atalx2; +typedef _Complex long int Talx2clong atalx2; +typedef _Complex unsigned long int Talx2culong atalx2; +typedef _Complex long long int Talx2cllong atalx2; +typedef _Complex unsigned long long int Talx2cullong atalx2; +#endif +typedef float Talx2float atalx2; +typedef double Talx2double atalx2; +typedef long double Talx2ldouble atalx2; +typedef _Complex float Talx2cfloat atalx2; +typedef _Complex double Talx2cdouble atalx2; +typedef _Complex long double Talx2cldouble atalx2; +typedef enum E0 Talx2E0 atalx2; +typedef enum E1 Talx2E1 atalx2; +typedef enum E2 Talx2E2 atalx2; +typedef enum E3 Talx2E3 atalx2; +typedef enum E4 Talx2E4 atalx2; +typedef enum E5 Talx2E5 atalx2; +typedef enum E6 Talx2E6 atalx2; +typedef enum E7 Talx2E7 atalx2; +typedef enum E8 Talx2E8 atalx2; +typedef enum E9 Talx2E9 atalx2; +typedef void *Talx2ptr atalx2; +typedef char *Talx2cptr atalx2; +typedef int *Talx2iptr atalx2; +typedef int Talx4int atalx4; +typedef unsigned int Talx4uint atalx4; +typedef long int Talx4long atalx4; +typedef unsigned long int Talx4ulong atalx4; +typedef long long int Talx4llong atalx4; +typedef unsigned long long int Talx4ullong atalx4; +#ifndef SKIP_COMPLEX_INT +typedef _Complex short int Talx4cshort atalx4; +typedef _Complex unsigned short int Talx4cushort atalx4; +typedef _Complex int Talx4cint atalx4; +typedef _Complex unsigned int Talx4cuint atalx4; +typedef _Complex long int Talx4clong atalx4; +typedef _Complex unsigned long int Talx4culong atalx4; +typedef _Complex long long int Talx4cllong atalx4; +typedef _Complex unsigned long long int Talx4cullong atalx4; +#endif +typedef float Talx4float atalx4; +typedef double Talx4double atalx4; +typedef long double Talx4ldouble atalx4; +typedef _Complex float Talx4cfloat atalx4; +typedef _Complex double Talx4cdouble atalx4; +typedef _Complex long double Talx4cldouble atalx4; +typedef enum E0 Talx4E0 atalx4; +typedef enum E1 Talx4E1 atalx4; +typedef enum E2 Talx4E2 atalx4; +typedef enum E3 Talx4E3 atalx4; +typedef enum E4 Talx4E4 atalx4; +typedef enum E5 Talx4E5 atalx4; +typedef enum E6 Talx4E6 atalx4; +typedef enum E7 Talx4E7 atalx4; +typedef enum E8 Talx4E8 atalx4; +typedef enum E9 Talx4E9 atalx4; +typedef void *Talx4ptr atalx4; +typedef char *Talx4cptr atalx4; +typedef int *Talx4iptr atalx4; +typedef long int Taly8long ataly8; +typedef unsigned long int Taly8ulong ataly8; +typedef long long int Talx8llong atalx8; +typedef unsigned long long int Talx8ullong atalx8; +#ifndef SKIP_COMPLEX_INT +typedef _Complex int Talx8cint atalx8; +typedef _Complex unsigned int Talx8cuint atalx8; +typedef _Complex long int Talx8clong atalx8; +typedef _Complex unsigned long int Talx8culong atalx8; +typedef _Complex long long int Talx8cllong atalx8; +typedef _Complex unsigned long long int Talx8cullong atalx8; +#endif +typedef double Talx8double atalx8; +typedef long double Talx8ldouble atalx8; +typedef _Complex float Talx8cfloat atalx8; +typedef _Complex double Talx8cdouble atalx8; +typedef _Complex long double Talx8cldouble atalx8; +typedef void *Taly8ptr ataly8; +typedef char *Taly8cptr ataly8; +typedef int *Taly8iptr ataly8; +#ifndef SKIP_COMPLEX_INT +typedef _Complex long int Taly16clong ataly16; +typedef _Complex unsigned long int Taly16culong ataly16; +typedef _Complex long long int Talx16cllong atalx16; +typedef _Complex unsigned long long int Talx16cullong atalx16; +#endif +typedef _Complex double Talx16cdouble atalx16; +typedef _Complex long double Talx16cldouble atalx16; +typedef int (*Tfnptr) (void); + +/* Bitfield macros. In C, it is invalid to use numbers larger + than type's bitsize, but we don't know the size when generating + the testcases. */ +#define BN8(n) ((((n) - 1) & 7) + 1) +#define BN16(n) ((((n) - 1) & 15) + 1) +#define BN32(n) ((((n) - 1) & 31) + 1) +#define BN64(n) ((((n) - 1) & 63) + 1) +#define BCN(n) BN8 (n) +#if USHRT_MAX == 255 +# define BSN(n) BN8 (n) +#elif USHRT_MAX == 65535 +# define BSN(n) BN16 (n) +#elif USHRT_MAX == 4294967295U +# define BSN(n) BN32 (n) +#elif USHRT_MAX == 18446744073709551615ULL +# define BSN(n) BN64 (n) +#endif +#if UINT_MAX == 255 +# define BIN(n) BN8 (n) +#elif UINT_MAX == 65535 +# define BIN(n) BN16 (n) +#elif UINT_MAX == 4294967295U +# define BIN(n) BN32 (n) +#elif UINT_MAX == 18446744073709551615ULL +# define BIN(n) BN64 (n) +#endif +#if ULONG_MAX == 255 +# define BLN(n) BN8 (n) +#elif ULONG_MAX == 65535 +# define BLN(n) BN16 (n) +#elif ULONG_MAX == 4294967295U +# define BLN(n) BN32 (n) +#elif ULONG_MAX == 18446744073709551615ULL +# define BLN(n) BN64 (n) +#endif +#if ULONG_MAX == 255 +# define BLN(n) BN8 (n) +#elif ULONG_MAX == 65535 +# define BLN(n) BN16 (n) +#elif ULONG_MAX == 4294967295U +# define BLN(n) BN32 (n) +#elif ULONG_MAX == 18446744073709551615ULL +# define BLN(n) BN64 (n) +#endif +#if !defined ULLONG_MAX && defined __LONG_LONG_MAX__ +# define ULLONG_MAX (__LONG_LONG_MAX__ * 2ULL + 1ULL) +#endif +#if ULLONG_MAX == 255 +# define BQN(n) BN8 (n) +#elif ULLONG_MAX == 65535 +# define BQN(n) BN16 (n) +#elif ULLONG_MAX == 4294967295U +# define BQN(n) BN32 (n) +#elif ULLONG_MAX == 18446744073709551615ULL +# define BQN(n) BN64 (n) +#endif + +#define T(n, fields, ops) TX(n, struct, , fields, ({ ops });) +#define U(n, fields, ops) TX(n, union, , fields, ({ ops });) +#ifdef SKIP_COMPLEX_INT +#define TXCI(n, type, attrs, fields, ops) +#define TCI(n, fields, ops) +#define UCI(n, fields, ops) +#else +#define TXCI(n, type, attrs, fields, ops) TX(n, type, attrs, fields, ({ ops });) +#define TCI(n, fields, ops) TX(n, struct, , fields, ({ ops });) +#define UCI(n, fields, ops) TX(n, union, , fields, ({ ops });) +#endif diff --git a/gcc/testsuite/objc.dg/gnu-encoding/struct-layout-1_test.h b/gcc/testsuite/objc.dg/gnu-encoding/struct-layout-1_test.h new file mode 100644 index 000000000..3463bb912 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-encoding/struct-layout-1_test.h @@ -0,0 +1,9 @@ +#include "struct-layout-1.h" + +#define TX(n, type, attrs, fields, ops) \ +type S##n { fields } attrs; \ +void test##n (void) \ +{ \ + if (objc_sizeof_type (@encoding (type S##n)) != sizeof(type S##n)) \ + fails ++; \ +} diff --git a/gcc/testsuite/objc.dg/gnu-encoding/struct-layout-encoding-1_generate.c b/gcc/testsuite/objc.dg/gnu-encoding/struct-layout-encoding-1_generate.c new file mode 100644 index 000000000..7494131c1 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-encoding/struct-layout-encoding-1_generate.c @@ -0,0 +1,1380 @@ +/* Structure layout test generator. + Copyright (C) 2004, 2005, 2007, 2010, 2011 Free Software Foundation, Inc. + Contributed by Jakub Jelinek <jakub@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/* Compile with gcc -o struct-layout-1_generate{,.c} generate_random{,_r}.c */ + +/* N.B. -- This program cannot use libiberty as that will not work + when testing an installed compiler. */ +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stddef.h> +/* We use our own pseudo-random number generator, so that it gives the same + values on all hosts. */ +#include "generate-random.h" + +#if LLONG_MAX != 9223372036854775807LL && __LONG_LONG_MAX__ != 9223372036854775807LL +# error Need 64-bit long long +#endif + +typedef unsigned int hashval_t; + +enum TYPE +{ + TYPE_INT, + TYPE_UINT, + TYPE_CINT, + TYPE_CUINT, + TYPE_FLOAT, + TYPE_CFLOAT, + TYPE_SENUM, + TYPE_UENUM, + TYPE_PTR, + TYPE_FNPTR, + TYPE_OTHER +}; + +struct types +{ + const char *name; + enum TYPE type; + unsigned long long int maxval; + char bitfld; +}; + +struct types base_types[] = { +/* As we don't know whether char will be signed or not, just limit ourselves + to unsigned values less than maximum signed char value. */ +{ "char", TYPE_UINT, 127, 'C' }, +{ "signed char", TYPE_INT, 127, 'C' }, +{ "unsigned char", TYPE_UINT, 255, 'C' }, +{ "short int", TYPE_INT, 32767, 'S' }, +{ "unsigned short int", TYPE_UINT, 65535, 'S' }, +{ "int", TYPE_INT, 2147483647, 'I' }, +{ "unsigned int", TYPE_UINT, 4294967295U, 'I' }, +{ "long int", TYPE_INT, 9223372036854775807LL, 'L' }, +{ "unsigned long int", TYPE_UINT, 18446744073709551615ULL, 'L' }, +{ "long long int", TYPE_INT, 9223372036854775807LL, 'Q' }, +{ "unsigned long long int", TYPE_UINT, 18446744073709551615ULL, 'Q' }, +{ "bool", TYPE_UINT, 1, 'B' }, +{ "void *", TYPE_PTR, 0, 0 }, +{ "char *", TYPE_PTR, 0, 0 }, +{ "int *", TYPE_PTR, 0, 0 }, +{ "float", TYPE_FLOAT, 0, 0 }, +{ "double", TYPE_FLOAT, 0, 0 }, +/*{ "long double", TYPE_FLOAT, 0, 0 },*/ +/* Disabled as double and long double + are encoded thee same, currently */ +#define NTYPES1 16 +#if 0 +/* enums are disabled for now as it seems like their encoding is broken, we should + just encode them using their underlaying type but we don't. */ +{ "enum E0", TYPE_UENUM, 0, ' ' }, +{ "enum E1", TYPE_UENUM, 1, ' ' }, +{ "enum E2", TYPE_SENUM, 3, ' ' }, +{ "enum E3", TYPE_SENUM, 127, ' ' }, +{ "enum E4", TYPE_UENUM, 255, ' ' }, +{ "enum E5", TYPE_SENUM, 32767, ' ' }, +{ "enum E6", TYPE_UENUM, 65535, ' ' }, +{ "enum E7", TYPE_SENUM, 2147483647, ' ' }, +{ "enum E8", TYPE_UENUM, 4294967295U, ' ' }, +{ "enum E9", TYPE_SENUM, 1099511627775LL, ' ' }, +#endif +#define NTYPES2 (sizeof (base_types) / sizeof (base_types[0])) +}; +struct types complex_types[] = { +{ "_Complex char", TYPE_CUINT, 127, 0 }, +{ "_Complex signed char", TYPE_CINT, 127, 0 }, +{ "_Complex unsigned char", TYPE_CUINT, 255, 0 }, +{ "_Complex short int", TYPE_CINT, 32767, 0 }, +{ "_Complex unsigned short int", TYPE_CUINT, 65535, 0 }, +{ "_Complex int", TYPE_CINT, 2147483647, 0 }, +{ "_Complex unsigned int", TYPE_CUINT, 4294967295U, 0 }, +{ "_Complex long int", TYPE_CINT, 9223372036854775807LL, 0 }, +{ "_Complex unsigned long int", TYPE_CUINT, 18446744073709551615ULL, 0 }, +{ "_Complex long long int", TYPE_CINT, 9223372036854775807LL, 0 }, +{ "_Complex unsigned long long int", TYPE_CUINT, 18446744073709551615ULL, 0 }, +{ "_Complex float", TYPE_CFLOAT, 0, 0 }, +{ "_Complex double", TYPE_CFLOAT, 0, 0 }, +/*{ "_Complex long double", TYPE_CFLOAT, 0, 0 }, */ +/* Disable until long doubles are encoded correctly. */ +#define NCTYPES2 (sizeof (complex_types) / sizeof (complex_types[0])) +}; +struct types vector_types[] = { +/* vector-defs.h typedefs */ +{ "v8qi", TYPE_OTHER, 0, 0 }, +{ "v16qi", TYPE_OTHER, 0, 0 }, +{ "v2hi", TYPE_OTHER, 0, 0 }, +{ "v4hi", TYPE_OTHER, 0, 0 }, +{ "v8hi", TYPE_OTHER, 0, 0 }, +{ "v2si", TYPE_OTHER, 0, 0 }, +{ "v4si", TYPE_OTHER, 0, 0 }, +{ "v1di", TYPE_OTHER, 0, 0 }, +{ "v2di", TYPE_OTHER, 0, 0 }, +{ "v2sf", TYPE_OTHER, 0, 0 }, +{ "v4sf", TYPE_OTHER, 0, 0 }, +{ "v16sf", TYPE_OTHER, 0, 0 }, +{ "v2df", TYPE_OTHER, 0, 0 }, +{ "u8qi", TYPE_OTHER, 0, 0 }, +{ "u16qi", TYPE_OTHER, 0, 0 }, +{ "u2hi", TYPE_OTHER, 0, 0 }, +{ "u4hi", TYPE_OTHER, 0, 0 }, +{ "u8hi", TYPE_OTHER, 0, 0 }, +{ "u2si", TYPE_OTHER, 0, 0 }, +{ "u4si", TYPE_OTHER, 0, 0 }, +{ "u1di", TYPE_OTHER, 0, 0 }, +{ "u2di", TYPE_OTHER, 0, 0 }, +{ "u2sf", TYPE_OTHER, 0, 0 }, +{ "u4sf", TYPE_OTHER, 0, 0 }, +{ "u16sf", TYPE_OTHER, 0, 0 }, +{ "u2df", TYPE_OTHER, 0, 0 }, +{ "__m64", TYPE_OTHER, 0, 0 }, +{ "__m128", TYPE_OTHER, 0, 0 } +#define NVTYPES2 (sizeof (vector_types) / sizeof (vector_types[0])) +}; + +struct types bitfld_types[NTYPES2]; +int n_bitfld_types; + +enum ETYPE +{ + ETYPE_TYPE, + ETYPE_ARRAY, + ETYPE_BITFLD, + ETYPE_STRUCT, + ETYPE_UNION, + ETYPE_STRUCT_ARRAY, + ETYPE_UNION_ARRAY +}; + +struct entry +{ +#ifdef __GNUC__ + enum ETYPE etype : 8; +#else + unsigned char etype; +#endif + unsigned short len; + unsigned char arr_len; + struct types *type; + const char *attrib; + /* Used to chain together entries in the hash table. */ + struct entry *next; +}; + +/* A prime number giving the number of slots in the hash table. */ +#define HASH_SIZE 32749 +static struct entry *hash_table[HASH_SIZE]; + +static int idx, limidx, output_one; +static const char *destdir; +static const char *srcdir; +FILE *outfile; + +void +switchfiles (int fields) +{ + static int filecnt; + static char *destbuf, *destptr; + ++filecnt; + if (outfile) + fclose (outfile); + if (output_one) + { + outfile = stdout; + return; + } + if (destbuf == NULL) + { + size_t len = strlen (destdir); + destbuf = malloc (len + 20); + if (!destbuf) + abort (); + memcpy (destbuf, destdir, len); + if (!len || destbuf[len - 1] != '/') + destbuf[len++] = '/'; + destptr = destbuf + len; + } + sprintf (destptr, "t%03d_main.m", filecnt); + outfile = fopen (destbuf, "w"); + if (outfile == NULL) + { + fail: + fputs ("failed to create test files\n", stderr); + exit (1); + } + /* FIXME: these tests should not be xfailed on aix but they are because + libobjc uses GCC's headers for trying to find the struct layout but it + gets it wrong. */ + if (filecnt == 2 + || filecnt == 3 + || filecnt == 4 + || filecnt == 6 + || filecnt == 7 + || filecnt == 8 + || filecnt == 11 + || filecnt == 12 + || filecnt == 15 + || filecnt == 22) + { + fprintf (outfile, "\ +/* { dg-do run { xfail { powerpc*-*-aix* } } } */\n\ +/* { dg-options \"-w -I%s -fgnu-runtime\" } */\n", srcdir); + } + /* FIXME: these should not be xfailed but they are because + of bugs in libobjc and the objc front-end. 25 is because + vectors are not encoded. The rest are because or zero sized + arrays are encoded as pointers. See PR objc/25361. */ + else if (filecnt == 25 || (filecnt >= 27 && filecnt <= 29)) + { + fprintf (outfile, "\ +/* { dg-do run { xfail { { i?86-*-* x86_64-*-* } || { powerpc*-apple-darwin* && ilp32 } } } } */\n\ +/* { dg-options \"-w -I%s -fgnu-runtime\" } */\n", srcdir); + } + else if (filecnt >= 30) + { + fprintf (outfile, "\ +/* { dg-do run { xfail { i?86-*-* x86_64-*-* } } } */\n\ +/* { dg-options \"-w -I%s -fgnu-runtime\" } */\n", srcdir); + } + else + { + fprintf (outfile, "\ +/* { dg-do run } */\n\ +/* { dg-options \"-w -I%s -fgnu-runtime\" } */\n", srcdir); + } + fprintf(outfile, "#include <objc/encoding.h> \n\ +#include \"struct-layout-1.h\"\n\ +\n\ +int fails; \n\ +#define TX(n, type, attrs, fields, ops) \\\n\ +type S##n { fields } attrs; \\\n\ +void test##n (void) \\\n\ +{ \\\n\ + char *encoding = @encode (type S##n); \\\n\ + if (objc_sizeof_type (encoding) != sizeof(type S##n)) \\\n\ + { \\\n\ + fails ++; \\\n\ + printf(#type \" { \" #fields \"} size is %%u, but is calulated as %%u\\n\", \\\n\ + sizeof(type S##n), objc_sizeof_type (encoding)); \\\n\ + } \\\n\ + if (objc_alignof_type (encoding) != __alignof__ (type S##n)) \\\n\ + { \\\n\ + fails ++; \\\n\ + printf(#type \" { \" #fields \"} align is %%u, but is calulated as %%u\\n\", \\\n\ + __alignof__ (type S##n), objc_alignof_type (encoding)); \\\n\ + } \\\n\ +}\n\ +#include \"t%03d_test.h\"\n\ +#undef TX\n\ +\n\ +int main (void)\n\ +{\n\ +#define TX(n, type, attrs, fields, ops) test##n ();\n\ +#include \"t%03d_test.h\"\n\ +#undef TX\n\ + if (fails)\n\ + {\n\ + fflush (stdout);\n\ + abort ();\n\ + }\n\ + exit (0);\n\ +}\n", filecnt, filecnt); + fclose (outfile); + sprintf (destptr, "t%03d_test.h", filecnt); + outfile = fopen (destbuf, "w"); + if (outfile == NULL) + goto fail; + if (fields <= 2) + limidx = idx + 300; + else if (fields <= 4) + limidx = idx + 200; + else if (fields <= 6) + limidx = idx + 100; + else + limidx = idx + 50; +} + +unsigned long long int +getrandll (void) +{ + unsigned long long int ret; + ret = generate_random () & 0xffffff; + ret |= (generate_random () & 0xffffffLL) << 24; + ret |= ((unsigned long long int) generate_random ()) << 48; + return ret; +} + +int +subfield (struct entry *e, char *letter) +{ + int i, type; + char buf[20]; + const char *p; + switch (e[0].etype) + { + case ETYPE_STRUCT: + case ETYPE_UNION: + case ETYPE_STRUCT_ARRAY: + case ETYPE_UNION_ARRAY: + type = e[0].attrib ? 1 + (generate_random () & 3) : 0; + if (e[0].etype == ETYPE_STRUCT || e[0].etype == ETYPE_STRUCT_ARRAY) + p = "struct"; + else + p = "union"; + if (e[0].etype == ETYPE_STRUCT_ARRAY || e[0].etype == ETYPE_UNION_ARRAY) + { + if (e[0].arr_len == 255) + snprintf (buf, 20, "%c[]", *letter); + else + snprintf (buf, 20, "%c[%d]", *letter, e[0].arr_len); + } + else + { + buf[0] = *letter; + buf[1] = '\0'; + } + ++*letter; + switch (type) + { + case 0: + case 3: + case 4: + fprintf (outfile, "%s{", p); + break; + case 1: + fprintf (outfile, "%s %s{", e[0].attrib, p); + break; + case 2: + fprintf (outfile, "%s %s{", p, e[0].attrib); + break; + } + + for (i = 1; i <= e[0].len; ) + i += subfield (e + i, letter); + + switch (type) + { + case 0: + case 1: + case 2: + fprintf (outfile, "}%s;", buf); + break; + case 3: + fprintf (outfile, "}%s %s;", e[0].attrib, buf); + break; + case 4: + fprintf (outfile, "}%s %s;", buf, e[0].attrib); + break; + } + return 1 + e[0].len; + case ETYPE_TYPE: + case ETYPE_ARRAY: + if (e[0].etype == ETYPE_ARRAY) + { + if (e[0].arr_len == 255) + snprintf (buf, 20, "%c[]", *letter); + else + snprintf (buf, 20, "%c[%d]", *letter, e[0].arr_len); + } + else + { + buf[0] = *letter; + buf[1] = '\0'; + } + ++*letter; + if (e[0].attrib) + switch (generate_random () % 3) + { + case 0: + fprintf (outfile, "%s %s %s;", e[0].attrib, e[0].type->name, buf); + break; + case 1: + fprintf (outfile, "%s %s %s;", e[0].type->name, e[0].attrib, buf); + break; + case 2: + fprintf (outfile, "%s %s %s;", e[0].type->name, buf, e[0].attrib); + break; + } + else + fprintf (outfile, "%s %s;", e[0].type->name, buf); + return 1; + case ETYPE_BITFLD: + if (e[0].len == 0) + { + if (e[0].attrib) + switch (generate_random () % 3) + { + case 0: + fprintf (outfile, "%s %s:0;", e[0].attrib, e[0].type->name); + break; + case 1: + fprintf (outfile, "%s %s:0;", e[0].type->name, e[0].attrib); + break; + case 2: + fprintf (outfile, "%s:0 %s;", e[0].type->name, e[0].attrib); + break; + } + else + fprintf (outfile, "%s:0;", e[0].type->name); + ++*letter; + return 1; + } + switch (e[0].type->bitfld) + { + case 'C': + case 'S': + case 'I': + case 'L': + case 'Q': + snprintf (buf, 20, "B%cN(%d)", e[0].type->bitfld, e[0].len); + break; + case 'B': + case ' ': + snprintf (buf, 20, "%d", e[0].len); + break; + default: + abort (); + } + if (e[0].attrib) + switch (generate_random () % 3) + { + case 0: + fprintf (outfile, "%s %s %c:%s;", e[0].attrib, e[0].type->name, + *letter, buf); + break; + case 1: + fprintf (outfile, "%s %s %c:%s;", e[0].type->name, e[0].attrib, + *letter, buf); + break; + case 2: + fprintf (outfile, "%s %c:%s %s;", e[0].type->name, *letter, + buf, e[0].attrib); + break; + } + else + fprintf (outfile, "%s %c:%s;", e[0].type->name, *letter, buf); + ++*letter; + return 1; + default: + abort (); + } +} + +char namebuf[1024]; + +void +output_FNB (char mode, struct entry *e) +{ + unsigned long long int l1, l2, m; + int signs = 0; + const char *p, *q; + + if (e->type->type == TYPE_OTHER) + { + if (mode == 'B') + abort (); + fprintf (outfile, "N(%d,%s)", idx, namebuf); + return; + } + fprintf (outfile, "%c(%d,%s,", mode, idx, namebuf); + l1 = getrandll (); + l2 = getrandll (); + switch (e->type->type) + { + case TYPE_INT: + signs = generate_random () & 3; + m = e->type->maxval; + if (mode == 'B') + m &= e->len > 1 ? (1ULL << (e->len - 1)) - 1 : 1; + l1 &= m; + l2 &= m; + fprintf (outfile, "%s%llu%s,%s%llu%s", + (signs & 1) ? "-" : "", l1, l1 > 2147483647 ? "LL" : "", + (signs & 2) ? "-" : "", l2, l2 > 2147483647 ? "LL" : ""); + break; + case TYPE_UINT: + m = e->type->maxval; + if (mode == 'B') + m &= (1ULL << e->len) - 1; + l1 &= m; + l2 &= m; + fprintf (outfile, "%lluU%s,%lluU%s", l1, l1 > 4294967295U ? "LL" : "", + l2, l2 > 4294967295U ? "LL" : ""); + break; + case TYPE_FLOAT: + l1 &= 0xffffff; + l2 &= 0xffffff; + signs = generate_random () & 3; + fprintf (outfile, "%s%f,%s%f", (signs & 1) ? "-" : "", + ((double) l1) / 64, (signs & 2) ? "-" : "", ((double) l2) / 64); + break; + case TYPE_CINT: + signs = generate_random () & 3; + l1 &= e->type->maxval; + l2 &= e->type->maxval; + fprintf (outfile, "CINT(%s%llu%s,%s%llu%s),", + (signs & 1) ? "-" : "", l1, l1 > 2147483647 ? "LL" : "", + (signs & 2) ? "-" : "", l2, l2 > 2147483647 ? "LL" : ""); + signs = generate_random () & 3; + l1 = getrandll (); + l2 = getrandll (); + l1 &= e->type->maxval; + l2 &= e->type->maxval; + fprintf (outfile, "CINT(%s%llu%s,%s%llu%s)", + (signs & 1) ? "-" : "", l1, l1 > 2147483647 ? "LL" : "", + (signs & 2) ? "-" : "", l2, l2 > 2147483647 ? "LL" : ""); + break; + case TYPE_CUINT: + l1 &= e->type->maxval; + l2 &= e->type->maxval; + fprintf (outfile, "CINT(%lluU%s,%lluU%s),", + l1, l1 > 4294967295U ? "LL" : "", + l2, l2 > 4294967295U ? "LL" : ""); + l1 = getrandll (); + l2 = getrandll (); + l1 &= e->type->maxval; + l2 &= e->type->maxval; + fprintf (outfile, "CINT(%lluU%s,%lluU%s)", + l1, l1 > 4294967295U ? "LL" : "", + l2, l2 > 4294967295U ? "LL" : ""); + break; + case TYPE_CFLOAT: + l1 &= 0xffffff; + l2 &= 0xffffff; + signs = generate_random () & 3; + fprintf (outfile, "CDBL(%s%f,%s%f),", + (signs & 1) ? "-" : "", ((double) l1) / 64, + (signs & 2) ? "-" : "", ((double) l2) / 64); + l1 = getrandll (); + l2 = getrandll (); + l1 &= 0xffffff; + l2 &= 0xffffff; + signs = generate_random () & 3; + fprintf (outfile, "CDBL(%s%f,%s%f)", + (signs & 1) ? "-" : "", ((double) l1) / 64, + (signs & 2) ? "-" : "", ((double) l2) / 64); + break; + case TYPE_UENUM: + if (e->type->maxval == 0) + fputs ("e0_0,e0_0", outfile); + else if (e->type->maxval == 1) + fprintf (outfile, "e1_%lld,e1_%lld", l1 & 1, l2 & 1); + else + { + p = strchr (e->type->name, '\0'); + while (--p >= e->type->name && *p >= '0' && *p <= '9'); + p++; + l1 %= 7; + l2 %= 7; + if (l1 > 3) + l1 += e->type->maxval - 6; + if (l2 > 3) + l2 += e->type->maxval - 6; + fprintf (outfile, "e%s_%lld,e%s_%lld", p, l1, p, l2); + } + break; + case TYPE_SENUM: + p = strchr (e->type->name, '\0'); + while (--p >= e->type->name && *p >= '0' && *p <= '9'); + p++; + l1 %= 7; + l2 %= 7; + fprintf (outfile, "e%s_%s%lld,e%s_%s%lld", + p, l1 < 3 ? "m" : "", + l1 == 3 ? 0LL : e->type->maxval - (l1 & 3), + p, l2 < 3 ? "m" : "", + l2 == 3 ? 0LL : e->type->maxval - (l2 & 3)); + break; + case TYPE_PTR: + l1 %= 256; + l2 %= 256; + fprintf (outfile, "(%s)&intarray[%lld],(%s)&intarray[%lld]", + e->type->name, l1, e->type->name, l2); + break; + case TYPE_FNPTR: + l1 %= 10; + l2 %= 10; + fprintf (outfile, "fn%lld,fn%lld", l1, l2); + break; + default: + abort (); + } + fputs (")", outfile); +} + +int +subvalues (struct entry *e, char *p, char *letter) +{ + int i, j; + char *q; + if (p >= namebuf + sizeof (namebuf) - 32) + abort (); + p[0] = *letter; + p[1] = '\0'; + q = p + 1; + switch (e[0].etype) + { + case ETYPE_STRUCT_ARRAY: + case ETYPE_UNION_ARRAY: + if (e[0].arr_len == 0 || e[0].arr_len == 255) + { + *letter += 1 + e[0].len; + return 1 + e[0].len; + } + i = generate_random () % e[0].arr_len; + snprintf (p, sizeof (namebuf) - (p - namebuf) - 1, + "%c[%d]", *letter, i); + q = strchr (p, '\0'); + /* FALLTHROUGH */ + case ETYPE_STRUCT: + case ETYPE_UNION: + *q++ = '.'; + ++*letter; + for (i = 1; i <= e[0].len; ) + { + i += subvalues (e + i, q, letter); + if (e[0].etype == ETYPE_UNION || e[0].etype == ETYPE_UNION_ARRAY) + { + *letter += e[0].len - i + 1; + break; + } + } + return 1 + e[0].len; + case ETYPE_TYPE: + ++*letter; + output_FNB ('F', e); + return 1; + case ETYPE_ARRAY: + if (e[0].arr_len == 0 || e[0].arr_len == 255) + { + ++*letter; + return 1; + } + i = generate_random () % e[0].arr_len; + snprintf (p, sizeof (namebuf) - (p - namebuf), + "%c[%d]", *letter, i); + output_FNB ('F', e); + if ((generate_random () & 7) == 0) + { + j = generate_random () % e[0].arr_len; + if (i != j) + { + snprintf (p, sizeof (namebuf) - (p - namebuf), + "%c[%d]", *letter, j); + output_FNB ('F', e); + } + } + ++*letter; + return 1; + case ETYPE_BITFLD: + ++*letter; + if (e[0].len != 0) + output_FNB ('B', e); + return 1; + } +} + +/* DERIVED FROM: +-------------------------------------------------------------------- +lookup2.c, by Bob Jenkins, December 1996, Public Domain. +hash(), hash2(), hash3, and mix() are externally useful functions. +Routines to test the hash are included if SELF_TEST is defined. +You can use this free for any purpose. It has no warranty. +-------------------------------------------------------------------- +*/ + +/* +-------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. +For every delta with one or two bit set, and the deltas of all three + high bits or all three low bits, whether the original value of a,b,c + is almost all zero or is uniformly distributed, +* If mix() is run forward or backward, at least 32 bits in a,b,c + have at least 1/4 probability of changing. +* If mix() is run forward, every bit of c will change between 1/3 and + 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) +mix() was built out of 36 single-cycle latency instructions in a + structure that could supported 2x parallelism, like so: + a -= b; + a -= c; x = (c>>13); + b -= c; a ^= x; + b -= a; x = (a<<8); + c -= a; b ^= x; + c -= b; x = (b>>13); + ... + Unfortunately, superscalar Pentiums and Sparcs can't take advantage + of that parallelism. They've also turned some of those single-cycle + latency instructions into multi-cycle latency instructions. Still, + this is the fastest good hash I could find. There were about 2^^68 + to choose from. I only looked at a billion or so. +-------------------------------------------------------------------- +*/ +/* same, but slower, works on systems that might have 8 byte hashval_t's */ +#define mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<< 8); \ + c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \ + a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \ + b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \ + c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \ + a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \ + b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \ + c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \ +} + +/* +-------------------------------------------------------------------- +hash() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + level : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Every 1-bit and 2-bit delta achieves avalanche. +About 36+6len instructions. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (ub1 **)k, do it like this: + for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h); + +By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this +code any way you wish, private, educational, or commercial. It's free. + +See http://burtleburtle.net/bob/hash/evahash.html +Use for hash table lookup, or anything where one collision in 2^32 is +acceptable. Do NOT use for cryptographic purposes. +-------------------------------------------------------------------- +*/ + +static hashval_t +iterative_hash (const void *k_in /* the key */, + register size_t length /* the length of the key */, + register hashval_t initval /* the previous hash, or + an arbitrary value */) +{ + register const unsigned char *k = (const unsigned char *)k_in; + register hashval_t a,b,c,len; + + /* Set up the internal state */ + len = length; + a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + c = initval; /* the previous hash value */ + + /*---------------------------------------- handle most of the key */ + while (len >= 12) + { + a += (k[0] +((hashval_t)k[1]<<8) +((hashval_t)k[2]<<16) +((hashval_t)k[3]<<24)); + b += (k[4] +((hashval_t)k[5]<<8) +((hashval_t)k[6]<<16) +((hashval_t)k[7]<<24)); + c += (k[8] +((hashval_t)k[9]<<8) +((hashval_t)k[10]<<16)+((hashval_t)k[11]<<24)); + mix(a,b,c); + k += 12; len -= 12; + } + + /*------------------------------------- handle the last 11 bytes */ + c += length; + switch(len) /* all the case statements fall through */ + { + case 11: c+=((hashval_t)k[10]<<24); + case 10: c+=((hashval_t)k[9]<<16); + case 9 : c+=((hashval_t)k[8]<<8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((hashval_t)k[7]<<24); + case 7 : b+=((hashval_t)k[6]<<16); + case 6 : b+=((hashval_t)k[5]<<8); + case 5 : b+=k[4]; + case 4 : a+=((hashval_t)k[3]<<24); + case 3 : a+=((hashval_t)k[2]<<16); + case 2 : a+=((hashval_t)k[1]<<8); + case 1 : a+=k[0]; + /* case 0: nothing left to add */ + } + mix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} + +hashval_t +e_hash (const void *a) +{ + const struct entry *e = a; + hashval_t ret = 0; + int i; + + if (e[0].etype != ETYPE_STRUCT && e[0].etype != ETYPE_UNION) + abort (); + for (i = 0; i <= e[0].len; ++i) + { + int attriblen; + ret = iterative_hash (&e[i], offsetof (struct entry, attrib), ret); + attriblen = e[i].attrib ? strlen (e[i].attrib) : -1; + ret = iterative_hash (&attriblen, sizeof (int), ret); + if (e[i].attrib) + ret = iterative_hash (e[i].attrib, attriblen, ret); + } + return ret; +} + +int +e_eq (const void *a, const void *b) +{ + const struct entry *ea = a, *eb = b; + int i; + if (ea[0].etype != ETYPE_STRUCT && ea[0].etype != ETYPE_UNION) + abort (); + if (ea[0].len != eb[0].len) + return 0; + for (i = 0; i <= ea[0].len; ++i) + { + if (ea[i].etype != eb[i].etype + || ea[i].len != eb[i].len + || ea[i].arr_len != eb[i].arr_len + || ea[i].type != eb[i].type) + return 0; + if ((ea[i].attrib == NULL) ^ (eb[i].attrib == NULL)) + return 0; + if (ea[i].attrib && strcmp (ea[i].attrib, eb[i].attrib) != 0) + return 0; + } + return 1; +} + +static int +e_exists (const struct entry *e) +{ + struct entry *h; + hashval_t hval; + + hval = e_hash (e); + for (h = hash_table[hval % HASH_SIZE]; h; h = h->next) + if (e_eq (e, h)) + return 1; + return 0; +} + +static void +e_insert (struct entry *e) +{ + hashval_t hval; + + hval = e_hash (e); + e->next = hash_table[hval % HASH_SIZE]; + hash_table[hval % HASH_SIZE] = e; +} + +void +output (struct entry *e) +{ + int i; + char c; + struct entry *n; + const char *skip_cint = ""; + + if (e[0].etype != ETYPE_STRUCT && e[0].etype != ETYPE_UNION) + abort (); + + if (e_exists (e)) + return; + + n = (struct entry *) malloc ((e[0].len + 1) * sizeof (struct entry)); + memcpy (n, e, (e[0].len + 1) * sizeof (struct entry)); + e_insert (n); + + if (idx == limidx) + switchfiles (e[0].len); + + for (i = 1; i <= e[0].len; ++i) + if ((e[i].etype == ETYPE_TYPE || e[i].etype == ETYPE_ARRAY) + && (e[i].type->type == TYPE_CINT || e[i].type->type == TYPE_CUINT)) + break; + if (i <= e[0].len) + skip_cint = "CI"; + if (e[0].attrib) + fprintf (outfile, (generate_random () & 1) + ? "TX%s(%d,%s %s,," : "TX%s(%d,%s,%s,", skip_cint, + idx, e[0].etype == ETYPE_STRUCT ? "struct" : "union", + e[0].attrib); + else if (e[0].etype == ETYPE_STRUCT) + fprintf (outfile, "T%s(%d,", skip_cint, idx); + else + fprintf (outfile, "U%s(%d,", skip_cint, idx); + c = 'a'; + for (i = 1; i <= e[0].len; ) + i += subfield (e + i, &c); + fputs (",", outfile); + c = 'a'; + for (i = 1; i <= e[0].len; ) + { + i += subvalues (e + i, namebuf, &c); + if (e[0].etype == ETYPE_UNION) + break; + } + fputs (")\n", outfile); + if (output_one && idx == limidx) + exit (0); + ++idx; +} + +enum FEATURE +{ + FEATURE_VECTOR = 1, + FEATURE_COMPLEX = 2, + FEATURE_ZEROARRAY = 8, + FEATURE_ZEROBITFLD = 16, + ALL_FEATURES = FEATURE_COMPLEX | FEATURE_VECTOR | FEATURE_ZEROARRAY + | FEATURE_ZEROBITFLD +}; + +void +singles (enum FEATURE features) +{ + struct entry e[2]; + int i; + memset (e, 0, sizeof (e)); + e[0].etype = ETYPE_STRUCT; + output (e); + e[0].etype = ETYPE_UNION; + output (e); + e[0].len = 1; + e[0].attrib = NULL; + for (i = 0; i < NTYPES2; ++i) + { + e[0].etype = ETYPE_STRUCT; + e[1].etype = ETYPE_TYPE; + e[1].type = &base_types[i]; + output (e); + e[0].etype = ETYPE_UNION; + output (e); + } + if (features & FEATURE_COMPLEX) + for (i = 0; i < NCTYPES2; ++i) + { + e[0].etype = ETYPE_STRUCT; + e[1].etype = ETYPE_TYPE; + e[1].type = &complex_types[i]; + output (e); + e[0].etype = ETYPE_UNION; + output (e); + } + if (features & FEATURE_VECTOR) + for (i = 0; i < NVTYPES2; ++i) + { + e[0].etype = ETYPE_STRUCT; + e[1].etype = ETYPE_TYPE; + e[1].type = &vector_types[i]; + output (e); + e[0].etype = ETYPE_UNION; + output (e); + } +} + +void +choose_type (enum FEATURE features, struct entry *e, int r, int in_array) +{ + int i; + + i = NTYPES2 - NTYPES1; + if (features & FEATURE_COMPLEX) + i += NCTYPES2; + if (features & FEATURE_VECTOR) + i += NVTYPES2; + r >>= 2; + r %= i; + if (r < NTYPES2 - NTYPES1) + e->type = &base_types[r + NTYPES1]; + r -= NTYPES2 - NTYPES1; + if (e->type == NULL && (features & FEATURE_COMPLEX)) + { + if (r < NCTYPES2) + e->type = &complex_types[r]; + r -= NCTYPES2; + } + if (e->type == NULL && (features & FEATURE_VECTOR)) + { + if (r < NVTYPES2) + e->type = &vector_types[r]; + r -= NVTYPES2; + } + if (e->type == NULL) + abort (); +} + +/* This is from gcc.c-torture/execute/builtin-bitops-1.c. */ +static int +my_ffsll (unsigned long long x) +{ + int i; + if (x == 0) + return 0; + /* We've tested LLONG_MAX for 64 bits so this should be safe. */ + for (i = 0; i < 64; i++) + if (x & (1ULL << i)) + break; + return i + 1; +} + +void +generate_fields (enum FEATURE features, struct entry *e, struct entry *parent, + int len) +{ + int r, i, j, ret = 1, n, incr, sametype; + + for (n = 0; n < len; n += incr) + { + r = generate_random (); + /* 50% ETYPE_TYPE base_types NTYPES1 + 12.5% ETYPE_TYPE other + 12.5% ETYPE_ARRAY + 12.5% ETYPE_BITFLD + 12.5% ETYPE_STRUCT|ETYPE_UNION|ETYPE_STRUCT_ARRAY|ETYPE_UNION_ARRAY */ + i = (r & 7); + r >>= 3; + incr = 1; + switch (i) + { + case 6: /* BITfields disabled for now as _Bool bitfields are broken. */ + case 0: + case 1: + case 2: + case 3: + e[n].etype = ETYPE_TYPE; + e[n].type = &base_types[r % NTYPES1]; + break; + case 4: + e[n].etype = ETYPE_TYPE; + choose_type (features, &e[n], r, 0); + break; + case 5: + e[n].etype = ETYPE_ARRAY; + i = r & 1; + r >>= 1; + if (i) + e[n].type = &base_types[r % NTYPES1]; + else + choose_type (features, &e[n], r, 1); + r = generate_random (); + if ((features & FEATURE_ZEROARRAY) && (r & 3) == 0) + { + e[n].arr_len = 0; + if (n == len - 1 && (r & 4) + && (parent->etype == ETYPE_STRUCT + || parent->etype == ETYPE_STRUCT_ARRAY)) + { + int k; + for (k = 0; k < n; ++k) + if (e[k].etype != ETYPE_BITFLD || e[k].len) + { + e[n].arr_len = 255; + break; + } + } + } + else if ((r & 3) != 3) + e[n].arr_len = (r >> 2) & 7; + else + e[n].arr_len = (r >> 2) & 31; + break; +#if 0 + case 6: + sametype = 1; + switch (r & 7) + { + case 0: + case 1: + case 2: + break; + case 3: + case 4: + case 5: + incr = 1 + (r >> 3) % (len - n); + break; + case 6: + case 7: + sametype = 0; + incr = 1 + (r >> 3) % (len - n); + break; + } + for (j = n; j < n + incr; ++j) + { + int mi, ma; + + e[j].etype = ETYPE_BITFLD; + if (j == n || !sametype) + { + r = generate_random (); + r >>= 2; + e[j].type + = &bitfld_types[r % n_bitfld_types]; + } + else + e[j].type = e[n].type; + r = generate_random (); + mi = 0; + ma = 0; + switch (e[j].type->bitfld) + { + case 'C': ma = 8; break; + case 'S': ma = 16; break; + case 'I': ma = 32; break; + case 'L': + case 'Q': ma = 64; break; + case 'B': ma = 1; break; + case ' ': + if (e[j].type->type == TYPE_UENUM) + mi = my_ffsll (e[j].type->maxval + 1) - 1; + else if (e[j].type->type == TYPE_SENUM) + mi = my_ffsll (e[j].type->maxval + 1); + else + abort (); + if (!mi) + mi = 1; + if (mi <= 32) + ma = 32; + else + ma = 64; + break; + default: + abort (); + } + e[j].len = ma + 1; + if (sametype && (r & 3) == 0 && ma > 1) + { + int sum = 0, k; + for (k = n; k < j; ++k) + sum += e[k].len; + sum %= ma; + e[j].len = sum ? ma - sum : ma; + } + r >>= 2; + if (! (features & FEATURE_ZEROBITFLD) && mi == 0) + mi = 1; + if (e[j].len < mi || e[j].len > ma) + e[j].len = mi + (r % (ma + 1 - mi)); + r >>= 6; + if ((features & FEATURE_ZEROBITFLD) && (r & 3) == 0 + && mi == 0) + e[j].len = 0; + } + break; +#endif + case 7: + switch (r & 7) + { + case 0: + case 1: + case 2: + e[n].etype = ETYPE_STRUCT; + break; + case 3: + case 4: + e[n].etype = ETYPE_UNION; + break; + case 5: + case 6: + e[n].etype = ETYPE_STRUCT_ARRAY; + break; + case 7: + e[n].etype = ETYPE_UNION_ARRAY; + break; + } + r >>= 3; + e[n].len = r % (len - n); + incr = 1 + e[n].len; + generate_fields (features, &e[n + 1], &e[n], e[n].len); + if (e[n].etype == ETYPE_STRUCT_ARRAY + || e[n].etype == ETYPE_UNION_ARRAY) + { + r = generate_random (); + if ((features & FEATURE_ZEROARRAY) && (r & 3) == 0) + { + e[n].arr_len = 0; + if (n + incr == len && (r & 4) + && (parent->etype == ETYPE_STRUCT + || parent->etype == ETYPE_STRUCT_ARRAY)) + { + int k; + for (k = 0; k < n; ++k) + if (e[k].etype != ETYPE_BITFLD || e[k].len) + { + e[n].arr_len = 255; + break; + } + } + } + else if ((r & 3) != 3) + e[n].arr_len = (r >> 2) & 7; + else + e[n].arr_len = (r >> 2) & 31; + } + break; + } + } +} + +void +generate_random_tests (enum FEATURE features, int len) +{ + struct entry e[len + 1]; + int i, r; + if (len > 'z' - 'a' + 1) + abort (); + memset (e, 0, sizeof (e)); + r = generate_random (); + if ((r & 7) == 0) + e[0].etype = ETYPE_UNION; + else + e[0].etype = ETYPE_STRUCT; + r >>= 3; + e[0].len = len; + generate_fields (features, &e[1], &e[0], len); + output (e); +} + +struct { const char *name; enum FEATURE f; } +features[] = { +{ "normal", 0 }, +{ "complex", FEATURE_COMPLEX }, +{ "vector", FEATURE_VECTOR }, +{ "[0] :0", FEATURE_ZEROARRAY | FEATURE_ZEROBITFLD }, +{ "complex vector [0]", + FEATURE_COMPLEX | FEATURE_VECTOR | FEATURE_ZEROARRAY } +}; + +int +main (int argc, char **argv) +{ + int i, j, count, c, n = 3000; + char *optarg; + + if (sizeof (int) != 4 || sizeof (long long) != 8) + return 1; + + i = 1; + while (i < argc) + { + c = '\0'; + if (argv[i][0] == '-' && argv[i][2] == '\0') + c = argv[i][1]; + optarg = argv[i + 1]; + if (!optarg) + goto usage; + switch (c) + { + case 'n': + n = atoi (optarg); + break; + case 'd': + destdir = optarg; + break; + case 's': + srcdir = optarg; + break; + case 'i': + output_one = 1; + limidx = atoi (optarg); + break; + default: + fprintf (stderr, "unrecognized option %s\n", argv[i]); + goto usage; + } + i += 2; + } + + if (output_one) + { + outfile = fopen ("/dev/null", "w"); + if (outfile == NULL) + { + fputs ("could not open /dev/null", stderr); + return 1; + } + n = limidx + 1; + } + + if (destdir == NULL && !output_one) + { + usage: + fprintf (stderr, "Usage:\n\ +%s [-s srcdir -d destdir] [-n count] [-i idx]\n\ +Either -s srcdir -d destdir or -i idx must be used\n", argv[0]); + return 1; + } + + if (srcdir == NULL && !output_one) + goto usage; + + for (i = 0; i < NTYPES2; ++i) + if (base_types[i].bitfld) + bitfld_types[n_bitfld_types++] = base_types[i]; + for (i = 0; i < sizeof (features) / sizeof (features[0]); ++i) + { + int startidx = idx; + if (! output_one) + limidx = idx; + if (!i) + count = 200; + else + count = 20; + for (j = 1; j <= 9; ++j) + while (idx < startidx + j * count) + generate_random_tests (features[i].f, j); + while (idx < startidx + count * 10) + generate_random_tests (features[i].f, 10 + (generate_random () % 16)); + } + for (i = 0; n > 3000 && i < sizeof (features) / sizeof (features[0]); ++i) + { + int startidx; + startidx = idx; + if (! output_one) + limidx = idx; + singles (features[i].f); + if (!i) + { + count = 1000; + while (idx < startidx + 1000) + generate_random_tests (features[i].f, 1); + } + else + { + startidx = idx; + count = 100; + while (idx < startidx + 100) + generate_random_tests (features[i].f, 1); + } + startidx = idx; + for (j = 2; j <= 9; ++j) + while (idx < startidx + (j - 1) * count) + generate_random_tests (features[i].f, j); + while (idx < startidx + count * 9) + generate_random_tests (features[i].f, 10 + (generate_random () % 16)); + } + if (! output_one) + limidx = idx; + while (idx < n) + generate_random_tests (ALL_FEATURES, 1 + (generate_random () % 25)); + fclose (outfile); + return 0; +} diff --git a/gcc/testsuite/objc.dg/gnu-encoding/vector-defs.h b/gcc/testsuite/objc.dg/gnu-encoding/vector-defs.h new file mode 100644 index 000000000..57140f115 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-encoding/vector-defs.h @@ -0,0 +1,72 @@ +/* This includes all of the vector modes that are recognized by + c_common_type_for_mode. */ + +typedef int __attribute__((mode(QI))) qi; +typedef int __attribute__((mode(HI))) hi; +typedef int __attribute__((mode(SI))) si; +typedef int __attribute__((mode(DI))) di; +typedef float __attribute__((mode(SF))) sf; +typedef float __attribute__((mode(DF))) df; + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 5) + +typedef qi __attribute__((vector_size (8))) v8qi; +typedef qi __attribute__((vector_size (16))) v16qi; + +typedef hi __attribute__((vector_size (4))) v2hi; +typedef hi __attribute__((vector_size (8))) v4hi; +typedef hi __attribute__((vector_size (16))) v8hi; + +typedef si __attribute__((vector_size (8))) v2si; +typedef si __attribute__((vector_size (16))) v4si; + +typedef di __attribute__((vector_size (8))) v1di; +typedef di __attribute__((vector_size (16))) v2di; + +typedef sf __attribute__((vector_size (8))) v2sf; +typedef sf __attribute__((vector_size (16))) v4sf; +typedef sf __attribute__((vector_size (64))) v16sf; + +typedef df __attribute__((vector_size (16))) v2df; + +#else + +typedef int __attribute__((mode(V8QI))) v8qi; +typedef int __attribute__((mode(V16QI))) v16qi; + +typedef int __attribute__((mode(V2HI))) v2hi; +typedef int __attribute__((mode(V4HI))) v4hi; +typedef int __attribute__((mode(V8HI))) v8hi; + +typedef int __attribute__((mode(V2SI))) v2si; +typedef int __attribute__((mode(V4SI))) v4si; + +typedef int __attribute__((mode(V1DI))) v1di; +typedef int __attribute__((mode(V2DI))) v2di; + +typedef float __attribute__((mode(V2SF))) v2sf; +typedef float __attribute__((mode(V4SF))) v4sf; +typedef float __attribute__((mode(V16SF))) v16sf; + +typedef float __attribute__((mode(V2DF))) v2df; + +#endif + +typedef union U8QI { v8qi v; qi a[8]; } u8qi; +typedef union U16QI { v16qi v; qi a[16]; } u16qi; + +typedef union U2HI { v2hi v; hi a[2]; } u2hi; +typedef union U4HI { v4hi v; hi a[4]; } u4hi; +typedef union U8HI { v8hi v; hi a[8]; } u8hi; + +typedef union U2SI { v2si v; si a[2]; } u2si; +typedef union U4SI { v4si v; si a[4]; } u4si; + +typedef union U1DI { v1di v; di a[1]; } u1di; +typedef union U2DI { v2di v; di a[2]; } u2di; + +typedef union U2SF { v2sf v; sf a[2]; } u2sf; +typedef union U4SF { v4sf v; sf a[4]; } u4sf; +typedef union U16SF { v16sf v; sf a[16]; } u16sf; + +typedef union U2DF { v2df v; df a[2]; } u2df; diff --git a/gcc/testsuite/objc.dg/gnu-runtime-1.m b/gcc/testsuite/objc.dg/gnu-runtime-1.m new file mode 100644 index 000000000..c7e3bcc3a --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-runtime-1.m @@ -0,0 +1,19 @@ +/* Test that compiling for the GNU runtime works (regardless of + the system runtime used). */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +#include <objc/Object.h> + +@interface FooBar: Object +- (void)boo; +@end + +int main () +{ + id fooBarInst = [[FooBar alloc] init]; + [fooBarInst boo]; + return 0; +} + diff --git a/gcc/testsuite/objc.dg/gnu-runtime-2.m b/gcc/testsuite/objc.dg/gnu-runtime-2.m new file mode 100644 index 000000000..9903d2972 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-runtime-2.m @@ -0,0 +1,30 @@ +/* Sanity check for GNU-runtime version of constant strings, + regardless of runtime used on target system. */ + +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +#include <objc/Object.h> +#include <string.h> +#include <stdlib.h> + +@interface NXConstantString: Object +{ + char *c_string; + unsigned int len; +} +-(const char *) cString; +-(unsigned int) length; +@end + +@implementation NXConstantString +-(const char *) cString { return c_string; } +-(unsigned int) length { return len; } +@end + +int main(int argc, void **args) +{ + if (strcmp ([@"this is a string" cString], "this is a string")) + abort (); + return 0; +} diff --git a/gcc/testsuite/objc.dg/gnu-runtime-3.m b/gcc/testsuite/objc.dg/gnu-runtime-3.m new file mode 100644 index 000000000..e0c8cc416 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-runtime-3.m @@ -0,0 +1,14 @@ +/* Sanity check for GNU-runtime regardless of runtime used on target system. */ + +/* { dg-do run } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +#include <objc/Object.h> +#include <string.h> +#include <stdlib.h> + +int main(int argc, void **args) +{ + [Object new]; + return 0; +} diff --git a/gcc/testsuite/objc.dg/headers.m b/gcc/testsuite/objc.dg/headers.m new file mode 100644 index 000000000..4c61e1e55 --- /dev/null +++ b/gcc/testsuite/objc.dg/headers.m @@ -0,0 +1,31 @@ +// Test for obscure conflicts with the system headers (inspired by similar +// test in libstdc++-v3). Author: Loren J. Rittle <ljrittle@acm.org>. +// { dg-options "-Wall -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wshadow" } +// { dg-do compile } + +#ifdef __NEXT_RUNTIME__ +#include <Foundation/NSString.h> +#else +#include <objc/NXConstStr.h> +#endif +#include <objc/Object.h> +#include <objc/Protocol.h> +#ifdef __NEXT_RUNTIME__ +#include <objc/objc-runtime.h> +#else +#include <objc/encoding.h> +#include <objc/hash.h> +#endif + +#include <objc/objc-api.h> +#ifndef __NEXT_RUNTIME__ +#include <objc/objc-list.h> +#endif + +#include <objc/objc.h> + +#ifndef __NEXT_RUNTIME__ +#include <objc/sarray.h> +#include <objc/thr.h> +#include <objc/typedstream.h> +#endif diff --git a/gcc/testsuite/objc.dg/id-1.m b/gcc/testsuite/objc.dg/id-1.m new file mode 100644 index 000000000..2bfcc63f9 --- /dev/null +++ b/gcc/testsuite/objc.dg/id-1.m @@ -0,0 +1,7 @@ +/* Test attempt to redefine 'id' in an incompatible fashion. */ +/* { dg-do compile } */ + +typedef int id; /* { dg-error "conflicting types for .id." } */ +/* { dg-message "previous declaration of .id. was here" "" { target *-*-* } 0 } */ + +id b; diff --git a/gcc/testsuite/objc.dg/image-info.m b/gcc/testsuite/objc.dg/image-info.m new file mode 100644 index 000000000..194d3664f --- /dev/null +++ b/gcc/testsuite/objc.dg/image-info.m @@ -0,0 +1,43 @@ +/* Check if the '-freplace-objc-classes' option causes the + __OBJC,__image_info section to be emitted. This is only + usable on MacOS X 10.3 and later. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do compile { target { *-*-darwin* } } } */ +/* { dg-skip-if "NeXT-only" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-freplace-objc-classes" } */ + +#include <objc/objc.h> +#include <objc/Object.h> + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort(); + +@interface Object (TEST_SUITE_C1) +- init; +@end +@implementation Object (TEST_SUITE_C1) +- init {return self;} +@end + +@interface Base: Object { +@public + int a; + float b; + char c; +} +- init; +@end + +@implementation Base +- init { + [super init]; + a = 123; + b = 1.23; + c = 'c'; + return self; +} +@end + +/* { dg-final { scan-assembler "\t.section __OBJC, __image_info.*\n\t.align.*\nL_OBJC_ImageInfo.*:\n\t.long\t0\n\t.long\t1" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler "\t.section __DATA, __objc_imageinfo.*\n\t.align.*\nL_OBJC_ImageInfo.*:\n\t.long\t0\n\t.long\t17" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/incomplete-type-1.m b/gcc/testsuite/objc.dg/incomplete-type-1.m new file mode 100644 index 000000000..f1e875f9a --- /dev/null +++ b/gcc/testsuite/objc.dg/incomplete-type-1.m @@ -0,0 +1,22 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +enum type1; +struct type2; + +@interface MyObject +- (void) method1: (enum type1)argument; +- (void) method2: (struct type2)argument; +@end + +@implementation MyObject +- (void) method1: (enum type1)argument { /* { dg-error "does not have a known size" } */ + return; +} +- (void) method2: (struct type2)argument { /* { dg-error "does not have a known size" } */ + return; +} +@end + diff --git a/gcc/testsuite/objc.dg/invalid-method-1.m b/gcc/testsuite/objc.dg/invalid-method-1.m new file mode 100644 index 000000000..78eae2c58 --- /dev/null +++ b/gcc/testsuite/objc.dg/invalid-method-1.m @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* Test that we keep compiling if a method definition is found outside + of an @implementation context. +*/ + ++ (void)C { } /* { dg-error "method definition not in @implementation context" } */ + +/* We have another error here to test that the compiler is still going and + finding errors in the rest of the code. +*/ +@compatibility_alias class1 class2; /* { dg-warning "annot find class" } */ diff --git a/gcc/testsuite/objc.dg/invalid-method-2.m b/gcc/testsuite/objc.dg/invalid-method-2.m new file mode 100644 index 000000000..cb18de957 --- /dev/null +++ b/gcc/testsuite/objc.dg/invalid-method-2.m @@ -0,0 +1,18 @@ +/* { dg-do compile } */ + +/* Test that using an invalid type in a method declaration produces a + friendly error without a compiler crash. */ + +@interface MyClass +@end + +@implementation MyClass +- (x) method /* { dg-error "unknown type name" } */ +{ + return 0; +} +- (id) method2: (x)argument /* { dg-error "unknown type name" } */ +{ + return 0; +} +@end diff --git a/gcc/testsuite/objc.dg/invalid-type-1.m b/gcc/testsuite/objc.dg/invalid-type-1.m new file mode 100644 index 000000000..b8609f8c8 --- /dev/null +++ b/gcc/testsuite/objc.dg/invalid-type-1.m @@ -0,0 +1,24 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ +#include <objc/objc.h> + +typedef int Integer; + +@class MyClass; + +typedef MyClass AClass; + +@protocol MyProtocol +- (void) method; +@end + +Class <MyProtocol> class_object; /* This is fine. */ + +id <MyProtocol> object; /* This is fine. */ + +AClass <MyProtocol> *object1; /* This is fine. */ + +Integer <MyProtocol> *object2; /* { dg-error "only Objective-C object types can be qualified with a protocol" } */ + +Integer <NonExistingProtocol> *object3; /* { dg-error "only Objective-C object types can be qualified with a protocol" } */ +/* { dg-error "cannot find protocol" "" { target *-*-* } 23 } */ diff --git a/gcc/testsuite/objc.dg/isa-field-1.m b/gcc/testsuite/objc.dg/isa-field-1.m new file mode 100644 index 000000000..377280f0d --- /dev/null +++ b/gcc/testsuite/objc.dg/isa-field-1.m @@ -0,0 +1,63 @@ +/* Ensure there are no bizarre difficulties with accessing the 'isa' field of objects. */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@interface Object (Test) +- (Class) test1: (id)object; +@end + +@interface Derived: Object +- (Class) test2: (id)object; +@end + +@implementation Object (Test) + +Class test1(id object) { +#ifdef __NEXT_RUNTIME__ + Class cls = object->isa; +#else + Class cls = object->class_pointer; +#endif + return cls; +} +- (Class) test1: (id)object { +#ifdef __NEXT_RUNTIME__ + Class cls = object->isa; +#else + Class cls = object->class_pointer; +#endif + return cls; +} + +@end + +@implementation Derived + +Class test2(id object) { +#ifdef __NEXT_RUNTIME__ + Class cls = object->isa; +#else + Class cls = object->class_pointer; +#endif + return cls; +} +- (Class) test2: (id)object { +#ifdef __NEXT_RUNTIME__ + Class cls = object->isa; +#else + Class cls = object->class_pointer; +#endif + return cls; +} + +@end + +Class test3(id object) { +#ifdef __NEXT_RUNTIME__ + Class cls = object->isa; +#else + Class cls = object->class_pointer; +#endif + return cls; +} diff --git a/gcc/testsuite/objc.dg/ivar-invalid-type-1.m b/gcc/testsuite/objc.dg/ivar-invalid-type-1.m new file mode 100644 index 000000000..3e7785db8 --- /dev/null +++ b/gcc/testsuite/objc.dg/ivar-invalid-type-1.m @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +@end + +@interface MySubClass +{ + volatile int a; /* This is allowed */ + extern int b; /* { dg-error "expected" } */ + static int c; /* { dg-error "expected" } */ + inline int d; /* { dg-error "expected" } */ + typedef int e; /* { dg-error "expected" } */ + __thread int f; /* { dg-error "expected" } */ +} +@end diff --git a/gcc/testsuite/objc.dg/ivar-problem-1.m b/gcc/testsuite/objc.dg/ivar-problem-1.m new file mode 100644 index 000000000..4a8776805 --- /dev/null +++ b/gcc/testsuite/objc.dg/ivar-problem-1.m @@ -0,0 +1,65 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* This test checks what happens if there are 16 instance variables. + In that case, the class was not created correctly. In this testcase, + we have two classes, one with 15 variables and one with 16. Older + GCCs would generate a bogus warning for the second class but not + for the first one. */ + +#include <stdlib.h> +#include <objc/objc.h> + +@interface MyRootClass1 +{ + Class isa; + int v2; + int v3; + int v4; + int v5; + int v6; + int v7; + int v8; + int v9; + int v10; + int v11; + int v12; + int v13; + int v14; + int v15; +} +- (id) init; +@end + +@implementation MyRootClass1 +- (id) init { return self; } +@end + + +@interface MyRootClass2 +{ + Class isa; + int v2; + int v3; + int v4; + int v5; + int v6; + int v7; + int v8; + int v9; + int v10; + int v11; + int v12; + int v13; + int v14; + int v15; + /* Adding the 16th variable used to cause bogus warnings to be + generated. */ + int v16; +} +- (id) init; +@end + +@implementation MyRootClass2 +- (id) init { return self; } /* This should not generate a bogus warning. */ +@end diff --git a/gcc/testsuite/objc.dg/keywords-1.m b/gcc/testsuite/objc.dg/keywords-1.m new file mode 100644 index 000000000..abb4537ae --- /dev/null +++ b/gcc/testsuite/objc.dg/keywords-1.m @@ -0,0 +1,27 @@ +/* Test that 'in', 'out', 'inout', 'bycopy', 'byref', 'oneway' + are not keywords outside of a "protocol qualifier" context. +*/ +/* { dg-do compile } */ + +typedef int in; + +in out (in inout) +{ + int byref = inout * 2; + + return byref + inout; +} + +@class byref; + +@interface inout +@end + +@protocol oneway; + +int main (void) +{ + in bycopy = (in)(out (0)); + + return (in)bycopy; +} diff --git a/gcc/testsuite/objc.dg/keywords-2.m b/gcc/testsuite/objc.dg/keywords-2.m new file mode 100644 index 000000000..c81cb4d0c --- /dev/null +++ b/gcc/testsuite/objc.dg/keywords-2.m @@ -0,0 +1,24 @@ +/* Test that 'encode', 'end', 'compatibility_alias', 'defs', + 'protocol', 'selector', finally', 'synchronized', 'interface', + 'implementation' are not keywords if not after a '@'. +*/ +/* { dg-do compile } */ + +int encode (int end) +{ + int compatibility_alias = end * 2; + int defs = compatibility_alias * 2; + int protocol = defs * 2; + int selector = protocol * 2; + int finally = selector * 2; + int synchronized = finally * 2; + int interface = synchronized * 2; + int implementation = interface * 2; + + return implementation; +} + +int main (void) +{ + return encode (0); +} diff --git a/gcc/testsuite/objc.dg/keywords-3.m b/gcc/testsuite/objc.dg/keywords-3.m new file mode 100644 index 000000000..28c2cf50e --- /dev/null +++ b/gcc/testsuite/objc.dg/keywords-3.m @@ -0,0 +1,20 @@ +/* Test that 'class', 'public', 'private', protected', 'try', 'catch', + 'throw' are not keywords in pure Objective-C if not after a '@'. +*/ +/* { dg-do compile } */ + +int class (int public) +{ + int private = public; + int protected = private * 2; + int try = protected * 2; + int catch = try * 2; + int throw = catch * 2; + + return throw; +} + +int main (void) +{ + return class (0); +} diff --git a/gcc/testsuite/objc.dg/layout-1.m b/gcc/testsuite/objc.dg/layout-1.m new file mode 100644 index 000000000..f702eb2ba --- /dev/null +++ b/gcc/testsuite/objc.dg/layout-1.m @@ -0,0 +1,15 @@ +/* Ensure that we do not get bizarre warnings referring to + __attribute__((packed)) or some such. */ +/* { dg-do compile } */ +/* { dg-options "-Wpadded -Wpacked" } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@interface Derived1: Object +{ } +@end + +@interface Derived2: Object +- (id) foo; +@end + diff --git a/gcc/testsuite/objc.dg/layout-2.m b/gcc/testsuite/objc.dg/layout-2.m new file mode 100644 index 000000000..474fc0461 --- /dev/null +++ b/gcc/testsuite/objc.dg/layout-2.m @@ -0,0 +1,14 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, February 2011. */ +/* Ensure that -Wpadded generates no warnings during runtime structure metadata + generation. */ +/* { dg-do compile } */ +/* { dg-options "-Wpadded" } */ + +#include "../objc-obj-c++-shared/Object1.h" + +/* Implement a class, so that the metadata generation happens. */ +@interface MyClass : Object +@end + +@implementation MyClass +@end diff --git a/gcc/testsuite/objc.dg/libobjc-selector-1.m b/gcc/testsuite/objc.dg/libobjc-selector-1.m new file mode 100644 index 000000000..49947d7b8 --- /dev/null +++ b/gcc/testsuite/objc.dg/libobjc-selector-1.m @@ -0,0 +1,39 @@ +/* Test a little inefficiency that was fixed in libobjc when dealing + with selectors (PR libobjc/45953). */ + +/* { dg-do run } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +/* To get the modern GNU Objective-C Runtime API, you include + objc/runtime.h. */ +#include <objc/runtime.h> +#include <stdlib.h> + +/* Test that registering a new selector, with the same name but a + different type than the previous one, does not change the original + name string. It is actually fine to change it (there is no + guarantee that it won't change), except for runtime performance / + memory consumption, since changing it means that the runtime is + doing an unneeded objc_malloc()/strcpy(), which is inefficient. */ + +int main (void) +{ + SEL selector_1; + SEL selector_2; + const char *name_1; + const char *name_2; + + /* These method type strings may well be invalid. Please don't use + them as examples. They are irrelevant for this test; any string + will do. */ + selector_1 = sel_registerTypedName ("method", "v@:"); + name_1 = sel_getName (selector_1); + + selector_2 = sel_registerTypedName ("method", "i@:"); + name_2 = sel_getName (selector_1); + + if (name_1 != name_2) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/local-decl-1.m b/gcc/testsuite/objc.dg/local-decl-1.m new file mode 100644 index 000000000..4a4bfdffe --- /dev/null +++ b/gcc/testsuite/objc.dg/local-decl-1.m @@ -0,0 +1,25 @@ +/* Test for hiding of ivars by local variables. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +@interface Sprite { + int a; +} +@end + +Sprite *glob; + +@interface blah +{ + Sprite* sprite; +} +@end + +@implementation blah +- (Sprite *)load +{ + Sprite *sprite = 0; + Sprite *glob = 0; /* ok */ + return sprite; /* { dg-warning "hides instance variable" } */ +} +@end diff --git a/gcc/testsuite/objc.dg/local-decl-2.m b/gcc/testsuite/objc.dg/local-decl-2.m new file mode 100644 index 000000000..b1af6d27b --- /dev/null +++ b/gcc/testsuite/objc.dg/local-decl-2.m @@ -0,0 +1,42 @@ +/* Test for ivar access inside of class methods. It should be allowed (with a warning), but only + if no other declarations with the same name are seen. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@interface Sprite: Object { + int sprite, spree; +} ++ (void)setFoo:(int)foo; ++ (void)setSprite:(int)sprite; +- (void)setFoo:(int)foo; +- (void)setSprite:(int)sprite; +@end + +int spree = 23; + +@implementation Sprite ++ (void)setFoo:(int)foo { + sprite = foo; /* { dg-warning "instance variable .sprite. accessed in class method" } */ + spree = foo; +} ++ (void)setSprite:(int)sprite { + int spree; + sprite = 15; + spree = 17; + ((Sprite *)self)->sprite = 16; /* NB: This is how one _should_ access */ + ((Sprite *)self)->spree = 18; /* ivars from within class methods! */ +} +- (void)setFoo:(int)foo { + sprite = foo; + spree = foo; +} +- (void)setSprite:(int)sprite { + int spree; + sprite = 15; /* { dg-warning "local declaration of .sprite. hides instance variable" } */ + self->sprite = 16; + spree = 17; /* { dg-warning "local declaration of .spree. hides instance variable" } */ + self->spree = 18; +} +@end diff --git a/gcc/testsuite/objc.dg/lookup-1.m b/gcc/testsuite/objc.dg/lookup-1.m new file mode 100644 index 000000000..737d58a68 --- /dev/null +++ b/gcc/testsuite/objc.dg/lookup-1.m @@ -0,0 +1,56 @@ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m" } */ + +#include <stdlib.h> +#include "../objc-obj-c++-shared/Object1.h" + +typedef struct MyWidget { + int a; +} MyWidget; + +MyWidget gWidget = { 17 }; + +@protocol MyProto +- (MyWidget *)widget; +@end + +@interface Foo: Object +@end + +@interface Bar: Foo <MyProto> +@end + +@interface Container: Object ++ (MyWidget *)elementForView:(Foo *)view; +@end + +@implementation Foo +@end + +@implementation Bar +- (MyWidget *)widget { + return &gWidget; +} +@end + +@implementation Container ++ (MyWidget *)elementForView:(Foo *)view +{ + MyWidget *widget = (MyWidget *) nil; + if ([view conformsTo:@protocol(MyProto)]) { + widget = [(Foo <MyProto> *)view widget]; + } + return widget; +} +@end + +int main(void) { + id view = [Bar new]; + MyWidget *w = [Container elementForView: view]; + + if (!w || w->a != 17) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/lto/lto.exp b/gcc/testsuite/objc.dg/lto/lto.exp new file mode 100644 index 000000000..f567cd93e --- /dev/null +++ b/gcc/testsuite/objc.dg/lto/lto.exp @@ -0,0 +1,84 @@ +# Copyright (C) 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. +# +# Based on gcc/testsuite/gcc.dg/lto/lto.exp. + +# Test link-time optimization across multiple files. +# +# Programs are broken into multiple files. Each one is compiled +# separately with LTO information. The final executable is generated +# by collecting all the generated object files using regular LTO or WHOPR. + +if $tracelevel then { + strace $tracelevel +} + +# Load procedures from common libraries. +load_lib standard.exp +load_lib objc-dg.exp + +# Load the language-independent compabibility support procedures. +load_lib lto.exp + +# If LTO has not been enabled, bail. +if { ![check_effective_target_lto] } { + return +} + +global LTO_OPTIONS + +set LTO_OPTIONS [list \ + {-O0 -flto -fgnu-runtime} \ + {-O2 -flto -fgnu-runtime} \ + {-O0 -flto -flto-partition=none -fgnu-runtime} \ + {-O2 -flto -flto-partition=none -fgnu-runtime} \ +] + +objc_init +lto_init no-mathlib + +# Define an identifier for use with this suite to avoid name conflicts +# with other lto tests running at the same time. +set sid "objc_lto" +set tests [lsort [glob -nocomplain $srcdir/$subdir/*_0.m]] + +# Main loop. +foreach src $tests { + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $src] then { + continue + } + lto-execute $src $sid +} + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { +set LTO_OPTIONS [list \ + {-O0 -flto -fnext-runtime} \ + {-O2 -flto -fnext-runtime} \ + {-O0 -flto -flto-partition=none -fnext-runtime} \ + {-O2 -flto -flto-partition=none -fnext-runtime} \ +] + foreach src $tests { + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $src] then { + continue + } + lto-execute $src $sid + } +} + +lto_finish diff --git a/gcc/testsuite/objc.dg/lto/trivial-1_0.m b/gcc/testsuite/objc.dg/lto/trivial-1_0.m new file mode 100644 index 000000000..076f2306c --- /dev/null +++ b/gcc/testsuite/objc.dg/lto/trivial-1_0.m @@ -0,0 +1,37 @@ +/* { dg-lto-do run } */ +/* { dg-skip-if "" { "*-*-darwin*" && lp64 } { "*" } { "" } } */ +extern int printf (char *,...) ; + +typedef struct objc_class *Class; + +struct objc_class { + Class isa; + /* other stuff... */ +} ; + +@interface myRootObject { +@public + Class isa; +} ++initialize; ++(Class)class; + +@end + +@implementation myRootObject ++initialize { + return self; +} + ++(Class)class { + return (Class)self; +} + +@end + +int main(void) +{ + [myRootObject class]; + printf("trivial OK\n"); + return 0; +} diff --git a/gcc/testsuite/objc.dg/member-1.m b/gcc/testsuite/objc.dg/member-1.m new file mode 100644 index 000000000..4c7b5ae35 --- /dev/null +++ b/gcc/testsuite/objc.dg/member-1.m @@ -0,0 +1,5 @@ +void foo() +{ + struct A a; /* { dg-error "storage size" } */ + a.i; +} diff --git a/gcc/testsuite/objc.dg/method-1.m b/gcc/testsuite/objc.dg/method-1.m new file mode 100644 index 000000000..194c64fac --- /dev/null +++ b/gcc/testsuite/objc.dg/method-1.m @@ -0,0 +1,30 @@ +/* Tests of duplication. */ +/* { dg-do compile } */ + +@interface class1 +- (int) meth1; /* { dg-message "previous declaration" } */ +- (void) meth1; /* { dg-error "duplicate declaration of method .\\-meth1." } */ +@end + +@interface class2 ++ (void) meth1; /* { dg-message "previous declaration" } */ ++ (int) meth1; /* { dg-error "duplicate declaration of method .\\+meth1." } */ +@end + +@interface class3 +- (int) meth1; +@end + +@implementation class3 +- (int) meth1 { return 0; } /* { dg-message "previous definition" } */ +- (int) meth1 { return 0; } /* { dg-error "redefinition of" } */ +@end + +@interface class4 ++ (void) meth1; +@end + +@implementation class4 ++ (void) meth1 {} /* { dg-message "previous definition" } */ ++ (void) meth1 {} /* { dg-error "redefinition of" } */ +@end diff --git a/gcc/testsuite/objc.dg/method-10.m b/gcc/testsuite/objc.dg/method-10.m new file mode 100644 index 000000000..442df690a --- /dev/null +++ b/gcc/testsuite/objc.dg/method-10.m @@ -0,0 +1,35 @@ +/* When there is only one candidate method available, make sure the + compiler uses its argument/return types when constructing the + message sends (so that proper C/C++ argument conversions may + take place). */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +static double d = 4.5920234e2; + +@interface Foo : Object +-(void) brokenType: (int)x floatingPoint: (double)y; +@end + + +@implementation Foo +-(void) brokenType: (int)x floatingPoint: (double)y +{ + CHECK_IF(x == 459); + CHECK_IF(y == d); +} +@end + +int main(void) +{ + Foo *foo=[Foo new]; + [foo brokenType: d floatingPoint: d]; + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/method-11.m b/gcc/testsuite/objc.dg/method-11.m new file mode 100644 index 000000000..ddd0121b0 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-11.m @@ -0,0 +1,33 @@ +/* Ensure that we indeed cannot obtain the value of a message send + if the chosen method signature returns 'void'. There used to + exist a cheesy hack that allowed it. While at it, check that + the first lexically occurring method signature gets picked + when sending messages to 'id'. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface Object1 +- (void)initWithData:(Object1 *)data; +@end + +@interface Object2 +- (id)initWithData:(Object1 *)data; +@end + +@interface Object3 +- (id)initWithData:(Object2 *)data; +@end + +void foo(void) { + id obj1, obj2 = 0; + obj2 = [obj1 initWithData: obj2]; + /* { dg-warning "multiple methods named .\\-initWithData:. found" "" { target *-*-* } 25 } */ + /* { dg-message "using .\\-\\(void\\)initWithData:\\(Object1 \\*\\)data." "" { target *-*-* } 12 } */ + /* { dg-message "also found .\\-\\(id\\)initWithData:\\(Object1 \\*\\)data." "" { target *-*-* } 16 } */ + /* { dg-message "also found .\\-\\(id\\)initWithData:\\(Object2 \\*\\)data." "" { target *-*-* } 20 } */ + + /* The following error is a consequence of picking the "wrong" method signature. */ + /* { dg-error "void value not ignored as it ought to be" "" { target *-*-* } 25 } */ +} diff --git a/gcc/testsuite/objc.dg/method-12.m b/gcc/testsuite/objc.dg/method-12.m new file mode 100644 index 000000000..411caac11 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-12.m @@ -0,0 +1,25 @@ +/* Contributed by Igor Seleznev <selez@mail.ru>. */ +/* This used to be broken. */ + +#include <objc/objc.h> + +@interface A ++ (A *)currentContext; +@end + +@interface B ++ (B *)currentContext; +@end + +int main() +{ + [A currentContext]; /* { dg-bogus "multiple declarations" } */ + return 0; +} + +@implementation A ++ (A *)currentContext { return nil; } +@end +@implementation B ++ (B *)currentContext { return nil; } +@end diff --git a/gcc/testsuite/objc.dg/method-13.m b/gcc/testsuite/objc.dg/method-13.m new file mode 100644 index 000000000..b3e44bd25 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-13.m @@ -0,0 +1,78 @@ +/* Test if instance methods of root classes are used as class methods, if no + "real" methods are found. For receivers of type 'id' and 'Class', all + root classes must be considered. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <objc/objc.h> + +#ifdef __NEXT_RUNTIME__ +#define OBJC_GETCLASS objc_getClass +#else +#define OBJC_GETCLASS objc_get_class +#endif + +extern void abort(void); +extern int strcmp(const char *, const char *); +#define CHECK_IF(expr) if(!(expr)) abort() + +@protocol Proto +- (const char *) method4; +@end + +@interface Root +{ Class isa; } ++ (const char *) method2; +@end + +@interface Derived: Root +- (const char *) method1; +- (const char *) method2; +- (const char *) method3; +@end + +@interface Root (Categ) +- (const char *) method3; +@end + +@implementation Root (Categ) +- (const char *) method3 { return "Root(Categ)::-method3"; } +- (const char *) method4 { return "Root(Categ)::-method4"; } +@end + +@implementation Derived +- (const char *) method1 { return "Derived::-method1"; } +- (const char *) method2 { return "Derived::-method2"; } +- (const char *) method3 { return "Derived::-method3"; } +@end + +@implementation Root +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif +- (const char *) method1 { return "Root::-method1"; } ++ (const char *) method2 { return "Root::+method2"; } +@end + +int main(void) +{ + Class obj = OBJC_GETCLASS("Derived"); + + /* None of the following should elicit compiler-time warnings. */ + + CHECK_IF(!strcmp([Root method1], "Root::-method1")); + CHECK_IF(!strcmp([Root method2], "Root::+method2")); + CHECK_IF(!strcmp([Root method3], "Root(Categ)::-method3")); + CHECK_IF(!strcmp([Root method4], "Root(Categ)::-method4")); + CHECK_IF(!strcmp([Derived method1], "Root::-method1")); + CHECK_IF(!strcmp([Derived method2], "Root::+method2")); + CHECK_IF(!strcmp([Derived method3], "Root(Categ)::-method3")); + CHECK_IF(!strcmp([Derived method4], "Root(Categ)::-method4")); + CHECK_IF(!strcmp([obj method1], "Root::-method1")); + CHECK_IF(!strcmp([obj method2], "Root::+method2")); + CHECK_IF(!strcmp([obj method3], "Root(Categ)::-method3")); + CHECK_IF(!strcmp([obj method4], "Root(Categ)::-method4")); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/method-14.m b/gcc/testsuite/objc.dg/method-14.m new file mode 100644 index 000000000..96982254a --- /dev/null +++ b/gcc/testsuite/objc.dg/method-14.m @@ -0,0 +1,17 @@ +/* Test if context-sensitive "in", "out", "byref", etc., qualifiers can be + used as method selectors. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +@interface Foo +- (void)insertNewButtonImage:(Foo *)newButtonImage in:(Foo *)buttonCell; ++ (oneway void)oneway:(int)i2 byref:(int)i3 out:(float)f4 bycopy:(float)f5; +@end + +@implementation Foo +- (void)insertNewButtonImage:(Foo *)newButtonImage in:(Foo *)buttonCell { } ++ (oneway void)oneway:(int)i2 byref:(int)i3 out:(float)f4 bycopy:(float)f5 { } +@end + +/* { dg-final { scan-assembler "insertNewButtonImage:in:" } } */ +/* { dg-final { scan-assembler "oneway:byref:out:bycopy:" } } */ diff --git a/gcc/testsuite/objc.dg/method-15.m b/gcc/testsuite/objc.dg/method-15.m new file mode 100644 index 000000000..6a5aec6ac --- /dev/null +++ b/gcc/testsuite/objc.dg/method-15.m @@ -0,0 +1,56 @@ +/* Test if prior method lookup at method @implementation time is not + overly aggressive, leading to methods being found in other classes. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@class NSString; + +@protocol NSMenuItem ++ (void)setUsesUserKeyEquivalents:(BOOL)flag; ++ (BOOL)usesUserKeyEquivalents; +@end + +@interface NSMenuItem : Object <NSMenuItem> { + @private + id _menu; +} +@end + +@interface NSResponder : Object <NSMenuItem> +{ + id _nextResponder; +} +@end + +@interface Object(NSMenuValidation) +- (BOOL)validateMenuItem:(id <NSMenuItem>)menuItem; +@end + +@interface NSResponder (NSStandardKeyBindingMethods) +- (void)insertText:(id)insertString; +- (void)doCommandBySelector:(SEL)aSelector; +@end + +@interface NSView : NSResponder +{ + id _superview; + id _subviews; +} +@end + +@interface SKTGraphicView : NSView { + @private + float _gridSpacing; +} +@end + +@implementation SKTGraphicView +- (BOOL)validateMenuItem:(NSMenuItem *)item { + return (BOOL)1; +} +- (void)insertText:(NSString *)str { +} +@end diff --git a/gcc/testsuite/objc.dg/method-16.m b/gcc/testsuite/objc.dg/method-16.m new file mode 100644 index 000000000..c8394ffbb --- /dev/null +++ b/gcc/testsuite/objc.dg/method-16.m @@ -0,0 +1,24 @@ +/* Do not warn about "slightly" mismatched method signatures if + -Wstrict-selector-match is off. */ + +/* { dg-do compile } */ +/* { dg-options "-Wno-strict-selector-match" } */ + +#include <objc/objc.h> + +@interface Base +- (id) meth1: (Base *)arg1; +- (id) window; +@end + +@interface Derived: Base +- (id) meth1: (Derived *)arg1; +- (Base *)window; +@end + +void foo(void) { + id r; + + [r meth1:r]; + [r window]; +} diff --git a/gcc/testsuite/objc.dg/method-17.m b/gcc/testsuite/objc.dg/method-17.m new file mode 100644 index 000000000..3f6d8d06a --- /dev/null +++ b/gcc/testsuite/objc.dg/method-17.m @@ -0,0 +1,26 @@ +/* Test for spurious "may or may not return a value" warnings. */ + +/* { dg-do compile } */ +/* { dg-options "-Wreturn-type -Wextra" } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@interface Foo: Object +- (id) meth1; +- (void) meth2; +@end + +extern int bar; + +@implementation Foo +- (id) meth1 { + if (bar) + return [Object new]; + return; /* { dg-warning "'return' with no value, in function returning non-void" } */ +} +- (void) meth2 { + if (!bar) + return; + bar = 0; +} /* { dg-bogus "'return' with no value, in function returning non-void" } */ +@end diff --git a/gcc/testsuite/objc.dg/method-18.m b/gcc/testsuite/objc.dg/method-18.m new file mode 100644 index 000000000..77fd3ef1b --- /dev/null +++ b/gcc/testsuite/objc.dg/method-18.m @@ -0,0 +1,29 @@ +/* Do not warn about "slightly" mismatched method signatures if + -Wstrict-selector-match is off. */ +/* { dg-do compile } */ +/* { dg-options "-Wno-strict-selector-match" } */ + +#include <objc/objc.h> + +typedef enum { en1_1, en1_2 } En1; +typedef enum { en2_1, en2_2 } En2; +typedef struct { int a, b; } St1; +typedef struct { unsigned a, b; } St2; + +@interface Base +- (id) meth1: (En1)arg1; +- (St1) window; +@end + +@interface Derived: Base +- (id) meth1: (En2)arg1; +- (St2)window; +@end + +void foo(void) { + id r; + En1 en; + + [r meth1:en]; + [r window]; +} diff --git a/gcc/testsuite/objc.dg/method-19.m b/gcc/testsuite/objc.dg/method-19.m new file mode 100644 index 000000000..362d55858 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-19.m @@ -0,0 +1,17 @@ +/* The following should NOT generate "may not respond to" warnings, since a forward-declared + @class (instance) should be treated like a 'Class') ('id'). */ + +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@class NotKnown; + +void foo(NotKnown *n) { + [NotKnown new]; + [n nonexistent_method]; /* { dg-warning "no .\\-nonexistent_method. method found" } */ +} + +/* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */ +/* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 0 } */ +/* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/objc.dg/method-2.m b/gcc/testsuite/objc.dg/method-2.m new file mode 100644 index 000000000..8bf211f87 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-2.m @@ -0,0 +1,32 @@ +/* Test for lookup of class (factory) methods. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +@interface MyBase +- (void) rootInstanceMethod; +@end + +@interface MyIntermediate: MyBase +@end + +@interface MyDerived: MyIntermediate +- (void) instanceMethod; ++ (void) classMethod; +@end + +@implementation MyDerived +- (void) instanceMethod { +} + ++ (void) classMethod { /* If a class method is not found, the root */ + [self rootInstanceMethod]; /* class is searched for an instance method */ + [MyIntermediate rootInstanceMethod]; /* with the same name. */ + + [self instanceMethod]; /* { dg-warning ".MyDerived. may not respond to .\\+instanceMethod." } */ + /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 25 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 25 } */ + /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 25 } */ + [MyDerived instanceMethod]; /* { dg-warning ".MyDerived. may not respond to .\\+instanceMethod." } */ +} +@end + diff --git a/gcc/testsuite/objc.dg/method-20.m b/gcc/testsuite/objc.dg/method-20.m new file mode 100644 index 000000000..722463ce2 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-20.m @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +/* We used to crash after we found the type for int[m] was declared as invalid. */ +/* PR objc/29197 */ + +@ implementation NGActiveSocket ++ (void) socketPair:(int[m]) _pair {} /* { dg-error "" } */ + /* { dg-warning "" "" { target *-*-* } 7 } */ +@end diff --git a/gcc/testsuite/objc.dg/method-20b.m b/gcc/testsuite/objc.dg/method-20b.m new file mode 100644 index 000000000..733d8722b --- /dev/null +++ b/gcc/testsuite/objc.dg/method-20b.m @@ -0,0 +1,45 @@ +/* Check if array and function parameters get decayed to pointers as + they should. */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m" } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include <string.h> +#include <stdlib.h> + +static char global_buf[20]; + +char *strcpy_like_callee(const char *s) { + strcpy(global_buf, s); + return global_buf; +} + +typedef char io_string_t[512]; +typedef char *(func_type)(const char *); + +@interface DeviceObject: Object +- (void) func:(func_type)func stucPathInIORegistry:(io_string_t)ioRegPath; +@end +@implementation DeviceObject +- (void) func:(func_type)func stucPathInIORegistry:(io_string_t)ioRegPath +{ + func(ioRegPath); +} +@end + +int main (void) { + io_string_t my_string; + DeviceObject *obj = [DeviceObject new]; + + strcpy (my_string, "Hello!"); + strcpy (global_buf, "Good-bye!"); + + [obj func:strcpy_like_callee stucPathInIORegistry:my_string]; + + if (strcmp (global_buf, "Hello!")) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/method-3.m b/gcc/testsuite/objc.dg/method-3.m new file mode 100644 index 000000000..abee4e065 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-3.m @@ -0,0 +1,48 @@ +/* Test for sending messages to aliased classes (and instances thereof). */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "" } */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +@interface Int1: Object ++ (int) classMeth; +- (int) instanceMeth; +@end + +@interface Int2: Object ++ (int) classMeth; +- (int) instanceMeth; +@end + +@implementation Int1 ++ (int) classMeth { return 345; } +- (int) instanceMeth { return 697; } +@end + +@implementation Int2 ++ (int) classMeth { return 1345; } +- (int) instanceMeth { return 1697; } +@end + +typedef Int1 Int1Typedef; +@compatibility_alias Int1Alias Int1Typedef; +@compatibility_alias Int2Alias Int2; +typedef Int2Alias Int2Typedef; + +int main(void) { + Int1Alias *int1alias = [[Int1Typedef alloc] init]; + Int2Typedef *int2typedef = [[Int2Alias alloc] init]; + + CHECK_IF([Int1Typedef classMeth] == 345 && [Int2Alias classMeth] == 1345); + CHECK_IF([int1alias instanceMeth] == 697 && [int2typedef instanceMeth] == 1697); + CHECK_IF([(Int2Typedef *)int1alias instanceMeth] == 697); + CHECK_IF([(Int1Alias *)int2typedef instanceMeth] == 1697); + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/method-4.m b/gcc/testsuite/objc.dg/method-4.m new file mode 100644 index 000000000..df25bba21 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-4.m @@ -0,0 +1,26 @@ +/* Check if class references (generated for the NeXT runtime) are appropriately + folded. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* The ABI is different for m64 darwin so skip this test for now */ +/* { dg-do compile { target { *-*-darwin* && { ! lp64 } } } } */ +/* { dg-skip-if "" { *-*-darwin* } { "-fgnu-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" + +typedef Object ObjectTypedef1; +typedef ObjectTypedef1 ObjectTypedef2; +@compatibility_alias ObjectAlias1 ObjectTypedef2; +@compatibility_alias ObjectAlias2 ObjectAlias1; +typedef ObjectAlias2 ObjectTypedef3; + +void foo(void) { + id obj = [Object new]; + obj = [ObjectTypedef1 new]; + obj = [ObjectTypedef2 new]; + obj = [ObjectTypedef3 new]; + obj = [ObjectAlias1 new]; + obj = [ObjectAlias2 new]; +} + +/* { dg-final { scan-assembler "_OBJC_ClassRefs_0" } } */ +/* { dg-final { scan-assembler-not "_OBJC_ClassRefs_1" } } */ diff --git a/gcc/testsuite/objc.dg/method-5.m b/gcc/testsuite/objc.dg/method-5.m new file mode 100644 index 000000000..9fa8cb6d9 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-5.m @@ -0,0 +1,20 @@ +/* Check if sending messages to "underspecified" objects is handled gracefully. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +@class UnderSpecified; +typedef struct NotAClass { + int a, b; +} NotAClass; + +void foo(UnderSpecified *u, NotAClass *n) { + [n nonexistent_method]; /* { dg-warning "invalid receiver type" } */ + /* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 11 } */ + [NotAClass nonexistent_method]; /* { dg-error ".NotAClass. is not an Objective\\-C class name or alias" } */ + [u nonexistent_method]; /* { dg-warning "no .\\-nonexistent_method. method found" } */ + [UnderSpecified nonexistent_method]; /* { dg-warning "no .\\+nonexistent_method. method found" } */ +} + +/* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */ +/* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 0 } */ +/* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/objc.dg/method-6.m b/gcc/testsuite/objc.dg/method-6.m new file mode 100644 index 000000000..c46d9c450 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-6.m @@ -0,0 +1,32 @@ +/* Check that sending messages to variables of type 'Class' does not involve instance methods, + unless they reside in root classes. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ +/* { dg-options "-Wstrict-selector-match" } */ + +#include "../objc-obj-c++-shared/Protocol1.h" + +@interface Base +- (unsigned)port; +@end + +@interface Derived: Base +- (Object *)port; ++ (Protocol *)port; +- (id)starboard; +@end + +void foo(void) { + Class receiver; + + [receiver port]; /* { dg-warning "multiple methods named .\\+port. found" } */ + /* { dg-message "using .\\-\\(unsigned( int)?\\)port." "" { target *-*-* } 10 } */ + /* { dg-message "also found .\\+\\(Protocol \\*\\)port." "" { target *-*-* } 15 } */ + + [receiver starboard]; /* { dg-warning "no .\\+starboard. method found" } */ + /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 26 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 26 } */ + /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 26 } */ + + [Class port]; /* { dg-error ".Class. is not an Objective\\-C class name or alias" } */ +} diff --git a/gcc/testsuite/objc.dg/method-7.m b/gcc/testsuite/objc.dg/method-7.m new file mode 100644 index 000000000..d7a7b97b7 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-7.m @@ -0,0 +1,29 @@ +/* Check if finding multiple signatures for a method is handled gracefully. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ +/* { dg-options "-Wstrict-selector-match" } */ + + +#include "../objc-obj-c++-shared/Object1.h" + +@interface Class1 +- (void)setWindow:(Object *)wdw; +@end + +@interface Class2 +- (void)setWindow:(Class1 *)window; +@end + +id foo(void) { + Object *obj = [[Object alloc] init]; + id obj2 = obj; + [obj setWindow:nil]; /* { dg-warning ".Object. may not respond to .\\-setWindow:." } */ + /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 20 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 20 } */ + /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 20 } */ + [obj2 setWindow:nil]; /* { dg-warning "multiple methods named .\\-setWindow:. found" } */ + /* { dg-message "using .\\-\\(void\\)setWindow:\\(Object \\*\\)wdw." "" { target *-*-* } 10 } */ + /* { dg-message "also found .\\-\\(void\\)setWindow:\\(Class1 \\*\\)window." "" { target *-*-* } 14 } */ + + return obj; +} diff --git a/gcc/testsuite/objc.dg/method-8.m b/gcc/testsuite/objc.dg/method-8.m new file mode 100644 index 000000000..4a13b7d6c --- /dev/null +++ b/gcc/testsuite/objc.dg/method-8.m @@ -0,0 +1,14 @@ +/* Check if casting the receiver type causes method lookup to succeed. This was broken + in Objective-C++. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ + +@interface A +@end + +@interface B: A +- (void)f; +@end + +void g(A *p) { [(B *)p f]; } + diff --git a/gcc/testsuite/objc.dg/method-9.m b/gcc/testsuite/objc.dg/method-9.m new file mode 100644 index 000000000..d755d6ad8 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-9.m @@ -0,0 +1,45 @@ +/* Check if finding multiple signatures for a method is handled gracefully + when method lookup succeeds (see also method-7.m). */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ +/* { dg-options "-Wstrict-selector-match" } */ + + +#include "../objc-obj-c++-shared/Object1.h" + +@protocol MyObject +- (id)initWithData:(Object *)data; +@end + +@protocol SomeOther +- (id)initWithData:(int)data; +@end + +@protocol MyCoding +- (id)initWithData:(id<MyObject, MyCoding>)data; +@end + +@interface NTGridDataObject: Object <MyCoding> +{ + Object<MyCoding> *_data; +} ++ (NTGridDataObject*)dataObject:(id<MyObject, MyCoding>)data; +@end + +@implementation NTGridDataObject +- (id)initWithData:(id<MyObject, MyCoding>)data { + return data; +} ++ (NTGridDataObject*)dataObject:(id<MyObject, MyCoding>)data +{ + NTGridDataObject *result = [[NTGridDataObject alloc] initWithData:data]; + /* { dg-warning "multiple methods named .\\-initWithData:. found" "" { target *-*-* } 35 } */ + /* { dg-message "using .\\-\\(id\\)initWithData:\\(Object \\*\\)data." "" { target *-*-* } 11 } */ + /* { dg-message "also found .\\-\\(id\\)initWithData:\\(id <MyObject, MyCoding>\\)data." "" { target *-*-* } 19 } */ + /* { dg-message "also found .\\-\\(id\\)initWithData:\\(int\\)data." "" { target *-*-* } 15 } */ + + /* The following warning is a consequence of picking the "wrong" method signature. */ + /* { dg-warning "passing argument 1 of .initWithData:. from distinct Objective\\-C type" "" { target *-*-* } 35 } */ + return result; +} +@end diff --git a/gcc/testsuite/objc.dg/method-conflict-1.m b/gcc/testsuite/objc.dg/method-conflict-1.m new file mode 100644 index 000000000..2cc96e4fd --- /dev/null +++ b/gcc/testsuite/objc.dg/method-conflict-1.m @@ -0,0 +1,26 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test that you can not declare two methods, in the same protocol, + with the same name but conflicting method signatures. */ + +@protocol MyProtocol ++ (int) method1: (int)x; /* { dg-message "previous declaration" } */ ++ (float) method1: (int)x; /* { dg-error "duplicate declaration of method .\\+method1." } */ + +- (int) method2: (int)x; /* { dg-message "previous declaration" } */ +- (int) method2: (float)x; /* { dg-error "duplicate declaration of method .\\-method2." } */ + +@optional ++ (int *) method3: (int)x; /* { dg-message "previous declaration" } */ ++ (int *) method3: (int **)x; /* { dg-error "duplicate declaration of method .\\+method3." } */ + +- (id) method4: (id)x; /* { dg-message "previous declaration" } */ +- (void) method4: (id)x; /* { dg-error "duplicate declaration of method .\\-method4." } */ +@end + +/* We don't test conflicting types between @required and @optional + methods, as that is tested in method-conflict-2. */ + diff --git a/gcc/testsuite/objc.dg/method-conflict-2.m b/gcc/testsuite/objc.dg/method-conflict-2.m new file mode 100644 index 000000000..0b0612d77 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-conflict-2.m @@ -0,0 +1,34 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test that you can not declare two methods, in the same protocol, + with the same name and method signature, but one as @required and + once as @optional. */ + +/* First, @required conflicting with @optional. */ +@protocol MyProtocol + +@optional ++ (void) method1: (id)x; /* { dg-message "previous declaration" } */ +- (id) method2: (long)x; /* { dg-message "previous declaration" } */ + +@required ++ (void) method1: (id)x; /* { dg-error "declared .@optional. and .@required. at the same time" } */ +- (id) method2: (long)x; /* { dg-error "declared .@optional. and .@required. at the same time" } */ + +@end + +/* Second, @optional conflicting with @required. */ +@protocol MyProtocol2 + +@required ++ (void) method3: (Class)x; /* { dg-message "previous declaration" } */ +- (id *) method4: (long)x; /* { dg-message "previous declaration" } */ + +@optional ++ (void) method3: (Class)x; /* { dg-error "declared .@optional. and .@required. at the same time" } */ +- (id *) method4: (long)x; /* { dg-error "declared .@optional. and .@required. at the same time" } */ + +@end diff --git a/gcc/testsuite/objc.dg/method-conflict-3.m b/gcc/testsuite/objc.dg/method-conflict-3.m new file mode 100644 index 000000000..cc4d2631f --- /dev/null +++ b/gcc/testsuite/objc.dg/method-conflict-3.m @@ -0,0 +1,63 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test that the compiler can correctly compare protocols in types of + method signatures. */ + +@protocol A, B, C; + +@interface MyClass +- (void) method1: (id)x; +- (void) method1: (id)x; /* Ok */ + +- (void) method2: (id <A>)x; +- (void) method2: (id <A>)x; /* Ok */ + +- (void) method3: (id <A, B>)x; +- (void) method3: (id <A, B>)x; /* Ok */ + +- (void) method4: (id <A, B>)x; +- (void) method4: (id <A, B, B>)x; /* Ok */ + +- (void) method5: (id <A, A, B>)x; +- (void) method5: (id <A, B, B>)x; /* Ok */ + +- (void) method6: (id <A, A, B, B, C, C>)x; +- (void) method6: (id <C, A, B>)x; /* Ok */ + +- (void) method7: (id)x; /* { dg-message "previous declaration" } */ +- (void) method7: (id <A>)x; /* { dg-error "duplicate declaration" } */ + +- (void) method8: (id <A>)x; /* { dg-message "previous declaration" } */ +- (void) method8: (id)x; /* { dg-error "duplicate declaration" } */ + +- (void) method9: (id <A>)x; /* { dg-message "previous declaration" } */ +- (void) method9: (id <B>)x; /* { dg-error "duplicate declaration" } */ + +- (void) methodA: (id <A>)x; /* { dg-message "previous declaration" } */ +- (void) methodA: (id <A, B>)x; /* { dg-error "duplicate declaration" } */ + +- (void) methodB: (id <A, B>)x; /* { dg-message "previous declaration" } */ +- (void) methodB: (id <A>)x; /* { dg-error "duplicate declaration" } */ + +- (void) methodC: (id <A, B, C>)x; /* { dg-message "previous declaration" } */ +- (void) methodC: (id <A, B>)x; /* { dg-error "duplicate declaration" } */ + +- (void) methodD: (id <A, B, C>)x; /* { dg-message "previous declaration" } */ +- (void) methodD: (id <A, B, A>)x; /* { dg-error "duplicate declaration" } */ + +- (void) methodE: (MyClass <A, B, C> *)x; /* { dg-message "previous declaration" } */ +- (void) methodE: (MyClass <A, B, A> *)x; /* { dg-error "duplicate declaration" } */ + +- (void) methodF: (MyClass <A, B, A> *)x; +- (void) methodF: (MyClass <A, B, A> *)x; /* Ok */ + +- (void) methodG: (MyClass *)x; /* { dg-message "previous declaration" } */ +- (void) methodG: (MyClass <A, B, C> *)x; /* { dg-error "duplicate declaration" } */ + +- (void) methodH: (MyClass <A, C>*)x; /* { dg-message "previous declaration" } */ +- (void) methodH: (MyClass *)x; /* { dg-error "duplicate declaration" } */ + +@end diff --git a/gcc/testsuite/objc.dg/method-conflict-4.m b/gcc/testsuite/objc.dg/method-conflict-4.m new file mode 100644 index 000000000..a0c278294 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-conflict-4.m @@ -0,0 +1,47 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test that the compiler can correctly compare protocols in types of + method signatures. In this test we look at protocols implementing + other protocols. The fact that one protocol implements another one + doesn't mean that they are identical. */ + +@protocol A +- (void) doSomething; +@end + +@protocol B <A> +- (void) doSomethingElse; +@end + +@protocol C <A> +- (void) doYetSomethingElse; +@end + +@interface MyClass2 +- (void) aMethod: (id <A>)x; /* { dg-message "previous declaration" } */ +- (void) aMethod: (id <B>)x; /* { dg-error "duplicate declaration" } */ + +- (void) bMethod: (id <B>)x; /* { dg-message "previous declaration" } */ +- (void) bMethod: (id <A>)x; /* { dg-error "duplicate declaration" } */ + +- (void) cMethod: (id <A, B>)x; +- (void) cMethod: (id <B>)x; /* Ok - because if you implement B, then you also implement A, so <B> == <A, B> */ + +- (void) dMethod: (id <A, B>)x; +- (void) dMethod: (id <B, A>)x; /* Ok */ + +- (void) eMethod: (id <A>)x; /* { dg-message "previous declaration" } */ +- (void) eMethod: (id <B, C>)x; /* { dg-error "duplicate declaration" } */ + +- (void) fMethod: (id <B, C>)x; /* { dg-message "previous declaration" } */ +- (void) fMethod: (id <A>)x; /* { dg-error "duplicate declaration" } */ + +- (void) gMethod: (id <A>)x; /* { dg-message "previous declaration" } */ +- (void) gMethod: (id <A, B, C>)x; /* { dg-error "duplicate declaration" } */ + +- (void) hMethod: (id <A, B, C>)x; /* { dg-message "previous declaration" } */ +- (void) hMethod: (id <A>)x; /* { dg-error "duplicate declaration" } */ +@end diff --git a/gcc/testsuite/objc.dg/missing-proto-1.m b/gcc/testsuite/objc.dg/missing-proto-1.m new file mode 100644 index 000000000..7132ead4b --- /dev/null +++ b/gcc/testsuite/objc.dg/missing-proto-1.m @@ -0,0 +1,6 @@ +/* Test for graceful handling of missing protocol declarations. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +@interface Foo <Missing> /* { dg-error "cannot find protocol declaration for .Missing." } */ +@end diff --git a/gcc/testsuite/objc.dg/missing-proto-2.m b/gcc/testsuite/objc.dg/missing-proto-2.m new file mode 100644 index 000000000..cb121b496 --- /dev/null +++ b/gcc/testsuite/objc.dg/missing-proto-2.m @@ -0,0 +1,5 @@ +/* Test for graceful handling of missing protocol declarations. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +void *protRef = @protocol(Missing); /* { dg-error "cannot find protocol declaration for .Missing." } */ diff --git a/gcc/testsuite/objc.dg/missing-proto-3.m b/gcc/testsuite/objc.dg/missing-proto-3.m new file mode 100644 index 000000000..6c610ce35 --- /dev/null +++ b/gcc/testsuite/objc.dg/missing-proto-3.m @@ -0,0 +1,26 @@ +/* Ensure that the compiler gracefully handles missing protocol declarations. + In addition to not crashing :-), the compiler should properly handle + valid protocol references, even when they're mixed with invalid ones. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@protocol DefinedProtocol +- (id) missingMethod1; +@end + +@interface MyClass <UndefinedProtocol, DefinedProtocol> +/* { dg-error "cannot find protocol declaration for .UndefinedProtocol." "" { target *-*-* } 12 } */ +@end + +@implementation MyClass ++(Class)class +{ + return self; +} +@end + +/* { dg-warning "incomplete implementation of class .MyClass." "" { target *-*-* } 21 } */ +/* { dg-warning "method definition for .\\-missingMethod1. not found" "" { target *-*-* } 21 } */ +/* { dg-warning "class .MyClass. does not fully implement the .DefinedProtocol. protocol" "" { target *-*-* } 21 } */ + diff --git a/gcc/testsuite/objc.dg/msg-in-protocol.m b/gcc/testsuite/objc.dg/msg-in-protocol.m new file mode 100644 index 000000000..86b7c85a3 --- /dev/null +++ b/gcc/testsuite/objc.dg/msg-in-protocol.m @@ -0,0 +1,18 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@class Foo; + +@protocol Bar + +- (void)bang; + +@end + +void foo() +{ + Foo<Bar> *foo = nil; + [foo bang]; +} + diff --git a/gcc/testsuite/objc.dg/naming-1.m b/gcc/testsuite/objc.dg/naming-1.m new file mode 100644 index 000000000..3528961bf --- /dev/null +++ b/gcc/testsuite/objc.dg/naming-1.m @@ -0,0 +1,19 @@ +/* Test for obscuring of @interfaces with local vars. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +@interface View +@end + +void foo(void) +{ + int View; /* ok */ + View = 1; /* ok */ + View *view; /* { dg-error "undeclared|only once|it appears" } */ +} + +void bar(void) +{ + View *view; /* ok */ + View = 1; /* { dg-error "parse error|syntax error|expected" } */ +} diff --git a/gcc/testsuite/objc.dg/naming-2.m b/gcc/testsuite/objc.dg/naming-2.m new file mode 100644 index 000000000..6d087509e --- /dev/null +++ b/gcc/testsuite/objc.dg/naming-2.m @@ -0,0 +1,12 @@ +/* Test for collision of @interfaces with global vars. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +@interface Foo +@end +float Foo; /* { dg-error "parse error|syntax error|expected|redeclaration" } */ + +double Bar; +@interface Bar +@end /* { dg-error "redeclared as different kind of symbol" } */ +/* { dg-error "previous declaration of" "" { target *-*-* } 9 } */ diff --git a/gcc/testsuite/objc.dg/naming-3.m b/gcc/testsuite/objc.dg/naming-3.m new file mode 100644 index 000000000..dea388c5b --- /dev/null +++ b/gcc/testsuite/objc.dg/naming-3.m @@ -0,0 +1,17 @@ +/* Test for class name same as an unrelated struct field name. */ +/* { dg-do compile } */ +@interface PassThrough { + +} +@end + +struct S { + int (*PassThrough)(); +}; + +int main() +{ + PassThrough* pt; + struct S s; + s.PassThrough(); +} diff --git a/gcc/testsuite/objc.dg/naming-4.m b/gcc/testsuite/objc.dg/naming-4.m new file mode 100644 index 000000000..9a85229f6 --- /dev/null +++ b/gcc/testsuite/objc.dg/naming-4.m @@ -0,0 +1,27 @@ +/* Testing for detecting duplicate ivars. */ +/* { dg-do compile } */ + +typedef struct S { int i; } NSDictionary; + +@interface A +{ + NSDictionary * _userInfo; +} +@end + +@interface B : A +{ + NSDictionary * _userInfo; /* { dg-error "duplicate member" } */ + NSDictionary * _userInfo; /* { dg-error "duplicate member" } */ +} +@end + +@interface C : A +@end + +@interface D : C +{ + NSDictionary * _userInfo; /* { dg-error "duplicate member" } */ + NSDictionary * _userInfo; /* { dg-error "duplicate member" } */ +} +@end diff --git a/gcc/testsuite/objc.dg/naming-5.m b/gcc/testsuite/objc.dg/naming-5.m new file mode 100644 index 000000000..2e2786c41 --- /dev/null +++ b/gcc/testsuite/objc.dg/naming-5.m @@ -0,0 +1,42 @@ +/* Testing for detecting duplicate ivars. */ +/* { dg-do compile } */ + +typedef struct S { int i; } NSDictionary; + +@interface A +{ + NSDictionary * _userInfo; + int i1; + int i2; + int i3; + int i4; + int i5; + int i6; + int i7; +} +@end + +@interface B : A +{ + NSDictionary * _userInfo; /* { dg-error "duplicate member" } */ + int ii1; + int ii2; + int ii3; + int ii4; + int ii5; + int ii6; + int ii7; + NSDictionary * _userInfo; /* { dg-error "duplicate member" } */ +} +@end + +@interface C : A +@end + +@interface D : C +{ + NSDictionary * _userInfo; /* { dg-error "duplicate member" } */ + NSDictionary * _userInfo; /* { dg-error "duplicate member" } */ +} +@end + diff --git a/gcc/testsuite/objc.dg/next-runtime-1.m b/gcc/testsuite/objc.dg/next-runtime-1.m new file mode 100644 index 000000000..c76b6166d --- /dev/null +++ b/gcc/testsuite/objc.dg/next-runtime-1.m @@ -0,0 +1,20 @@ +/* Test that the correct version number (6) is set in the module descriptor + when compiling for the NeXT runtime ABI=0 - and that the MODULE descriptor + is not emitted at all for ABI 2. */ +/* modified from a testcase added by: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-skip-if "" { *-*-* } { "-fobjc-abi-version=1" } { "" } } */ +/* { dg-options "-fobjc-abi-version=0" { target { *-*-darwin* && { ! lp64 } } } } */ + +@interface FooBar +- (void)boo; +@end + +@implementation FooBar +- (void)boo { } +@end + +/* { dg-final { scan-assembler "L_OBJC_Module:\n\[ \t\]*\.long\t6\n" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler-not "L_OBJC_Module" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/no-extra-load.m b/gcc/testsuite/objc.dg/no-extra-load.m new file mode 100644 index 000000000..750353579 --- /dev/null +++ b/gcc/testsuite/objc.dg/no-extra-load.m @@ -0,0 +1,7 @@ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ + +#import <Foundation/Foundation.h> +main() { [NSObject new]; } + +/* { dg-final { scan-assembler-not "L_objc_msgSend\\\$non_lazy_ptr" } } */ diff --git a/gcc/testsuite/objc.dg/objc-fast-4.m b/gcc/testsuite/objc.dg/objc-fast-4.m new file mode 100644 index 000000000..b86e39529 --- /dev/null +++ b/gcc/testsuite/objc.dg/objc-fast-4.m @@ -0,0 +1,12 @@ +/* The code should call objc_msgSend directly, not through a pointer. */ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-options "-O0" } */ +/* Radar 4015820 */ + +#include "../objc-obj-c++-shared/Object1.h" + +void foo(void) { + Object *o; + [o++ free]; +} +/* { dg-final { scan-assembler-not "L_objc_msgSend\\\$non_lazy_ptr" } } */ diff --git a/gcc/testsuite/objc.dg/objc-foreach-1.m b/gcc/testsuite/objc.dg/objc-foreach-1.m new file mode 100644 index 000000000..81f5dae0c --- /dev/null +++ b/gcc/testsuite/objc.dg/objc-foreach-1.m @@ -0,0 +1,41 @@ +/* Syntax check for the new foreach statement. */ +/* { dg-do compile } */ + +typedef struct objc_class *Class; + +typedef struct objc_object { + Class isa; +} *id; + + +@interface MyList +@end + +@implementation MyList +- (unsigned int)countByEnumeratingWithState:(struct __objcFastEnumerationState *)state objects:(id *)items count:(unsigned int)stackcount +{ + return 0; +} +- (void)addObject:object { +} + +@end + +@interface MyList (BasicTest) +- (void)compilerTestAgainst; +@end +void BEGIN(); +void INFORLOOP(); +void END(); +@implementation MyList (BasicTest) +- (void)compilerTestAgainst { + + BEGIN(); + for (id elem in (self)) + if (elem) + INFORLOOP(); + + END(); +} +@end + diff --git a/gcc/testsuite/objc.dg/objc-foreach-2.m b/gcc/testsuite/objc.dg/objc-foreach-2.m new file mode 100644 index 000000000..a01f004fe --- /dev/null +++ b/gcc/testsuite/objc.dg/objc-foreach-2.m @@ -0,0 +1,41 @@ +/* Syntax check for the new foreach statement. */ +/* { dg-do compile } */ + +typedef struct objc_class *Class; + +typedef struct objc_object { + Class isa; +} *id; + + +@interface MyList +@end + +@implementation MyList +- (unsigned int)countByEnumeratingWithState:(struct __objcFastEnumerationState *)state objects:(id *)items count:(unsigned int)stackcount +{ + return 0; +} +- (void)addObject:object { +} + +@end + +@interface MyList (BasicTest) +- (void)compilerTestAgainst; +@end +void BEGIN(); +void INFORLOOP(); +void END(); +@implementation MyList (BasicTest) +- (void)compilerTestAgainst { + + id elem; + BEGIN(); + for (elem in (self)) + if (elem) + INFORLOOP(); + END(); +} +@end + diff --git a/gcc/testsuite/objc.dg/objc-foreach-3.m b/gcc/testsuite/objc.dg/objc-foreach-3.m new file mode 100644 index 000000000..922db39e7 --- /dev/null +++ b/gcc/testsuite/objc.dg/objc-foreach-3.m @@ -0,0 +1,42 @@ +/* Syntax check for the new foreach statement. + Use of declaration in loop-header without requiring c99 mode. */ +/* { dg-do compile } */ + +typedef struct objc_class *Class; + +typedef struct objc_object { + Class isa; +} *id; + + +@interface MyList +@end + +@implementation MyList +- (unsigned int)countByEnumeratingWithState:(struct __objcFastEnumerationState *)state objects:(id *)items count:(unsigned int)stackcount +{ + return 0; +} +- (void)addObject:object { +} + +@end + +@interface MyList (BasicTest) +- (void)compilerTestAgainst; +@end +void BEGIN(); +void INFORLOOP(); +void END(); +@implementation MyList (BasicTest) +- (void)compilerTestAgainst { + + BEGIN(); + for (id elem in (self)) + if (elem) + INFORLOOP(); + + END(); +} +@end + diff --git a/gcc/testsuite/objc.dg/objc-foreach-4.m b/gcc/testsuite/objc.dg/objc-foreach-4.m new file mode 100644 index 000000000..292a90885 --- /dev/null +++ b/gcc/testsuite/objc.dg/objc-foreach-4.m @@ -0,0 +1,26 @@ +/* Test for valid objc objects used in a for-each statement. */ +/* FIXME: Run this test with the GNU runtime as well. */ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-skip-if "No NeXT fast enum. pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ + +#include <objc/objc-api.h> +#include <Foundation/Foundation.h> + +#if defined (__NEXT_RUNTIME__) && defined (__LP64__) +/* Fudge the class reference until we implement the compiler-side + const strings. */ +extern void *_NSConstantStringClassReference; +#endif + +// gcc -o foo foo.m -framework Foundation + +int main (int argc, char const* argv[]) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + NSArray * arr = [NSArray arrayWithObjects:@"A", @"B", @"C", nil]; + for (NSString * foo in arr) { + NSLog(@"foo is %@", foo); + } + [pool release]; + return 0; +} diff --git a/gcc/testsuite/objc.dg/objc-foreach-5.m b/gcc/testsuite/objc.dg/objc-foreach-5.m new file mode 100644 index 000000000..cb1578199 --- /dev/null +++ b/gcc/testsuite/objc.dg/objc-foreach-5.m @@ -0,0 +1,39 @@ +/* FIXME: Run this test with the GNU runtime as well. */ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-skip-if "No NeXT fast enum. pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ + +#import <Foundation/Foundation.h> + +NSArray * createTestVictim(unsigned capacity) { + NSMutableArray * arr = [[NSMutableArray alloc] initWithCapacity:capacity]; + int x = 0; + + for(x = 0; x < capacity; x++) { + NSNumber * num = [NSNumber numberWithInteger:x]; + [arr addObject:num]; + } + + NSArray * immutableCopy = [arr copy]; + [arr release]; + + return immutableCopy; +} + +void addStuffUp(NSArray * values) { + NSInteger accumulator = 0; +// for (id item in values) { + id item; + for (item in values) { + accumulator += [item integerValue]; + } +} + +int main (int argc, char const* argv[]) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + NSArray * target = createTestVictim(10); + addStuffUp(target); + [pool release]; + return 0; +} +/* { dg-final { scan-assembler "_addStuffUp:" } } */ diff --git a/gcc/testsuite/objc.dg/objc-gc-4.m b/gcc/testsuite/objc.dg/objc-gc-4.m new file mode 100644 index 000000000..097f35e9f --- /dev/null +++ b/gcc/testsuite/objc.dg/objc-gc-4.m @@ -0,0 +1,64 @@ +/* Test looking up fields in superclasses in the context of write-barriers + (where component references get rewritten). */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile } */ +/* { dg-options "-fobjc-gc" } */ +/* { dg-prune-output "cc1obj: warning: '-fobjc-gc' is ignored for '-fgnu-runtime'" } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@class MyWindow; + +@interface MyDocument : Object { + MyWindow *_window; +} +@end + +@interface MyFileDocument : MyDocument { + struct { + unsigned int autoClose:1; + unsigned int openForUI:1; + unsigned int isClosing:1; + unsigned int needsDiskCheck:1; + unsigned int isWritable:1; + unsigned int representsFileOnDisk:1; + unsigned int RESERVED:26; + } _fdFlags; +} +@end + +@interface MyTextFileDocument : MyFileDocument { + Object *_textStorage; + struct __tfdFlags { + unsigned int immutable:1; + unsigned int lineEnding:2; + unsigned int isClosing:1; + unsigned int settingsAreSet:1; + unsigned int usesTabs:1; + unsigned int isUTF8WithBOM:1; + unsigned int wrapsLines:1; + unsigned int usingDefaultLanguage:1; + unsigned int RESERVED:23; + } _tfdFlags; + int _tabWidth; + int _indentWidth; +} +@end + +@interface MyRTFFileDocument : MyTextFileDocument +- (BOOL)readFromFile:(const char *)fileName ofType:(const char *)type; +@end + +@implementation MyRTFFileDocument +- (BOOL)readFromFile:(const char *)fileName ofType:(const char *)type { + if (_textStorage && fileName) { + [_textStorage free]; + return YES; + } else if (type) { + _textStorage = [MyRTFFileDocument new]; + return NO; + } + return (fileName && type); +} +@end diff --git a/gcc/testsuite/objc.dg/objc-nofilename-1.m b/gcc/testsuite/objc.dg/objc-nofilename-1.m new file mode 100644 index 000000000..21e0c53b7 --- /dev/null +++ b/gcc/testsuite/objc.dg/objc-nofilename-1.m @@ -0,0 +1,22 @@ +/* Test to make sure that file name does not appear in the binary. */ +/* { dg-do compile { target *-*-darwin* } } */ + +#include <objc/objc.h> + +@interface Foo { Class isa; } @end +@implementation Foo @end + +@interface Bar : Foo { Class Barisa; } @end + +@implementation Bar : Foo @end; + +@interface FINAL : Bar { Class FINALisa; } @end + +@implementation FINAL : Bar @end; + +int main(int argc, char **argv) +{ + return 0; +} + +/* { dg-final { scan-assembler-not "objc-nofilename-1.m" } } */ diff --git a/gcc/testsuite/objc.dg/param-1.m b/gcc/testsuite/objc.dg/param-1.m new file mode 100644 index 000000000..e796a3b51 --- /dev/null +++ b/gcc/testsuite/objc.dg/param-1.m @@ -0,0 +1,20 @@ +/* Test if compiler detects object as an parameter to a method + or not. It is not valid. */ +/* { dg-do compile } */ + +@interface foo +@end + +@implementation foo +@end + +@interface bar +-(void) my_method:(foo) my_param; /* { dg-error "can not use an object as parameter to a method" } */ +@end + +@implementation bar +-(void) my_method:(foo) my_param /* { dg-error "can not use an object as parameter to a method" } */ +{ +} +@end + diff --git a/gcc/testsuite/objc.dg/pch/interface-1.hs b/gcc/testsuite/objc.dg/pch/interface-1.hs new file mode 100644 index 000000000..fe5255af1 --- /dev/null +++ b/gcc/testsuite/objc.dg/pch/interface-1.hs @@ -0,0 +1,4 @@ +@interface TestClass ++ (int) test; +@end + diff --git a/gcc/testsuite/objc.dg/pch/interface-1.m b/gcc/testsuite/objc.dg/pch/interface-1.m new file mode 100644 index 000000000..9bc7ef3a2 --- /dev/null +++ b/gcc/testsuite/objc.dg/pch/interface-1.m @@ -0,0 +1,14 @@ +#include "interface-1.h" + +@implementation TestClass ++ (int) test +{ + return 0; +} +@end + +int main (void) +{ + return [TestClass test]; +} + diff --git a/gcc/testsuite/objc.dg/pch/pch.exp b/gcc/testsuite/objc.dg/pch/pch.exp new file mode 100644 index 000000000..0fca64125 --- /dev/null +++ b/gcc/testsuite/objc.dg/pch/pch.exp @@ -0,0 +1,64 @@ +# Copyright (C) 1997, 2002, 2003, 2007, 2008, 2010 +# Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# GCC testsuite for precompiled header interaction, +# that uses the `dg.exp' driver. + +# Load support procs. +load_lib objc-dg.exp +load_lib dg-pch.exp +load_lib torture-options.exp + +# Initialize `dg'. +dg-init + +torture-init + +set-torture-options $DG_TORTURE_OPTIONS + +set old_dg_do_what_default "${dg-do-what-default}" + +global torture_without_loops +set mytorture [concat [list {-O0 -g}] $torture_without_loops] + +# Main loop. +foreach test [lsort [glob -nocomplain $srcdir/$subdir/*.m]] { + + # We don't try to use the loop-optimizing options, since they are highly + # unlikely to make any difference to PCH. However, we do want to + # add -O0 -g, since users who want PCH usually want debugging and quick + # compiles. + dg-flags-pch $subdir $test "-fgnu-runtime" $mytorture ".h" +} + +if [istarget "*-*-darwin*" ] { + foreach test [lsort [glob -nocomplain $srcdir/$subdir/*.m]] { + global torture_without_loops + + # We don't try to use the loop-optimizing options, since they are highly + # unlikely to make any difference to PCH. However, we do want to + # add -O0 -g, since users who want PCH usually want debugging and quick + # compiles. + dg-flags-pch $subdir $test "-fnext-runtime" $mytorture ".h" + } +} + +set dg-do-what-default "$old_dg_do_what_default" + +# All done. +torture-finish +dg-finish diff --git a/gcc/testsuite/objc.dg/pr18255.m b/gcc/testsuite/objc.dg/pr18255.m new file mode 100644 index 000000000..c9bb87c67 --- /dev/null +++ b/gcc/testsuite/objc.dg/pr18255.m @@ -0,0 +1,24 @@ +/* This is a test for a GNU Objective-C Runtime library bug. */ +/* { dg-do run } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +#include <objc/Protocol.h> +#include <stdlib.h> + +@protocol a +- aMethod; +@end + + +@protocol b <a> +- bMethod; +@end + + +int main (int argc, char **argv) +{ + if ([@protocol(b) descriptionForInstanceMethod: @selector(aMethod)] == NULL) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/pr23214.m b/gcc/testsuite/objc.dg/pr23214.m new file mode 100644 index 000000000..d8092a806 --- /dev/null +++ b/gcc/testsuite/objc.dg/pr23214.m @@ -0,0 +1,38 @@ +/* Test that there is no problem initializing multiple static + Protocol instances. */ + +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <objc/Protocol.h> + +#ifdef __OBJC2__ +/* The ObjC V2 "Object" does not provide -class. */ +@interface Object (TS_CAT) +- class; +@end + +@implementation Object (TS_CAT) +- class { return isa; } +@end +#endif + +@protocol A +@end + +@protocol B +@end + +@interface Dummy : Object <B> +@end + +int main () +{ + [@protocol(A) class]; + [@protocol(B) class]; + + return 0; +} + +@implementation Dummy +@end diff --git a/gcc/testsuite/objc.dg/pr23709.m b/gcc/testsuite/objc.dg/pr23709.m new file mode 100644 index 000000000..7ff9b6052 --- /dev/null +++ b/gcc/testsuite/objc.dg/pr23709.m @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +@interface A ++(void)method: (int)parameter {} /* { dg-error "expected" } */ +@end + +@implementation A ++(void)method: (int)parameter +{ + *parameter; /* { dg-error "invalid type argument" } */ +} +@end diff --git a/gcc/testsuite/objc.dg/pr24393.m b/gcc/testsuite/objc.dg/pr24393.m new file mode 100644 index 000000000..269d84d9c --- /dev/null +++ b/gcc/testsuite/objc.dg/pr24393.m @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +#include <objc/objc.h> + +@interface Foo +{ + Class isa; +} +- (void) doSomething:(id object; /* { dg-error "xpected .\\)." } */ +- (void) someOtherMethod; +@end diff --git a/gcc/testsuite/objc.dg/pr28049.m b/gcc/testsuite/objc.dg/pr28049.m new file mode 100644 index 000000000..d5ba4a10b --- /dev/null +++ b/gcc/testsuite/objc.dg/pr28049.m @@ -0,0 +1,2 @@ +/* { dg-do compile } */ ++ /* { dg-error "expected" } */ diff --git a/gcc/testsuite/objc.dg/pr28050.m b/gcc/testsuite/objc.dg/pr28050.m new file mode 100644 index 000000000..efd9216f7 --- /dev/null +++ b/gcc/testsuite/objc.dg/pr28050.m @@ -0,0 +1,2 @@ +/* { dg-do compile } */ +int i = [0]; /* { dg-error "expected .:. before .\\]. token" } */ diff --git a/gcc/testsuite/objc.dg/pr44509.m b/gcc/testsuite/objc.dg/pr44509.m new file mode 100644 index 000000000..7c50bd0fc --- /dev/null +++ b/gcc/testsuite/objc.dg/pr44509.m @@ -0,0 +1,9 @@ +/* PR bootstrap/44509 */ +/* { dg-do compile } */ +/* { dg-options "--param ggc-min-expand=0 --param ggc-min-heapsize=0" } */ + +double +foo (void) +{ + return __DBL_MAX__ - __FLT_MAX__; +} diff --git a/gcc/testsuite/objc.dg/pr45735.m b/gcc/testsuite/objc.dg/pr45735.m new file mode 100644 index 000000000..395698bdb --- /dev/null +++ b/gcc/testsuite/objc.dg/pr45735.m @@ -0,0 +1,4 @@ +/* { dg-do compile } */ +@interface Fraction +-(void) setNumerator: (int) :(int) ; /* { dg-error "expected identifier" } */ +@end diff --git a/gcc/testsuite/objc.dg/pr45878.m b/gcc/testsuite/objc.dg/pr45878.m new file mode 100644 index 000000000..39fd6c3cd --- /dev/null +++ b/gcc/testsuite/objc.dg/pr45878.m @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fexceptions" } */ + +typedef struct objc_object { Class class_pointer; } *id; +typedef unsigned char BOOL; + +@interface Object +{ + Class isa; +} +- (BOOL)isEqual:anObject; +@end + +#ifdef __NEXT_RUNTIME__ +@interface NSConstantString: Object +{ + char *c_string; + unsigned int len; +} +@end +extern void *_NSConstantStringClassReference; +#else +@interface NXConstantString: Object +{ + char *c_string; + unsigned int len; +} +@end +#endif + +void function (void) +{ + if ([@"strings" isEqual: (id)0]) + { + ; + } +} + diff --git a/gcc/testsuite/objc.dg/pr48177.m b/gcc/testsuite/objc.dg/pr48177.m new file mode 100644 index 000000000..0d7ff2979 --- /dev/null +++ b/gcc/testsuite/objc.dg/pr48177.m @@ -0,0 +1,35 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, May 2011. */ +/* { dg-do run } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ + +#include <objc/runtime.h> +#include <stdlib.h> + +int main(int argc, void **args) +{ +#ifdef __GNU_LIBOBJC__ + /* This special test tests that, if you have a selector already + registered in the runtime with full type information, you can use + sel_registerTypedName() to get it even if you specify the type + with incorrect argframe information. This is helpful as + selectors generated by the compiler (which have correct argframe + information) are usually registered before hand-written ones + (which often have incorrect argframe information, but need the + correct one). + + Note that in this hand-written test, even the type information of + the first selector may be wrong (on this machine); but that's OK + as we'll never actually use the selectors. */ + SEL selector1 = sel_registerTypedName ("testMethod", "i8@0:4"); + SEL selector2 = sel_registerTypedName ("testMethod", "i8@8:8"); + + /* We compare the selectors using ==, not using sel_isEqual(). This + is because we are testing internals of the runtime and we know + that in the current implementation they should be identical if + the stuff is to work as expected. Don't do this at home. */ + if (selector1 != selector2) + abort (); +#endif + + return 0; +} diff --git a/gcc/testsuite/objc.dg/pragma-1.m b/gcc/testsuite/objc.dg/pragma-1.m new file mode 100644 index 000000000..e9527e39e --- /dev/null +++ b/gcc/testsuite/objc.dg/pragma-1.m @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* ??? Is there a better pragma that is handled for all targets, not + handled by the preprocessor, that would be better for testing here? */ + +@interface a {} +#pragma mark --- Output --- +@end diff --git a/gcc/testsuite/objc.dg/private-1.m b/gcc/testsuite/objc.dg/private-1.m new file mode 100644 index 000000000..a11183c8e --- /dev/null +++ b/gcc/testsuite/objc.dg/private-1.m @@ -0,0 +1,59 @@ +/* Test errors for accessing @private and @protected variables. */ +/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */ +/* { dg-do compile } */ +#include <objc/objc.h> + +@interface MySuperClass +{ +@private + int private; + +@protected + int protected; + +@public + int public; +} +- (void) test; +@end + +@implementation MySuperClass +- (void) test +{ + private = 12; /* Ok */ + protected = 12; /* Ok */ + public = 12; /* Ok */ +} +@end + + +@interface MyClass : MySuperClass +@end + +@implementation MyClass +- (void) test +{ + /* Private variables simply don't exist in the subclass. */ + private = 12; /* { dg-error "instance variable" } */ + /* { dg-message "function it appears in" "" { target *-*-* } { 37 } } */ + + protected = 12; /* Ok */ + public = 12; /* Ok */ +} +@end + +int main (void) +{ + MyClass *m = nil; + + if (m != nil) + { + int access; + + access = m->private; /* { dg-warning "is @private" } */ + access = m->protected; /* { dg-warning "is @protected" } */ + access = m->public; /* Ok */ + } + + return 0; +} diff --git a/gcc/testsuite/objc.dg/private-2.m b/gcc/testsuite/objc.dg/private-2.m new file mode 100644 index 000000000..eff376a0c --- /dev/null +++ b/gcc/testsuite/objc.dg/private-2.m @@ -0,0 +1,54 @@ +/* Test warnings for shadowing instance variables. */ +/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */ +/* { dg-do compile } */ +#include <objc/objc.h> + +@interface MySuperClass +{ +@private + int private; + +@protected + int protected; + +@public + int public; +} +- (void) test; +@end + +@implementation MySuperClass +- (void) test +{ + /* FIXME: I wonder if the warnings shouldn't be better generated + when the variable is declared, rather than used! */ + int private = 12; + int protected = 12; + int public = 12; + int a; + + a = private; /* { dg-warning "hides instance variable" } */ + a = protected; /* { dg-warning "hides instance variable" } */ + a = public; /* { dg-warning "hides instance variable" } */ +} +@end + + +@interface MyClass : MySuperClass +@end + +@implementation MyClass +- (void) test +{ + int private = 12; + int protected = 12; + int public = 12; + int a; + + /* The private variable can be shadowed without warnings, because + * it's invisible, and not accessible, to the subclass! */ + a = private; /* Ok */ + a = protected; /* { dg-warning "hides instance variable" } */ + a = public; /* { dg-warning "hides instance variable" } */ +} +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-1.m b/gcc/testsuite/objc.dg/property/at-property-1.m new file mode 100644 index 000000000..4ff269d0f --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-1.m @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +@property; /* { dg-error "expected" } */ +@property int; /* { dg-error "expected identifier" } */ + /* { dg-warning "declaration does not declare anything" "" { target *-*-* } 10 } */ +@property int a; +@property int b, c; +@property () int d; /* { dg-error "expected identifier" } */ +@property (readonly) int e; +@property (readonly,) int f; /* { dg-error "expected identifier" } */ +@property (xxx) int g; /* { dg-error "unknown property attribute" } */ +@property (readonly,xxx) int h; /* { dg-error "unknown property attribute" } */ +@property ( int i; /* { dg-error "unknown property attribute" } */ +/* Because the last syntax error opens a '(' and never closes it, we get to the end of input. */ +@end /* { dg-error "expected ..end. at end of input" } */ diff --git a/gcc/testsuite/objc.dg/property/at-property-10.m b/gcc/testsuite/objc.dg/property/at-property-10.m new file mode 100644 index 000000000..79d2ecdbb --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-10.m @@ -0,0 +1,100 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test the property syntax in a number of expressions. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} +/* Use the simplest synthesized accessor (assign, nonatomic) as we are + not testing the synthesized accessors in this test, just the + property syntax. */ +@property (nonatomic) int a; ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize a; +@end + +int +test (int g) +{ + return g; +} + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + MyRootClass *object2 = [[MyRootClass alloc] init]; + + object.a = 14; + object.a = object.a + object.a; + + if (object.a != 28) + abort (); + + object.a = 99; + object.a++; + + if (object.a != 100) + abort (); + + object.a = 99; + object.a *= 2; + + if (object.a != 198) + abort (); + + { + int f = object.a; + + if (f != 198) + abort (); + + if (f != object.a) + abort (); + + if (object.a != f) + abort (); + + object.a = object.a; + + if (object.a != 198) + abort (); + } + + if (test (object.a) != 198) + abort (); + + object.a = -object.a; + + if (object.a != -198) + abort (); + + for (object.a = 0; object.a < 99; object.a++) + object2.a = object.a; + + if (object2.a != object.a - 1) + abort (); + + if (object2.a != 98) + abort (); + + if (object.a != 99) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-11.m b/gcc/testsuite/objc.dg/property/at-property-11.m new file mode 100644 index 000000000..33baee9d6 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-11.m @@ -0,0 +1,47 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test that properties are found even if implemented in superclasses. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} +/* Use the simplest synthesized accessor (assign, nonatomic) as we are + not testing the synthesized accessors in this test, just the + property syntax. */ +@property (nonatomic) int a; ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize a; +@end + +@interface MySubClass : MyRootClass +@end + +@implementation MySubClass +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + object.a = 40; + if (object.a != 40) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-12.m b/gcc/testsuite/objc.dg/property/at-property-12.m new file mode 100644 index 000000000..e36f57aaa --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-12.m @@ -0,0 +1,47 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test atomic, assign synthesized methods. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; + id b; +} +@property int a; +@property (assign) id b; ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize a; +@synthesize b; +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + object.a = 40; + if (object.a != 40) + abort (); + + object.b = object; + if (object.b != object) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/at-property-13.m b/gcc/testsuite/objc.dg/property/at-property-13.m new file mode 100644 index 000000000..89bf748a2 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-13.m @@ -0,0 +1,72 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test retain and copy synthesized methods. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int copy_count; + id a; + id b; +} +@property (copy) id a; +@property (retain) id b; ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (id) copyWithZone: (void *)zone; +- (int) copyCount; +- (id) autorelease; +- (oneway void) release; +- (id) retain; +@end + +/* This class implements copyWithZone, which doesn't do anything other + than increasing a counter of how many copies were made. */ +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (id) copyWithZone: (void *)zone { copy_count++; return self; } +- (int) copyCount { return copy_count; } +- (id) autorelease { return self; } +- (oneway void) release { return; } +- (id) retain { return self; } +@synthesize a; +@synthesize b; +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + MyRootClass *argument = [[MyRootClass alloc] init]; + + /* This should copy argument. */ + object.a = argument; + if (object.a != argument) + abort (); + + /* Test that it was copied. */ + if ([object.a copyCount] != 1) + abort (); + + /* We just test that the retain accessors seem to work and that they + don't copy. We don't test that retain was actually called, + because if garbage collection is enabled, it may never be + called! */ + object.b = argument; + if (object.b != argument) + abort (); + + /* Test that it was not copied. */ + if ([object.b copyCount] != 1) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-14.m b/gcc/testsuite/objc.dg/property/at-property-14.m new file mode 100644 index 000000000..ccf842b7f --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-14.m @@ -0,0 +1,20 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} + +/* Test the warnings on 'assign'. */ +@property id property_a; /* { dg-warning "object property .property.a. has no .assign., .retain. or .copy. attribute" } */ + /* { dg-message ".assign. can be unsafe for Objective-C objects" "" { target *-*-* } 12 } */ + +@property (readonly) id property_b; /* No 'assign' warning (assign semantics do not matter if the property is readonly). */ +@property id *property_c; /* No 'assign' warning (the type is not an Objective-C object). */ +@property Class property_d; /* No 'assign' warning (Classes are static objects so assign semantics do not matter for them). */ +@property MyRootClass *property_e; /* { dg-warning "object property .property.e. has no .assign., .retain. or .copy. attribute" } */ + /* { dg-message ".assign. can be unsafe for Objective-C objects" "" { target *-*-* } 18 } */ +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-15.m b/gcc/testsuite/objc.dg/property/at-property-15.m new file mode 100644 index 000000000..ef5344246 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-15.m @@ -0,0 +1,20 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wno-property-assign-default" } */ + +#include <objc/objc.h> + +/* Test that -Wno-property-assign-default turns off all "object + property xxx has no assign, return or copy attribute" warnings. */ + +@interface MyRootClass +{ + Class isa; +} + +@property id property_a; /* Would normally generate a warning. */ +@property (readonly) id property_b; +@property id *property_c; +@property Class property_d; +@property MyRootClass *property_e; /* Would normally generate a warning. */ +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-16.m b/gcc/testsuite/objc.dg/property/at-property-16.m new file mode 100644 index 000000000..95f82e41b --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-16.m @@ -0,0 +1,55 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test that if you have a property declared in a class and a + sub-class, the attributes match. */ + +@interface MyRootClass +{ + Class isa; +} +@property (assign) id a; +@property (retain) id b; +@property int c; +@property (nonatomic) int d; +@property int e; +@property int f; +@property int g; +@property (readonly) int h; +@property (readonly,getter=getMe) int i; +@end + +@interface MyClass : MyRootClass +@property (assign) id a; +@property (retain) id b; +@property int c; +@property (nonatomic) int d; +@property int e; +@property int f; +@property int g; +@property (readonly) int h; +@property (readonly,getter=getMe) int i; +@end + +@interface MyClass2 : MyRootClass +@property (retain) id a; /* { dg-warning "assign semantics attributes of property .a. conflict with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 13 } */ +@property (assign) id b; /* { dg-warning "assign semantics attributes of property .b. conflict with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 14 } */ +@property (nonatomic) int c; /* { dg-warning ".nonatomic. attribute of property .c. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 15 } */ +@property int d; /* { dg-warning ".nonatomic. attribute of property .d. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 16 } */ +@property (setter=setX:) int e; /* { dg-warning ".setter. attribute of property .e. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 17 } */ +@property (getter=x) int f; /* { dg-warning ".getter. attribute of property .f. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 18 } */ +@property (readonly) int g; /* { dg-warning ".readonly. attribute of property .g. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 19 } */ +@property (readwrite) int h; /* Ok */ +@property (readonly) int i; /* { dg-warning ".getter. attribute of property .i. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 21 } */ +@end + diff --git a/gcc/testsuite/objc.dg/property/at-property-17.m b/gcc/testsuite/objc.dg/property/at-property-17.m new file mode 100644 index 000000000..efb62d6f7 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-17.m @@ -0,0 +1,98 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test that if you have a property declared in a class, with + getters/setters in the superclass, there are no warnings. */ + +@interface MyRootClass +{ + Class isa; + int myCount; + int myCount2; + int myCount3; +} +- (int)count; +- (void)setCount: (int)number; +- (int)count2; +- (void)setCount2: (int)number; +- (int)count3; +@end + +@implementation MyRootClass +- (int) count +{ + return myCount; +} +- (void) setCount: (int)number +{ + myCount = number; +} +- (int) count2 +{ + return myCount2; +} +- (void) setCount2: (int)number +{ + myCount2 = number; +} +- (int) count3 +{ + return myCount3; +} +@end + + + +/* Try with a subclass. */ +@interface MyClass : MyRootClass +@property int count; +@end + +@implementation MyClass +@end /* No warnings. */ + + + +/* Try with a category. */ +@interface MyRootClass (count) +@property int count; +@end + +@implementation MyRootClass (count) +@end /* No warnings. */ + + + +/* Try with a category of a subclass. */ +@interface MyClass2 : MyClass +@end + +@implementation MyClass2 +@end + +@interface MyClass2 (count2) +@property int count2; +@end + +@implementation MyClass2 (count2) +@end /* No warnings. */ + + + +/* Now, try with a category of a subclass, but with a missing setter, + which should generate a warning. */ +@interface MyClass3 : MyClass +@end + +@implementation MyClass3 +@end + +@interface MyClass3 (count3) +@property int count3; +@end + +@implementation MyClass3 (count3) +@end /* { dg-warning "incomplete implementation" } */ +/* { dg-warning "method definition for .-setCount3:. not found" "" { target *-*-* } 97 } */ diff --git a/gcc/testsuite/objc.dg/property/at-property-18.m b/gcc/testsuite/objc.dg/property/at-property-18.m new file mode 100644 index 000000000..e6ffb39cb --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-18.m @@ -0,0 +1,47 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test that if you have a property declared in a class and a + category, the attributes match. This is almost the same as + at-property-16.m, but for a category. It is a separate file + because it is difficult to test multiple messages for the same + line. */ + +@interface MyRootClass +{ + Class isa; +} +@property (assign) id a; +@property (retain) id b; +@property int c; +@property (nonatomic) int d; +@property int e; +@property int f; +@property int g; +@property (readonly) int h; +@property (readonly,getter=getMe) int i; +@property (nonatomic) float j; +@end + +@interface MyRootClass (Category) +@property (retain) id a; /* { dg-warning "assign semantics attributes of property .a. conflict with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 16 } */ +@property (assign) id b; /* { dg-warning "assign semantics attributes of property .b. conflict with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 17 } */ +@property (nonatomic) int c; /* { dg-warning ".nonatomic. attribute of property .c. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 18 } */ +@property int d; /* { dg-warning ".nonatomic. attribute of property .d. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 19 } */ +@property (setter=setX:) int e; /* { dg-warning ".setter. attribute of property .e. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 20 } */ +@property (getter=x) int f; /* { dg-warning ".getter. attribute of property .f. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 21 } */ +@property (readonly) int g; /* { dg-warning ".readonly. attribute of property .g. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 22 } */ +@property (readwrite) int h; /* Ok */ +@property (readonly) int i; /* { dg-warning ".getter. attribute of property .i. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 24 } */ +@property (nonatomic) float j; /* Ok */ +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-19.m b/gcc/testsuite/objc.dg/property/at-property-19.m new file mode 100644 index 000000000..be898e218 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-19.m @@ -0,0 +1,74 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test looking up a @property in a protocol of a category of a superclass. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +/* Use a different getter/setter, so that the only way to compile + object.count is to find the actual @property. */ +@protocol count +@property (getter=number, setter=setNumber:) int count; +@end + +@interface MySubClass : MyRootClass +- (int) testMe; +@end + +@interface MySubClass (Category) <count> +@end + +@implementation MySubClass (Category) +- (int) number +{ + return a; +} +- (void) setNumber: (int)count +{ + a = count; +} +@end + +@implementation MySubClass +- (int) testMe +{ + self.count = 400; + if (self.count != 400) + abort (); + + return self.count; +} +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + object.count = 44; + if (object.count != 44) + abort (); + + if ([object testMe] != 400) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-2.m b/gcc/testsuite/objc.dg/property/at-property-2.m new file mode 100644 index 000000000..19d59fdaa --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-2.m @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +@property int name __attribute__((deprecated)); +@property int table __attribute__((xxx)); /* { dg-warning ".xxx. attribute directive ignored" } */ +@property void function (void); /* { dg-error "declared as a function" } */ +@property typedef int j; /* { dg-error "expected" } */ +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-20.m b/gcc/testsuite/objc.dg/property/at-property-20.m new file mode 100644 index 000000000..1bb49da2b --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-20.m @@ -0,0 +1,81 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test that if you have a property declared in a class and a + sub-class, the types match (unless it's a readonly property, in + which case a "specialization" is enough). */ + +@protocol MyProtocolA +- (void) doNothingA; +@end + +@protocol MyProtocolB +- (void) doNothingB; +@end + +@interface MyRootClass +{ + Class isa; +} +@end + +@interface MySubClass1 : MyRootClass +@end + +@interface MySubClass2 : MyRootClass +@end + +@interface MySubClass3 : MyRootClass <MyProtocolA> +@end + +@interface MySubClass4 : MySubClass1 +@end + +/* Now, the test. */ + +@interface MyClass : MyRootClass +{ } +@property (assign) id <MyProtocolA> a; /* { dg-message "originally specified here" } */ +@property int b; /* { dg-message "originally specified here" } */ +@property float c; /* { dg-message "originally specified here" } */ +@property (assign) MyRootClass *d; /* { dg-message "originally specified here" } */ +@property (assign) MySubClass1 *e; /* { dg-message "originally specified here" } */ +@property (assign, readonly) MySubClass1 *f; /* { dg-message "originally specified here" } */ +@property (assign) MySubClass3 *g; /* { dg-message "originally specified here" } */ +@property (assign, readonly) MySubClass3 *h; /* { dg-message "originally specified here" } */ +@end + +/* The following are all OK because they are identical. */ +@interface MyClass2 : MyClass +{ } +@property (assign) id a; +@property int b; +@property float c; +@property (assign) MyRootClass *d; +@property (assign) MySubClass1 *e; +@property (assign, readonly) MySubClass1 *f; +@property (assign) MySubClass3 *g; +@property (assign, readonly) MySubClass3 *h; +@end + +/* The following are not OK. */ +@interface MyClass3 : MyClass +{ } +@property (assign) MySubClass1 *a; /* { dg-warning "type of property .a. conflicts with previous declaration" } */ +@property float b; /* { dg-warning "type of property .b. conflicts with previous declaration" } */ +@property int c; /* { dg-warning "type of property .c. conflicts with previous declaration" } */ +@property (assign) id d; /* { dg-warning "type of property .d. conflicts with previous declaration" } */ +@property (assign) MyRootClass *e; /* { dg-warning "type of property .e. conflicts with previous declaration" } */ +@property (assign, readonly) MyRootClass *f; /* { dg-warning "type of property .f. conflicts with previous declaration" } */ +@property (assign) MySubClass2 *g; /* { dg-warning "type of property .g. conflicts with previous declaration" } */ +@property (assign, readonly) MySubClass2 *h; /* { dg-warning "type of property .h. conflicts with previous declaration" } */ +@end + +/* The following are OK. */ +@interface MyClass4 : MyClass +{ } +@property (assign, readonly) MySubClass4 *f; +@property (assign, readonly) MySubClass3 <MyProtocolB> *h; +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-21.m b/gcc/testsuite/objc.dg/property/at-property-21.m new file mode 100644 index 000000000..d1f54b1cd --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-21.m @@ -0,0 +1,23 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@protocol MyProtocol +- (void) message; +@end + +@interface MyRootClass +{ + Class isa; +} + +/* Test the warnings on 'assign' with protocols. */ +@property id <MyProtocol> property_a; /* { dg-warning "object property .property.a. has no .assign., .retain. or .copy. attribute" } */ + /* { dg-message ".assign. can be unsafe for Objective-C objects" "" { target *-*-* } 16 } */ + +@property MyRootClass <MyProtocol> *property_b; /* { dg-warning "object property .property.b. has no .assign., .retain. or .copy. attribute" } */ + /* { dg-message ".assign. can be unsafe for Objective-C objects" "" { target *-*-* } 19 } */ + +@property Class <MyProtocol> property_c; /* No 'assign' warning (Classes are static objects so assign semantics do not matter for them). */ +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-22.m b/gcc/testsuite/objc.dg/property/at-property-22.m new file mode 100644 index 000000000..03b3d0bb4 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-22.m @@ -0,0 +1,172 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test properties of different types. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +enum colour { Red, Black }; + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; ++ (Class) class; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } ++ (Class) class { return self; } +@end + + +@interface MyClass : MyRootClass +{ + /* A bunch of C types. */ + char pchar; + short pshort; + int pint; + long plong; + float pfloat; + double pdouble; + enum colour penum; + + /* A bunch of pointers to C types. */ + char *pcharp; + short *pshortp; + int *pintp; + long *plongp; + float *pfloatp; + double *pdoublep; + enum colour *penump; + + /* A bunch of Objective-C types. */ + id pid; + Class pclass; + MyClass *pMyClassp; +} +@property (assign) char pchar; +@property (assign) short pshort; +@property (assign) int pint; +@property (assign) long plong; +@property (assign) float pfloat; +@property (assign) double pdouble; +@property (assign) enum colour penum; + +@property (assign) char *pcharp; +@property (assign) short *pshortp; +@property (assign) int *pintp; +@property (assign) long *plongp; +@property (assign) float *pfloatp; +@property (assign) double *pdoublep; +@property (assign) enum colour *penump; + +@property (assign) id pid; +@property (assign) Class pclass; +@property (assign) MyClass *pMyClassp; +@end + +@implementation MyClass +@synthesize pchar; +@synthesize pshort; +@synthesize pint; +@synthesize plong; +@synthesize pfloat; +@synthesize pdouble; +@synthesize penum; + +@synthesize pcharp; +@synthesize pshortp; +@synthesize pintp; +@synthesize plongp; +@synthesize pfloatp; +@synthesize pdoublep; +@synthesize penump; + +@synthesize pid; +@synthesize pclass; +@synthesize pMyClassp; +@end + +int main (void) +{ + MyClass *object = [[MyClass alloc] init]; + + object.pchar = 1; + if (object.pchar != 1) + abort (); + + object.pshort = 2; + if (object.pshort != 2) + abort (); + + object.pint = 3; + if (object.pint != 3) + abort (); + + object.plong = 4; + if (object.plong != 4) + abort (); + + object.pfloat = 0; + if (object.pfloat != 0) + abort (); + + object.pdouble = 0; + if (object.pdouble != 0) + abort (); + + object.penum = Black; + if (object.penum != Black) + abort (); + + object.pcharp = (char *)0; + if (object.pcharp != 0) + abort (); + + object.pshortp = (short *)0; + if (object.pshortp != 0) + abort (); + + object.pintp = (int *)0; + if (object.pintp != 0) + abort (); + + object.plongp = (long *)0; + if (object.plongp != 0) + abort (); + + object.pfloatp = (float *)0; + if (object.pfloatp != 0) + abort (); + + object.pdoublep = (double *)0; + if (object.pdoublep != 0) + abort (); + + object.penump = (enum colour *)0; + if (object.penump != 0) + abort (); + + object.pid = object; + if (object.pid != object) + abort (); + + object.pclass = [MyClass class]; + if (object.pclass != [MyClass class]) + abort (); + + object.pMyClassp = object; + if (object.pMyClassp != object) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-23.m b/gcc/testsuite/objc.dg/property/at-property-23.m new file mode 100644 index 000000000..c1fd29df4 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-23.m @@ -0,0 +1,17 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test that properties of type arrays or bitfields are rejected. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; +} +@property int a[8]; /* { dg-error "property can not be an array" } */ +@property int b:8; /* { dg-error "property can not be a bit-field" } */ +@property int c[]; /* { dg-error "property can not be an array" } */ +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-24.m b/gcc/testsuite/objc.dg/property/at-property-24.m new file mode 100644 index 000000000..b4a7699f6 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-24.m @@ -0,0 +1,118 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test @optional @properties. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +/* Use a different getters/setters, so that the only way to compile + object.countX is to find the actual @property. */ +@protocol count +@required +/* @required + @synthesize. */ +@property (getter=number1, setter=setNumber1:) int count1; +/* @required + manual setters/getters. */ +@property (getter=number2, setter=setNumber2:) int count2; + +@optional +/* @optional + @synthesize. */ +@property (getter=number3, setter=setNumber3:) int count3; +/* @optional + manual setters/getters. */ +@property (getter=number4, setter=setNumber4:) int count4; + +@optional +/* @optional + readonly, with a setter added in the class itself. */ +@property (readonly, getter=number5) int count5; +@end + +@interface MySubClass : MyRootClass <count> +{ + int count1; + int count2; + int count3; + int count4; + int count5; +} +- (void) setCount5: (int)value; +@end + +@implementation MySubClass +@synthesize count1; +- (int) number2 +{ + return count2; +} +- (void) setNumber2: (int)value +{ + count2 = value; +} +@synthesize count3; +- (int) number4 +{ + return count4; +} +- (void) setNumber4: (int)value +{ + count4 = value; +} +- (int) number5 +{ + return count5; +} +- (void) setCount5: (int)value +{ + count5 = value; +} +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + /* First, test that @required and @optional properties work as + expected if implemented either via @synthesize or manually. */ + object.count1 = 44; + if (object.count1 != 44) + abort (); + + object.count2 = 88; + if (object.count2 != 88) + abort (); + + object.count3 = 77; + if (object.count3 != 77) + abort (); + + object.count4 = 11; + if (object.count4 != 11) + abort (); + + /* Now, test the complication: @optional @property which is + readonly, but which has a setter manually implemented. + Apparently it is possible to use the dotsyntax and the @optional + @property getter is used when reading, while the manual setter is + used when writing. */ + object.count5 = 99; + if (object.count5 != 99) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-25.m b/gcc/testsuite/objc.dg/property/at-property-25.m new file mode 100644 index 000000000..422a29e55 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-25.m @@ -0,0 +1,87 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test warnings and non-warnings with @optional @properties. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +@protocol count +@optional +@property int count1; +@property (readonly) int count2; +@end + + +/* A class that implements all the properties. */ +@interface MySubClass1 : MyRootClass <count> +{ + int count1; + int count2; +} +@end + +@implementation MySubClass1 +@synthesize count1; +@synthesize count2; +@end + + +/* A class that implements nothing; no warnings as the properties are + all optional. */ +@interface MySubClass2 : MyRootClass <count> +@end + +@implementation MySubClass2 +@end + + +@protocol count2 +@required +@property int count1; +@property (readonly) int count2; +@end + +/* A class that implements all the properties. */ +@interface MySubClass3 : MyRootClass <count2> +{ + int count1; + int count2; +} +@end + +@implementation MySubClass3 +@synthesize count1; +@synthesize count2; +@end + + +/* A class that implements nothing; warnings as the properties are + all required. */ +@interface MySubClass4 : MyRootClass <count2> +@end + +@implementation MySubClass4 +@end + +/* { dg-warning "incomplete implementation of class" "" { target *-*-* } 81 } */ +/* { dg-warning "method definition for ..setCount1:. not found" "" { target *-*-* } 81 } */ +/* { dg-warning "method definition for ..count1. not found" "" { target *-*-* } 81 } */ +/* { dg-warning "method definition for ..count2. not found" "" { target *-*-* } 81 } */ +/* { dg-warning "class .MySubClass4. does not fully implement the .count2. protocol" "" { target *-*-* } 81 } */ diff --git a/gcc/testsuite/objc.dg/property/at-property-26.m b/gcc/testsuite/objc.dg/property/at-property-26.m new file mode 100644 index 000000000..c45757e23 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-26.m @@ -0,0 +1,85 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test @properties in class extensions. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +@protocol count4 +/* Use a different getters/setters, so that the only way to compile + object.countX is to find the actual @property. */ +@property (getter=number4, setter=setNumber4:) int count4; +@end + +@interface MySubClass : MyRootClass +{ + int count1; + int count2; + int count3; + int count4; +} +@property (getter=number1, setter=setNumber1:) int count1; +@end + +@interface MySubClass () +@property (getter=number2, setter=setNumber2:) int count2; +@end + +@interface MySubClass () <count4> +@property (getter=number3, setter=setNumber3:) int count3; +@end + +@implementation MySubClass +@synthesize count1; +@synthesize count2; +- (int) number3 +{ + return count3; +} +- (void) setNumber3: (int)value +{ + count3 = value; +} +@synthesize count4; +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + object.count1 = 20; + if (object.count1 != 20) + abort (); + + object.count2 = 11; + if (object.count2 != 11) + abort (); + + object.count3 = 19; + if (object.count3 != 19) + abort (); + + object.count4 = 74; + if (object.count4 != 74) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-27.m b/gcc/testsuite/objc.dg/property/at-property-27.m new file mode 100644 index 000000000..727834684 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-27.m @@ -0,0 +1,66 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test overriding a readonly @property with a readwrite one in a class extension. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +@protocol count2 +/* Use a different getters/setters, so that the only way to compile + object.countX is to find the actual @property. */ +@property (readonly, getter=number2) int count2; +@end + +@interface MySubClass : MyRootClass +{ + int count1; + int count2; +} +@property (readonly, getter=number1) int count1; +@end + +@interface MySubClass () +@property (readwrite, getter=number1, setter=setNumber1:) int count1; +@end + +@interface MySubClass () <count2> +@property (readwrite, getter=number2, setter=setNumber2:) int count2; +@end + +@implementation MySubClass +@synthesize count1; +@synthesize count2; +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + object.count1 = 20; + if (object.count1 != 20) + abort (); + + object.count2 = 11; + if (object.count2 != 11) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-28.m b/gcc/testsuite/objc.dg/property/at-property-28.m new file mode 100644 index 000000000..de5122443 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-28.m @@ -0,0 +1,29 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +/* Test errors when extending a property in a class extension. */ + +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; +} +@property (readonly, retain) id property1; /* { dg-message "originally specified here" } */ +@property (readonly) int property2; /* { dg-message "originally specified here" } */ +@property (readonly, getter=y) int property3; /* { dg-message "originally specified here" } */ +@property (readonly) int property4; /* Ok */ +@property (readonly) int property5; /* { dg-message "originally specified here" } */ +@end + +@interface MyRootClass () +@property (readwrite, copy) id property1; /* { dg-warning "assign semantics attributes of property .property1. conflict with previous declaration" } */ +@property (readwrite, nonatomic) int property2; /* { dg-warning ".nonatomic. attribute of property .property2. conflicts with previous declaration" } */ +@property (readwrite, getter=x) int property3; /* { dg-warning ".getter. attribute of property .property3. conflicts with previous declaration" } */ +@property (readwrite) int property4; /* Ok */ +@property (readwrite) float property5; /* { dg-warning "type of property .property5. conflicts with previous declaration" } */ +@end + + + diff --git a/gcc/testsuite/objc.dg/property/at-property-29.m b/gcc/testsuite/objc.dg/property/at-property-29.m new file mode 100644 index 000000000..0f31617f8 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-29.m @@ -0,0 +1,14 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, January 2011. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +/* Test missing '=' in setter/getter attributes. */ +@property (getter) int property_a; /* { dg-error "missing .=. .after .getter. attribute." } */ +@property (setter) int property_b; /* { dg-error "missing .=. .after .setter. attribute." } */ +@property (assign, getter) int property_c; /* { dg-error "missing .=. .after .getter. attribute." } */ +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-3.m b/gcc/testsuite/objc.dg/property/at-property-3.m new file mode 100644 index 000000000..70b522cba --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-3.m @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +@property volatile int a; /* This is allowed */ +@property extern int b; /* { dg-error "expected" } */ +@property static int c; /* { dg-error "expected" } */ +@property inline int d; /* { dg-error "expected" } */ +@property typedef int e; /* { dg-error "expected" } */ +@property __thread int f; /* { dg-error "expected" } */ +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-4.m b/gcc/testsuite/objc.dg/property/at-property-4.m new file mode 100644 index 000000000..941aab8e3 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-4.m @@ -0,0 +1,40 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +- (int) myGetter; +- (int) myGetterB; +- (int) myGetter2; +- (void) mySetter: (int)property; +- (void) mySetterB: (int)property; +- (void) mySetter2: (int)property; + +/* Test that all the new property attributes can be parsed. */ +@property (assign) id property_a; +@property (copy) id property_b; +@property (nonatomic) int property_c; +@property (readonly) int property_d; +@property (readwrite) int property_e; +@property (retain) id property_f; +@property (release) int property_g; /* { dg-error "unknown property attribute" } */ + +@property (getter=myGetter) int property_h; +@property (setter=mySetter:) int property_i; + +/* Now test various problems. */ + +@property (readonly, readwrite) int a; /* { dg-error ".readonly. attribute conflicts with .readwrite. attribute" } */ +@property (readonly, setter=mySetterB:) int b; /* { dg-error ".readonly. attribute conflicts with .setter. attribute" } */ + +@property (assign, retain) id c; /* { dg-error ".assign. attribute conflicts with .retain. attribute" } */ +@property (assign, copy) id d; /* { dg-error ".assign. attribute conflicts with .copy. attribute" } */ +@property (copy, retain) id e; /* { dg-error ".retain. attribute conflicts with .copy. attribute" } */ + +@property (setter=mySetter:,setter=mySetter2:) int f; /* { dg-error ".setter. attribute may only be specified once" } */ +@property (getter=myGetter, getter=myGetter2 ) int g; /* { dg-error ".getter. attribute may only be specified once" } */ + +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-5.m b/gcc/testsuite/objc.dg/property/at-property-5.m new file mode 100644 index 000000000..bd8949b7f --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-5.m @@ -0,0 +1,34 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; + id property_a; + int property_b; + int property_c; + int property_d; + id property_e; + id property_f; + id property_g; + id property_h; +} + +/* Test various error messages. */ +@property id property_a; /* { dg-warning "object property .property.a. has no .assign., .retain. or .copy. attribute" } */ + /* { dg-message ".assign. can be unsafe for Objective-C objects" "" { target *-*-* } 20 } */ +@property int property_b = 4; /* { dg-error "expected" } */ +@property (retain) int property_c; /* { dg-error ".retain. attribute is only valid for Objective-C objects" } */ +@property (copy) int property_d; /* { dg-error ".copy. attribute is only valid for Objective-C objects" } */ + +@property (retain) id property_e; +@property (retain) id property_f; +@property (retain) id property_g; +@property (retain) id property_h; +@property (retain) id property_e; /* { dg-error "redeclaration of property .property_e." } */ + /* { dg-message "originally specified here" "" { target *-*-* } 26 } */ +@end + +@property id test; /* { dg-error "property declaration not in .interface or .protocol context" } */ diff --git a/gcc/testsuite/objc.dg/property/at-property-6.m b/gcc/testsuite/objc.dg/property/at-property-6.m new file mode 100644 index 000000000..b3584cc40 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-6.m @@ -0,0 +1,61 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test the property syntax with non-synthesized setter/getter + and with standard names. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} +@property (nonatomic) int a; ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } + +- (int) a +{ + return a; +} +- (void) setA: (int)value +{ + a = value; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + if (object.a != 0) + abort (); + + object.a = 14; + + if (object.a != 14) + abort (); + + object.a = 23; + + if (object.a != 23) + abort (); + + object.a = 78; + + if (object.a != 78) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-7.m b/gcc/testsuite/objc.dg/property/at-property-7.m new file mode 100644 index 000000000..6f5cedaac --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-7.m @@ -0,0 +1,58 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test the property syntax with non-synthesized setter/getter + and with a non-standard name for the getter. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} +@property (getter = getA, nonatomic) int a; ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } + +- (int) getA +{ + return a; +} +- (void) setA: (int)value +{ + a = value; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + object.a = 14; + + if (object.a != 14) + abort (); + + object.a = 23; + + if (object.a != 23) + abort (); + + object.a = 78; + + if (object.a != 78) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-8.m b/gcc/testsuite/objc.dg/property/at-property-8.m new file mode 100644 index 000000000..497dedca7 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-8.m @@ -0,0 +1,58 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test the property syntax with non-synthesized setter/getter + and with a non-standard name for the setter. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} +@property (setter = writeA:, nonatomic) int a; ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } + +- (int) a +{ + return a; +} +- (void) writeA: (int)value +{ + a = value; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + object.a = 14; + + if (object.a != 14) + abort (); + + object.a = 23; + + if (object.a != 23) + abort (); + + object.a = 78; + + if (object.a != 78) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-9.m b/gcc/testsuite/objc.dg/property/at-property-9.m new file mode 100644 index 000000000..0f144fad2 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-9.m @@ -0,0 +1,53 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test the property syntax with synthesized setter/getter + and with a non-standard name for the getter and setter. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} +/* Use the simplest synthesized accessor (assign, nonatomic) as we are + not testing the synthesized accessors in this test, just the + property syntax. */ +@property (getter = giveMeA, setter = writeA:, nonatomic) int a; ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize a; +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + object.a = 14; + + if (object.a != 14) + abort (); + + object.a = 23; + + if (object.a != 23) + abort (); + + object.a = 78; + + if (object.a != 78) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-deprecated-1.m b/gcc/testsuite/objc.dg/property/at-property-deprecated-1.m new file mode 100644 index 000000000..e52047771 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-deprecated-1.m @@ -0,0 +1,37 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +/* Test that properties can be deprecated. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} +@property int a __attribute__((deprecated)); ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize a; +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + object.a = 40; /* { dg-warning "is deprecated" } */ + if (object.a != 40) /* { dg-warning "is deprecated" } */ + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-deprecated-2.m b/gcc/testsuite/objc.dg/property/at-property-deprecated-2.m new file mode 100644 index 000000000..d2901a55b --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-deprecated-2.m @@ -0,0 +1,25 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +/* Test that deprecation warnings are produced when a setter/getter of + a @property is used directly. */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; + int variable; +} +@property (assign, nonatomic) int property __attribute__ ((deprecated)); +@end + +void foo (void) +{ + MyClass *object = nil; + + if ([object property] > 0) /* { dg-warning "is deprecated" } */ + { + [object setProperty: 43]; /* { dg-warning "is deprecated" } */ + } +} diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-1.m b/gcc/testsuite/objc.dg/property/dotsyntax-1.m new file mode 100644 index 000000000..8922f5f03 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-1.m @@ -0,0 +1,63 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test the 'dot syntax' without a declarated property. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; + id b; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) count; +- (void) setCount: (int)value; +- (id) next; +- (void) setNext: (id)value; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) count +{ + return a; +} +- (void) setCount: (int)value +{ + a = value; +} +- (id) next +{ + return b; +} +- (void) setNext: (id)value +{ + b = value; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + object.count = 40; + if (object.count != 40) + abort (); + + object.next = object; + if (object.next != object) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-10.m b/gcc/testsuite/objc.dg/property/dotsyntax-10.m new file mode 100644 index 000000000..433595f3d --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-10.m @@ -0,0 +1,86 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test dot-syntax with 'super'. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +static int c; + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) count; +- (void) setCount: (int)count; ++ (int) classCount; ++ (void) setClassCount: (int)count; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} ++ (int) classCount +{ + return c; +} ++ (void) setClassCount: (int)count +{ + c = count; +} +@end + +@interface MySubClass : MyRootClass ++ (int) testMe; +- (int) testMe; +@end + +@implementation MySubClass +- (int) testMe +{ + super.count = 400; + if (super.count != 400) + abort (); + + return super.count; +} ++ (int) testMe +{ + super.classCount = 4000; + if (super.classCount != 4000) + abort (); + + return super.classCount; +} +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + if ([object testMe] != 400) + abort (); + + if ([MySubClass testMe] != 4000) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-11.m b/gcc/testsuite/objc.dg/property/dotsyntax-11.m new file mode 100644 index 000000000..6c9d924ca --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-11.m @@ -0,0 +1,61 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test the error reporting for the dot-syntax in the scenario where + we have a setter, but not a getter, yet a getter is requested. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +static int c; + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (void) setCount: (int)count; ++ (void) setClassCount: (int)count; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (void) setCount: (int)count +{ + a = count; +} ++ (void) setClassCount: (int)count +{ + c = count; +} +@end + +@interface MySubClass : MyRootClass ++ (int) testMe; +- (int) testMe; +@end + +@implementation MySubClass +- (int) testMe +{ + super.count = 400; + if (super.count != 400) /* { dg-error "no .count. getter found" } */ + abort (); + + return super.count; /* { dg-error "no .count. getter found" } */ +} ++ (int) testMe +{ + super.classCount = 4000; + if (super.classCount != 4000) /* { dg-error "no .classCount. getter found" } */ + abort (); + + return super.classCount; /* { dg-error "no .classCount. getter found" } */ +} +@end diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-12.m b/gcc/testsuite/objc.dg/property/dotsyntax-12.m new file mode 100644 index 000000000..20882f909 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-12.m @@ -0,0 +1,105 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test looking up a setter or getter which are in a protocol attached + to a category of a superclass. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +static int c; + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +@protocol count +- (int) count; +- (void) setCount: (int)count; +@end + +@protocol classCount ++ (int) classCount; ++ (void) setClassCount: (int)count; +@end + +@interface MyRootClass (Category) <count, classCount> +@end + +@implementation MyRootClass (Category) +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} ++ (int) classCount +{ + return c; +} ++ (void) setClassCount: (int)count +{ + c = count; +} +@end + +@interface MySubClass : MyRootClass ++ (int) testMe; +- (int) testMe; +@end + +@implementation MySubClass +- (int) testMe +{ + self.count = 400; + if (self.count != 400) + abort (); + + return self.count; +} ++ (int) testMe +{ + self.classCount = 4000; + if (self.classCount != 4000) + abort (); + + return self.classCount; +} +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + object.count = 44; + if (object.count != 44) + abort (); + + MySubClass.classCount = 40; + if (MySubClass.classCount != 40) + abort (); + + if ([object testMe] != 400) + abort (); + + if ([MySubClass testMe] != 4000) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-13.m b/gcc/testsuite/objc.dg/property/dotsyntax-13.m new file mode 100644 index 000000000..c5a4b3301 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-13.m @@ -0,0 +1,53 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test dot-syntax with a local variable. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) count; +- (void) setCount: (int)count; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + int i; + + for (i = 0; i < 10; i++) + { + object.count = i; + + if (object.count != i) + abort (); + } + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-14.m b/gcc/testsuite/objc.dg/property/dotsyntax-14.m new file mode 100644 index 000000000..0606ec4a2 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-14.m @@ -0,0 +1,77 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test dot-syntax with accessors to be looked up in protocol @properties. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@protocol ProtocolA +@property int countA; +@end + +@protocol ProtocolB +@property int countB; +@end + +@protocol ProtocolC +@property int countC; +@end + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@interface MySubClass <ProtocolA, ProtocolB, ProtocolC> +@end + +int function (MySubClass *object, int x) +{ + object.countA = x; + object.countB = x; + object.countC = object.countB; + + return object.countC; +} + +int function2 (MyRootClass <ProtocolA, ProtocolB, ProtocolC> *object, int x) +{ + object.countA = x; + object.countB = x; + object.countC = object.countB; + + return object.countC; +} + +int function3 (MyRootClass <ProtocolA, ProtocolB> *object, int x) +{ + object.countA = x; + object.countB = x; + object.countC = object.countB; /* { dg-error "request for member .countC. in something not a structure or union" } */ + + return object.countC; /* { dg-error "request for member .countC. in something not a structure or union" } */ +} + +int function4 (id <ProtocolA, ProtocolB, ProtocolC> object, int x) +{ + object.countA = x; + object.countB = x; + object.countC = object.countB; + + return object.countC; +} + +int function5 (id <ProtocolA, ProtocolB> object, int x) +{ + object.countA = x; + object.countB = x; + object.countC = object.countB; /* { dg-error "request for member .countC. in something not a structure or union" } */ + + return object.countC; /* { dg-error "request for member .countC. in something not a structure or union" } */ +} diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-15.m b/gcc/testsuite/objc.dg/property/dotsyntax-15.m new file mode 100644 index 000000000..767f6a2b8 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-15.m @@ -0,0 +1,80 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test dot-syntax with accessors to be looked up in protocols. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@protocol ProtocolA +- (int) countA; +- (void) setCountA: (int)aNumber; +@end + +@protocol ProtocolB +- (int) countB; +- (void) setCountB: (int)aNumber; +@end + +@protocol ProtocolC +- (int) countC; +- (void) setCountC: (int)aNumber; +@end + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@interface MySubClass <ProtocolA, ProtocolB, ProtocolC> +@end + +int function (MySubClass *object, int x) +{ + object.countA = x; + object.countB = x; + object.countC = object.countB; + + return object.countC; +} + +int function2 (MyRootClass <ProtocolA, ProtocolB, ProtocolC> *object, int x) +{ + object.countA = x; + object.countB = x; + object.countC = object.countB; + + return object.countC; +} + +int function3 (MyRootClass <ProtocolA, ProtocolB> *object, int x) +{ + object.countA = x; + object.countB = x; + object.countC = object.countB; /* { dg-error "request for member .countC. in something not a structure or union" } */ + + return object.countC; /* { dg-error "request for member .countC. in something not a structure or union" } */ +} + +int function4 (id <ProtocolA, ProtocolB, ProtocolC> object, int x) +{ + object.countA = x; + object.countB = x; + object.countC = object.countB; + + return object.countC; +} + +int function5 (id <ProtocolA, ProtocolB> object, int x) +{ + object.countA = x; + object.countB = x; + object.countC = object.countB; /* { dg-error "request for member .countC. in something not a structure or union" } */ + + return object.countC; /* { dg-error "request for member .countC. in something not a structure or union" } */ +} diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-16.m b/gcc/testsuite/objc.dg/property/dotsyntax-16.m new file mode 100644 index 000000000..893db69d9 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-16.m @@ -0,0 +1,91 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test dot-syntax with pre/post increment and decrement. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) count; +- (void) setCount: (int)count; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + object.count = 10; + if (object.count != 10) + abort (); + + /* First, test that they increment/decrement as expected. */ + object.count++; + if (object.count != 11) + abort (); + + ++object.count; + if (object.count != 12) + abort (); + + object.count--; + if (object.count != 11) + abort (); + + --object.count; + if (object.count != 10) + abort (); + + /* Now, test that they are pre/post increment/decrement, as + expected. */ + if (object.count++ != 10) + abort (); + + if (object.count != 11) + abort (); + + if (++object.count != 12) + abort (); + + if (object.count != 12) + abort (); + + if (object.count-- != 12) + abort (); + + if (object.count != 11) + abort (); + + if (--object.count != 10) + abort (); + + if (object.count != 10) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-17.m b/gcc/testsuite/objc.dg/property/dotsyntax-17.m new file mode 100644 index 000000000..c28e11f48 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-17.m @@ -0,0 +1,67 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test errors with the dot-syntax with pre/post increment and decrement. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int count; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@property (assign, readonly) int count; +- (void) setWriteOnlyCount: (int)value; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize count; +- (void) setWriteOnlyCount: (int)value +{ + a = value; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + object.count = 10; /* { dg-error "readonly property can not be set" } */ + if (object.count != 10) /* Ok */ + abort (); + + /* Test errors when trying to change a readonly property using + pre/post increment/decrement operators. */ + object.count++; /* { dg-error "readonly property can not be set" } */ + + ++object.count; /* { dg-error "readonly property can not be set" } */ + + object.count--; /* { dg-error "readonly property can not be set" } */ + + --object.count; /* { dg-error "readonly property can not be set" } */ + + /* Test errors when trying to change something using Objective-C 2.0 + dot-syntax but there is a setter but no getter. */ + object.writeOnlyCount = 10; /* Ok */ + + object.writeOnlyCount++; /* { dg-error "no .writeOnlyCount. getter found" } */ + + ++object.writeOnlyCount; /* { dg-error "no .writeOnlyCount. getter found" } */ + + object.writeOnlyCount--; /* { dg-error "no .writeOnlyCount. getter found" } */ + + --object.writeOnlyCount; /* { dg-error "no .writeOnlyCount. getter found" } */ + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-18.m b/gcc/testsuite/objc.dg/property/dotsyntax-18.m new file mode 100644 index 000000000..5697d311d --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-18.m @@ -0,0 +1,90 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test dot-syntax with tricky assignments. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) count; +- (void) setCount: (int)count; +- (int) somethingToExecuteOnlyOnce; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} +- (int) somethingToExecuteOnlyOnce +{ + a++; + return 10; +} +@end + +int main (void) +{ + MyRootClass *object1 = [[MyRootClass alloc] init]; + MyRootClass *object2 = [[MyRootClass alloc] init]; + MyRootClass *object3 = [[MyRootClass alloc] init]; + int i; + + object1.count = 10; + if (object1.count != 10) + abort (); + + object2.count = 10; + if (object2.count != 10) + abort (); + + /* Test multiple assignments to a constant. */ + object1.count = object2.count = 20; + + if (object1.count != 20 || object2.count != 20) + abort (); + + i = object1.count = 30; + + if (i != 30 || object1.count != 30) + abort (); + + i = object2.count = 30; + + if (i != 30 || object2.count != 30) + abort (); + + /* Test a simple assignment to something with a side-effect; the + 'rhs' should be evaluated only once. */ + object1.count = ([object2 somethingToExecuteOnlyOnce] > 0 ? 30 : 45); + + if (object1.count != 30 || object2.count != 31) + abort (); + + /* Test multiple assignments with side effects. */ + object3.count = object1.count = ([object2 somethingToExecuteOnlyOnce] > 0 ? 30 : 45); + + if (object1.count != 30 || object2.count != 32 || object3.count != 30) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-19.m b/gcc/testsuite/objc.dg/property/dotsyntax-19.m new file mode 100644 index 000000000..df4867b0a --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-19.m @@ -0,0 +1,113 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test dot-syntax with more tricky assignments. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + id a; + id b; + int p1; + float p2; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; + +@property (assign) id object1; +@property (assign) id object2; +- (id) test; +- (id) myself; +- (id) nilObject; + +@property int p1; +@property float p2; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize object1 = a; +@synthesize object2 = b; +- (id) test +{ + /* Test multiple assignments with 'self'. */ + self.object1 = self.object2 = self; + + if (self.object1 != self || self.object2 != self) + abort (); + + /* Test multiple assignments with a conditional and method calls. */ + self.object1 = self.object2 = (self ? [self myself] : [self nilObject]); + + if (self.object1 != self || self.object2 != self) + abort (); + + self.object1 = self.object2 = (self ? [self nilObject] : [self myself]); + + if (self.object1 != nil || self.object2 != nil) + abort (); + + return self.object1; +} +- (id) myself +{ + return self; +} +- (id) nilObject +{ + return nil; +} + +@synthesize p1; +@synthesize p2; +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + MyRootClass *object1 = [[MyRootClass alloc] init]; + + [object test]; + + /* Now, test multiple assignments with different types. Use + int/float as they seem to happily crash the compiler in gimplify + if proper conversions are not being generated by the + frontend. ;-) */ + object.p1 = object.p2 = 12; + + if (object.p1 != 12 || object.p2 != 12) + abort (); + + object.p1 = object.p2 = 2.7; + + if (object.p1 != 2) + abort (); + + /* Just try a different loop, mixing in a few different standard C + constructs to cover a few other cases. */ + object.p1 = 10; + object1.p1 = 0; + while (object.p1) + { + object1.p1 += ((object.p2 = 4.56) ? 0 : object.p1); + object.p1--; + } + + if (object.p1 != 0 || object1.p1 != 0) + abort (); + + if ((object.p1 = 0)) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-2.m b/gcc/testsuite/objc.dg/property/dotsyntax-2.m new file mode 100644 index 000000000..03e49aebc --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-2.m @@ -0,0 +1,72 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test the 'dot syntax' without a declarated property. This tests the case where + only the setter (or only the getter) exists. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; + id b; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) a; +- (void) setCount: (int)value; +- (id) b; +- (void) setNext: (id)value; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) a +{ + return a; +} +- (void) setCount: (int)value +{ + a = value; +} +- (id) b +{ + return b; +} +- (void) setNext: (id)value +{ + b = value; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + /* This should work because -setCount: exists (even if -count does + not). */ + object.count = 40; + + /* This should work because -a exists (even if -setA: does not). */ + if (object.a != 40) + abort (); + + /* This should work because -setNext: exists (even if -next does + not). */ + object.next = object; + + /* This should work because -b exists (even if -setB: does not). */ + if (object.b != object) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-20.m b/gcc/testsuite/objc.dg/property/dotsyntax-20.m new file mode 100644 index 000000000..f1dd48e61 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-20.m @@ -0,0 +1,67 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +/* Test warnings with the dot-syntax. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + id a; + id b; + int p1; + int p2; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; + +@property int p1; +@property int p2; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize p1; +@synthesize p2; +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + /* First, test that the artificial code generated by dot-syntax does + not generate unexpected warnings. */ + + /* All of the following should generate no warnings. */ + object.p1 = 0; + object.p2 = 0; + object.p1 = object.p2 = 0; + if (object.p1 > 0) + object.p2 = 0; + + object.p1++; + ++object.p1; + object.p1--; + --object.p1; + + while (object.p1) + object.p1--; + + /* Now test some warnings. */ + object.p1; /* { dg-warning "value computed is not used" } */ + + /* TODO: It would be good to get the following to warn. */ + if (object.p1 = 0) /* dg-warning "suggest parentheses around assignment used as truth value" */ + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-21.m b/gcc/testsuite/objc.dg/property/dotsyntax-21.m new file mode 100644 index 000000000..4b8945ed6 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-21.m @@ -0,0 +1,113 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test dot-syntax with super in a category. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) count; +- (void) setCount: (int)count; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} +@end + +/* First, test 'super' in the main implementation of a subclass. */ +@interface MySubClass : MyRootClass +- (int) superCount; +- (void) setSuperCount: (int)count; +@end + +@implementation MySubClass +- (int) superCount +{ + return super.count; +} +- (void) setSuperCount: (int)count +{ + super.count = count; +} +@end + +/* Now, test 'super' in a category of a subclass. */ +@interface MySubClass (Category) +- (int) superCount2; +- (void) setSuperCount2: (int)count; +- (int) test: (int)x; +@end + +@implementation MySubClass (Category) +- (int) superCount2 +{ + return super.count; +} +- (void) setSuperCount2: (int)count +{ + super.count = count; +} +- (int) test: (int)x +{ + /* For positive x, the following will leave super.count + unchanged. */ + super.count++; + --super.count; + + super.count = (x < 0 ? x : super.count); + + if ((x = super.count)) + super.count += 1; + + if ((x = super.count)) + super.count -= 1; + + /* Finally, also put a bit of self.count in the mix. */ + self.count++; + super.count--; + + return super.count; +} +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + object.count = 10; + if (object.count != 10) + abort (); + + object.superCount = 11; + if (object.superCount != 11) + abort (); + + object.superCount2 = 12; + if (object.superCount2 != 12) + abort (); + + if ([object test: 45] != 12) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-22.m b/gcc/testsuite/objc.dg/property/dotsyntax-22.m new file mode 100644 index 000000000..cc5834822 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-22.m @@ -0,0 +1,19 @@ +/* PR objc/47784. This testcase used to crash the compiler. */ + +typedef struct { + float x; +} SomeType; + +@interface MyClass + +@property(assign,readwrite) SomeType position; + +@end + +void example (MyClass *x) +{ + const SomeType SomeTypeZero = {0.0f}; + + x.position= SomeTypeZero; +} + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-3.m b/gcc/testsuite/objc.dg/property/dotsyntax-3.m new file mode 100644 index 000000000..d34780628 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-3.m @@ -0,0 +1,64 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test the 'dot syntax' without a declarated property. This tests the case where + the object is a Class. */ + + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +static int a; +static id b; + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; ++ (int) count; ++ (void) setCount: (int)value; ++ (id) next; ++ (void) setNext: (id)value; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } ++ (int) count +{ + return a; +} ++ (void) setCount: (int)value +{ + a = value; +} ++ (id) next +{ + return b; +} ++ (void) setNext: (id)value +{ + b = value; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + MyRootClass.count = 40; + if (MyRootClass.count != 40) + abort (); + + MyRootClass.next = object; + if (MyRootClass.next != object) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-4.m b/gcc/testsuite/objc.dg/property/dotsyntax-4.m new file mode 100644 index 000000000..2db067f1f --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-4.m @@ -0,0 +1,42 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test the 'dot syntax' without a declarated property. This tests + syntax errors in the case where the object is a Class. */ + + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +int main (void) +{ + MyRootClass.invalid = 40; /* { dg-error "could not find setter.getter" } */ + if (MyRootClass.invalid != 40) /* { dg-error "could not find setter.getter" } */ + abort (); + + MyRootClass.; /* { dg-error "expected identifier" } */ + if (MyRootClass.) /* { dg-error "expected identifier" } */ + abort (); + + MyRootClass.int; /* { dg-error "expected identifier" } */ + if (MyRootClass.int) /* { dg-error "expected identifier" } */ + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-5.m b/gcc/testsuite/objc.dg/property/dotsyntax-5.m new file mode 100644 index 000000000..06e113032 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-5.m @@ -0,0 +1,78 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test the 'dot syntax' with self, both in instance and class methods. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +static int c; + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) count; +- (void) setCount: (int)count; ++ (int) classCount; ++ (void) setClassCount: (int)count; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} ++ (int) classCount +{ + return c; +} ++ (void) setClassCount: (int)count +{ + c = count; +} +- (int) testMe +{ + self.count = 400; + if (self.count != 400) + abort (); + + return self.count; +} ++ (int) testMe +{ + self.classCount = 4000; + if (self.classCount != 4000) + abort (); + + return self.classCount; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + if ([object testMe] != 400) + abort (); + + if ([MyRootClass testMe] != 4000) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-6.m b/gcc/testsuite/objc.dg/property/dotsyntax-6.m new file mode 100644 index 000000000..7ecd34e3d --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-6.m @@ -0,0 +1,106 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test nested 'dot syntax' (xxx.yyy.zzz or [xxx yyy].zzz). */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@class MyRootClass; + +static MyRootClass *shared_root = nil; + +@interface MyRootClass +{ + Class isa; + int a; + int b; + MyRootClass *next; +} +@property int b; +@property (assign) MyRootClass *next; ++ (id) initialize; ++ (MyRootClass *)sharedInstance; ++ (id) alloc; +- (id) init; +- (MyRootClass *)same; +- (int) count; +- (void) setCount: (int)count; +@end + +@implementation MyRootClass +@synthesize b; +@synthesize next; ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } ++ (MyRootClass *)sharedInstance +{ + if (!shared_root) + shared_root = [[self alloc] init]; + + return shared_root; +} +- (MyRootClass *)same +{ + return self; +} +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + /* Test ClassName.accessor.accessor. */ + MyRootClass.sharedInstance.count = 500; + if (MyRootClass.sharedInstance.count != 500) + abort (); + + /* Test object.accessor.accessor. */ + object.same.count = 1000; + if (object.same.count != 1000) + abort (); + + /* Test object.accessor.property. */ + object.same.next = object; + if (object.same.next != object) + abort (); + + /* Test lots of nesting. */ + if (object.next.next.same.same.next.next.same != object) + abort (); + + /* Test more nesting. */ + MyRootClass.sharedInstance.next = object; + MyRootClass.sharedInstance.next.next.next.next.next.count = 2000; + if (MyRootClass.sharedInstance.next.next.next.next.next.count != 2000) + abort (); + + /* Test more nesting. */ + MyRootClass.sharedInstance.same.same.same.same.same.count = 3000; + if (MyRootClass.sharedInstance.same.same.same.same.same.count != 3000) + abort (); + + /* Test [object method].property. */ + [MyRootClass sharedInstance].count = 5000; + if ([MyRootClass sharedInstance].count != 5000) + abort (); + + /* Just a final check. */ + if (shared_root.count != 5000) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-7.m b/gcc/testsuite/objc.dg/property/dotsyntax-7.m new file mode 100644 index 000000000..15c1725d8 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-7.m @@ -0,0 +1,48 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test dot syntax of a casted expression. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) count; +- (void) setCount: (int)count; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} +@end + +int main (void) +{ + id object = [[MyRootClass alloc] init]; + + ((MyRootClass *)object).count = 200; + if (((MyRootClass *)object).count != 200) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-8.m b/gcc/testsuite/objc.dg/property/dotsyntax-8.m new file mode 100644 index 000000000..35dfda40c --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-8.m @@ -0,0 +1,62 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test the 'dot syntax' with typedefs. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +static int c; + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) count; +- (void) setCount: (int)count; ++ (int) classCount; ++ (void) setClassCount: (int)count; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} ++ (int) classCount +{ + return c; +} ++ (void) setClassCount: (int)count +{ + c = count; +} +@end + +typedef MyRootClass MyType; + +int main (void) +{ + MyType *object = [[MyRootClass alloc] init]; + + object.count = 1974; + if (object.count != 1974) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-9.m b/gcc/testsuite/objc.dg/property/dotsyntax-9.m new file mode 100644 index 000000000..61a5c0eb8 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-9.m @@ -0,0 +1,77 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test that setter/getters for dot-syntax are properly found even if + not declared in the @interface, but available in the local + @implementation before the current line (ie, [object name] can be + compiled in that case, so object.name should be compiled too). */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +static int c; + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} ++ (int) classCount +{ + return c; +} ++ (void) setClassCount: (int)count +{ + c = count; +} +- (int) testMe +{ + self.count = 400; + if (self.count != 400) + abort (); + + return self.count; +} ++ (int) testMe +{ + self.classCount = 4000; + if (self.classCount != 4000) + abort (); + + return self.classCount; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + if ([object testMe] != 400) + abort (); + + if ([MyRootClass testMe] != 4000) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-deprecated-1.m b/gcc/testsuite/objc.dg/property/dotsyntax-deprecated-1.m new file mode 100644 index 000000000..ad627a8c1 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-deprecated-1.m @@ -0,0 +1,41 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +/* Test the 'dot syntax' with deprecated methods. */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) classCount __attribute__ ((deprecated)); ++ (void) setClassCount: (int)value __attribute__ ((deprecated)); + +- (int) count __attribute__ ((deprecated)); +- (void) setCount: (int)value __attribute__ ((deprecated)); + +- (int) classCount2; +- (void) setClassCount2: (int)value; + +- (int) count2; +- (void) setCount2: (int)value; +@end + +void foo (void) +{ + MyClass *object = nil; + + + if (object.count > 0) /* { dg-warning "is deprecated" } */ + object.count = 20; /* { dg-warning "is deprecated" } */ + + if (MyClass.classCount < -7) /* { dg-warning "is deprecated" } */ + MyClass.classCount = 11; /* { dg-warning "is deprecated" } */ + + if (object.classCount2 > 0) + object.classCount2 = 19; + + if (object.count2 < -7) + object.count2 = 74; +} diff --git a/gcc/testsuite/objc.dg/property/dynamic-1.m b/gcc/testsuite/objc.dg/property/dynamic-1.m new file mode 100644 index 000000000..8f9737139 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dynamic-1.m @@ -0,0 +1,34 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +@end + +@implementation MyRootClass +@end + +@dynamic isa; /* { dg-error ".@dynamic. not in @implementation context" } */ + +@interface Test : MyRootClass +{ + int v1; + int v2; + int v3; + int v4; +} +@property int v1; +@property int v2; +@property int v3; +@property int v4; +@end + +@implementation Test +@dynamic; /* { dg-error "expected identifier" } */ +@dynamic v1, ; /* { dg-error "expected identifier" } */ +@dynamic v1, v2, v3; +@dynamic v4; +@end diff --git a/gcc/testsuite/objc.dg/property/dynamic-2.m b/gcc/testsuite/objc.dg/property/dynamic-2.m new file mode 100644 index 000000000..203ba34a1 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dynamic-2.m @@ -0,0 +1,45 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +@end + +@implementation MyRootClass +@end + +@dynamic isa; /* { dg-error ".@dynamic. not in @implementation context" } */ + +@interface Test : MyRootClass +{ + int v1; +} +@end +@implementation Test +@end + + +@interface Test (Category) +@property int v1; +@end +@implementation Test (Category) +@dynamic v1; +@end + + +@interface AnotherTest : MyRootClass +{ +} +@property int one; +@end + +@implementation AnotherTest +@dynamic one; +@dynamic one; /* { dg-error "property .one. already specified in .@dynamic." } */ + /* { dg-message "originally specified here" "" { target *-*-* } 41 } */ +@dynamic three; /* { dg-error "no declaration of property .three. found in the interface" } */ +@end diff --git a/gcc/testsuite/objc.dg/property/dynamic-3.m b/gcc/testsuite/objc.dg/property/dynamic-3.m new file mode 100644 index 000000000..e8a6693b0 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dynamic-3.m @@ -0,0 +1,49 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +@end + +@implementation MyRootClass +@end + +/* Test @property/@dynamic in a category. First, a case where + @dynamic should turn off all warnings. */ + +@interface MyRootClass (Category) +@property int a; +- (int) test; +@end +@implementation MyRootClass (Category) +@dynamic a; +- (int) test +{ + return self.a; /* This should compile into [self a] with no warnings. */ +} +@end + + + +/* Test @property/@dynamic in a category. Second, a case with a + missing setter and no @dynamic. A warning should be generated. */ + +@interface MyRootClass (Category2) +@property int b; +- (int) test; +@end +@implementation MyRootClass (Category2) +- (int) b +{ + return 0; +} +- (int) test +{ + return self.b; +} +@end /* { dg-warning "incomplete implementation" } */ +/* { dg-warning "method definition for .-setB:. not found" "" { target *-*-* } 48 } */ diff --git a/gcc/testsuite/objc.dg/property/dynamic-4.m b/gcc/testsuite/objc.dg/property/dynamic-4.m new file mode 100644 index 000000000..84998d6b4 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dynamic-4.m @@ -0,0 +1,45 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +@end + +@implementation MyRootClass +@end + +/* Test @property/@dynamic with protocols. */ + +@protocol MyProtocol +@property int a; +@end + + +/* This class is declared to conform to the protocol, but because of + @dynamic, no warnings are issued even if the getter/setter for the + @property are missing. */ +@interface MyClass1 : MyRootClass <MyProtocol> +@end + +@implementation MyClass1 +@dynamic a; +@end + + +/* This class is declared to conform to the protocol and warnings are + issued because the setter for the @property is missing. */ +@interface MyClass2 : MyRootClass <MyProtocol> +@end + +@implementation MyClass2 +- (int) a +{ + return 0; +} +@end /* { dg-warning "incomplete implementation" } */ +/* { dg-warning "method definition for .-setA:. not found" "" { target *-*-* } 43 } */ +/* { dg-warning "class .MyClass2. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 43 } */ diff --git a/gcc/testsuite/objc.dg/property/dynamic-5.m b/gcc/testsuite/objc.dg/property/dynamic-5.m new file mode 100644 index 000000000..77e81411a --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dynamic-5.m @@ -0,0 +1,53 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test @dynamic in the real scenario where a class declares a + @property, uses @dynamic to avoid implementing it, then subclasses + implement it. */ + +#include <objc/objc.h> +#include <objc/runtime.h> +#include <stdlib.h> + +@interface MyRootClass +{ + Class isa; +} +@property int a; ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@dynamic a; +@end + +@interface Test : MyRootClass +{ + int v1; +} +@end + +@implementation Test +@synthesize a = v1; +@end + +int main (void) +{ + /* Note how 'object' is declared to be of class 'MyRootClass', but + actually is of the subclass which implements the property for + real. */ + MyRootClass *object = [[Test alloc] init]; + + object.a = 40; + + if (object.a != 40) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/dynamic-6.m b/gcc/testsuite/objc.dg/property/dynamic-6.m new file mode 100644 index 000000000..23a7a8905 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dynamic-6.m @@ -0,0 +1,26 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test case when an accessor from a @property matches a method + required by a protocol. If the @property is @dynamic, then no + warning should be generated. */ + +#include <objc/objc.h> +#include <objc/runtime.h> +#include <stdlib.h> + +@protocol Count +- (int) count; +@end + +@interface MyRootClass <Count> +{ + Class isa; +} +@property int count; +@end + +@implementation MyRootClass +/* This @dynamic turns off any warnings for -count and -setCount:. */ +@dynamic count; +@end diff --git a/gcc/testsuite/objc.dg/property/fsf-property-basic.m b/gcc/testsuite/objc.dg/property/fsf-property-basic.m new file mode 100644 index 000000000..ddc0589e0 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/fsf-property-basic.m @@ -0,0 +1,62 @@ +/* Basic test, auto-generated getter/setter based on property name. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +extern int printf (char *fmt,...) ; +extern void abort (void); + +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface Bar +{ +@public + Class isa; + int FooBar; +} ++ (id) initialize; ++ (id) alloc ; +- (id) init; +- (int) whatIsFooBar; +@property int FooBar; +@end + +@implementation Bar + ++initialize { return self;} ++ (id) alloc { return class_createInstance (self, 0); } + +- (id) init {return self;} + +- (int) whatIsFooBar { return self->FooBar; } +@synthesize FooBar; +@end + +int main(int argc, char *argv[]) { + int res; + Bar *f = [[Bar alloc] init]; + + /* First, establish that the property getter & setter have been synthesized + and operate correctly. */ + [f setFooBar:1]; + + if ([f whatIsFooBar] != 1) + { printf ("setFooBar did not set FooBar\n"); abort ();} + + res = [f FooBar]; + + if (res != 1 ) + { printf ("[f FooBar] = %d\n", res); abort ();} + + /* Now check the short-cut object.property syntax. */ + /* Read... */ + res = f.FooBar; + if (res != 1 ) + { printf ("f.FooBar = %d\n", res); abort ();} + + /* .... write. */ + f.FooBar = 0; + /* printf ("seems OK\n", res); */ + return f.FooBar; +} + diff --git a/gcc/testsuite/objc.dg/property/fsf-property-method-access.m b/gcc/testsuite/objc.dg/property/fsf-property-method-access.m new file mode 100644 index 000000000..01eea5bf7 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/fsf-property-method-access.m @@ -0,0 +1,67 @@ +/* test access in methods, auto-generated getter/setter based on property name. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +extern int printf (char *fmt,...) ; +extern void abort (void); + +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface Bar +{ +@public + Class isa; + int FooBar; +} ++ (id) initialize; ++ (id) alloc ; +- (id) init; + +- (int) lookAtProperty; +- (void) setProperty: (int) v; + +@property int FooBar; +@end + +@implementation Bar + ++initialize { return self;} ++ (id) alloc { return class_createInstance(self, 0);} + +- (id) init {return self;} + +@synthesize FooBar; + +- (int) lookAtProperty { return FooBar; } +- (void) setProperty: (int) v { FooBar = v; } + +@end + +int main(int argc, char *argv[]) { + int res; + Bar *f = [[Bar alloc] init]; + + /* First, establish that the property getter & setter have been synthesized + and operate correctly. */ + [f setProperty:11]; + + if (f.FooBar != 11) + { printf ("setProperty did not set FooBar\n"); abort ();} + + res = [f lookAtProperty]; + if (res != 11 ) + { printf ("[f lookAtProperty] = %d\n", res); abort ();} + + /* Make sure we haven't messed up the shortcut form. */ + /* read ... */ + res = f.FooBar; + if (res != 11 ) + { printf ("f.FooBar = %d\n", res); abort ();} + + /* ... write. */ + f.FooBar = 0; + /* printf ("seems OK\n", res); */ + return f.FooBar; +} + diff --git a/gcc/testsuite/objc.dg/property/fsf-property-named-ivar.m b/gcc/testsuite/objc.dg/property/fsf-property-named-ivar.m new file mode 100644 index 000000000..545856850 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/fsf-property-named-ivar.m @@ -0,0 +1,61 @@ +/* Basic test, auto-generated getter/setter based on named ivar */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +extern int printf (char *fmt,...) ; +extern void abort (void); + +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface Bar +{ +@public + Class isa; + int var; +} ++ (id) initialize; ++ (id) alloc ; +- (id) init; + +@property int FooBar; +@end + +@implementation Bar + ++initialize { return self;} ++ (id) alloc { return class_createInstance (self, 0); } + +- (id) init {return self;} + +@synthesize FooBar = var; +@end + +int main(int argc, char *argv[]) { + int res; + Bar *f = [[Bar alloc] init]; + + /* First, establish that the property getter & setter have been synthesized + and operate correctly. */ + [f setFooBar:1234]; + + if (f->var != 1234) + { printf ("setFooBar did not set var correctly\n"); abort ();} + + res = [f FooBar]; + + if (res != 1234 ) + { printf ("[f FooBar] = %d\n", res); abort ();} + + /* Now check the short-cut object.property syntax. */ + /* Read .... */ + res = f.FooBar; + if (res != 1234 ) + { printf ("f.FooBar = %d\n", res); abort ();} + + /* ... and write. */ + f.FooBar = 0; + /* printf ("seems OK\n", res); */ + return f.FooBar; +} + diff --git a/gcc/testsuite/objc.dg/property/property-1.m b/gcc/testsuite/objc.dg/property/property-1.m new file mode 100644 index 000000000..147f007b9 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/property-1.m @@ -0,0 +1,32 @@ +/* This program tests use of property provided setter/getter functions. */ +/* { dg-options "-std=c99" } */ +/* { dg-do run } */ +/* { dg-additional-sources "../../objc-obj-c++-shared/Object1.m" } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#import "../../objc-obj-c++-shared/Object1.h" + +@interface Bar : Object +{ + int iVar; +} +@property (setter=MySetter:) int FooBar; +@end + +@implementation Bar +@synthesize FooBar=iVar; + +- (void) MySetter : (int) value { iVar = value; } + +@end + +int main(int argc, char *argv[]) { + Bar *f = [Bar new]; + f.FooBar = 1; + + f.FooBar += 3; + + f.FooBar -= 4; + return f.FooBar; +} + diff --git a/gcc/testsuite/objc.dg/property/property-encoding-1.m b/gcc/testsuite/objc.dg/property/property-encoding-1.m new file mode 100644 index 000000000..dc12c3137 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/property-encoding-1.m @@ -0,0 +1,182 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, March 2011. */ +/* Test encoding properties. */ +/* { dg-do run } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ + +#include <objc/runtime.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +@interface MyRootClass +{ Class isa; } ++ alloc; +- init; ++ initialize; +@end + +@implementation MyRootClass ++ alloc { return class_createInstance (self, 0); } +- init { return self; } ++ initialize { return self; } +@end + +@interface MySubClass : MyRootClass +{ + char char_property; + short short_property; + int int_property; + long long_property; + float float_property; + double double_property; + int *int_pointer_property; + + id propertyA; + id propertyB; + id propertyC; + id propertyD; + int propertyE; + id propertyF; + + id other_variable; +} +@property char char_property; +@property short short_property; +@property int int_property; +@property long long_property; +@property float float_property; +@property double double_property; +@property int *int_pointer_property; + +@property (assign, getter=getP, setter=setP:) id propertyA; +@property (assign) id propertyB; +@property (copy) id propertyC; +@property (retain) id propertyD; +@property (nonatomic) int propertyE; +@property (nonatomic, readonly, copy) id propertyF; + +@property (assign) id propertyG; +@property (assign, readonly, getter=X) id propertyH; +@end + +@implementation MySubClass +@synthesize char_property; +@synthesize short_property; +@synthesize int_property; +@synthesize long_property; +@synthesize float_property; +@synthesize double_property; +@synthesize int_pointer_property; + +@synthesize propertyA; +@synthesize propertyB; +@synthesize propertyC; +@synthesize propertyD; +@synthesize propertyE; +@synthesize propertyF; + +@synthesize propertyG = other_variable; +@dynamic propertyH; +@end + +#ifdef __OBJC2__ +void error (objc_property_t p) +{ + printf ("Error - property_getAttributes (\"%s\") returns \"%s\"\n", + property_getName (p), + property_getAttributes (p)); + abort (); +} + +/* Concatenate 3 strings and return the result. */ +char *concat (const char *a, const char *b, const char *c) +{ + /* We happily leak memory here. This is a test. */ + char *x = (char *)malloc (sizeof (char) * 128); + snprintf (x, 128, "%s%s%s", a, b, c); + return x; +} + +#endif + +int main (void) +{ +#ifdef __OBJC2__ + Class c = objc_getClass ("MySubClass"); + objc_property_t p; + + p = class_getProperty (c, "char_property"); + /* Usually we expect "Tc,Vchar_property", but if a char is of + different size, it may be encoded differently than "c". */ + if (strcmp (concat ("T", @encode (char), ",Vchar_property"), + property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "short_property"); + if (strcmp (concat ("T", @encode (short), ",Vshort_property"), + property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "int_property"); + if (strcmp (concat ("T", @encode (int), ",Vint_property"), + property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "long_property"); + if (strcmp (concat ("T", @encode (long), ",Vlong_property"), + property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "float_property"); + if (strcmp (concat ("T", @encode (float), ",Vfloat_property"), + property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "double_property"); + if (strcmp (concat ("T", @encode (double), ",Vdouble_property"), + property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "int_pointer_property"); + if (strcmp (concat ("T", @encode (int *), ",Vint_pointer_property"), + property_getAttributes (p)) != 0) + error (p); + + /* Objects are always encoded as '@' hence the string does not + depend on the architecture. */ + p = class_getProperty (c, "propertyA"); + if (strcmp ("T@,GgetP,SsetP:,VpropertyA", property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "propertyB"); + if (strcmp ("T@,VpropertyB", property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "propertyC"); + if (strcmp ("T@,C,VpropertyC", property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "propertyD"); + if (strcmp ("T@,&,VpropertyD", property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "propertyE"); + if (strcmp (concat ("T", @encode (int), ",N,VpropertyE"), + property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "propertyF"); + if (strcmp ("T@,R,C,N,VpropertyF", property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "propertyG"); + if (strcmp ("T@,Vother_variable", property_getAttributes (p)) != 0) + error (p); + + p = class_getProperty (c, "propertyH"); + if (strcmp ("T@,R,D,GX", property_getAttributes (p)) != 0) + error (p); +#endif + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/property-neg-1.m b/gcc/testsuite/objc.dg/property/property-neg-1.m new file mode 100644 index 000000000..cae1a5615 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/property-neg-1.m @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +@interface Bar +{ + int iVar; +} +@property int fooBar; +@end + +@implementation Bar +@end /* { dg-warning "incomplete implementation of class .Bar." } */ + /* { dg-warning "method definition for .-setFooBar:. not found" "" { target *-*-* } 11 } */ + /* { dg-warning "method definition for .-fooBar. not found" "" { target *-*-* } 11 } */ diff --git a/gcc/testsuite/objc.dg/property/property-neg-2.m b/gcc/testsuite/objc.dg/property/property-neg-2.m new file mode 100644 index 000000000..f730fe846 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/property-neg-2.m @@ -0,0 +1,8 @@ +/* { dg-do compile } */ + +@interface Bar +@end + +@implementation Bar +@property int FooBar; /* { dg-error "property declaration not in @interface or @protocol context" } */ +@end diff --git a/gcc/testsuite/objc.dg/property/property-neg-3.m b/gcc/testsuite/objc.dg/property/property-neg-3.m new file mode 100644 index 000000000..0b30931a8 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/property-neg-3.m @@ -0,0 +1,14 @@ +/* { dg-do compile } */ + +@interface Person +{ + char *firstName; +} +@property char *firstName; +@end + +@implementation Person +@dynamic firstName; +@synthesize firstName; /* { dg-error "property .firstName. already specified in .@dynamic." } */ + /* { dg-message "originally specified here" "" { target *-*-* } 11 } */ +@end diff --git a/gcc/testsuite/objc.dg/property/property-neg-4.m b/gcc/testsuite/objc.dg/property/property-neg-4.m new file mode 100644 index 000000000..cc25d84af --- /dev/null +++ b/gcc/testsuite/objc.dg/property/property-neg-4.m @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +@interface Person +{ + char *fullName; +} +@property char *fullName; ++ (void) testClass; +@end + + +@implementation Person +@synthesize fullName; ++ (void) testClass { + self.fullName = "MyName"; /* { dg-error "request for member .fullName." } */ +} +@end diff --git a/gcc/testsuite/objc.dg/property/property-neg-5.m b/gcc/testsuite/objc.dg/property/property-neg-5.m new file mode 100644 index 000000000..464470cba --- /dev/null +++ b/gcc/testsuite/objc.dg/property/property-neg-5.m @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +@interface Foo +@property ( readonly, getter = HELLO, setter = THERE : ) int value; /* { dg-error ".readonly. attribute conflicts with .setter. attribute" } */ +@end diff --git a/gcc/testsuite/objc.dg/property/property-neg-6.m b/gcc/testsuite/objc.dg/property/property-neg-6.m new file mode 100644 index 000000000..7059a56f0 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/property-neg-6.m @@ -0,0 +1,9 @@ +/* Check for proper declaration of @property. */ +/* { dg-do compile } */ + +@interface Bar +{ + int iVar; +} +@property int FooBar /* { dg-error "expected ':', ',', ';', '\}' or '__attribute__' at end of input" } */ +/* { dg-error "expected ..end. at end of input" "" { target *-*-* } 8 } */ diff --git a/gcc/testsuite/objc.dg/property/property-neg-7.m b/gcc/testsuite/objc.dg/property/property-neg-7.m new file mode 100644 index 000000000..4c3d5d7d3 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/property-neg-7.m @@ -0,0 +1,20 @@ +/* { dg-do compile } */ + +@interface NSArray +{ + int count; +} +@property(readonly) int count; +@end + +@implementation NSArray +@synthesize count; +@end + +void foo (NSArray *ans[], id pid, id apid[], int i) { + NSArray *test; + test.count = 1; /* { dg-error "readonly property can not be set" } */ + ((NSArray *)pid).count = 1; /* { dg-error "readonly property can not be set" } */ + ((NSArray *)apid[i]).count = 1; /* { dg-error "readonly property can not be set" } */ + ans[i].count = 3; /* { dg-error "readonly property can not be set" } */ +} diff --git a/gcc/testsuite/objc.dg/property/property.exp b/gcc/testsuite/objc.dg/property/property.exp new file mode 100644 index 000000000..e87730188 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/property.exp @@ -0,0 +1,43 @@ +# GCC Objective-C testsuite that uses the `dg.exp' driver. +# Copyright (C) 1997, 2001, 2007, 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Load support procs. +load_lib objc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS "" +} + +# Initialize `dg'. +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]] + +# Main loop. +dg-runtest $tests "-fgnu-runtime" $DEFAULT_CFLAGS + +# Darwin targets can also run code with the NeXT runtime. +# but Properties are not supported by the runtime lib before Darwin 9. +if [istarget "*-*-darwin\[9123\]*" ] { + dg-runtest $tests "-fnext-runtime" $DEFAULT_CFLAGS +} + +# All done. +dg-finish diff --git a/gcc/testsuite/objc.dg/property/synthesize-1.m b/gcc/testsuite/objc.dg/property/synthesize-1.m new file mode 100644 index 000000000..fbc8e03ee --- /dev/null +++ b/gcc/testsuite/objc.dg/property/synthesize-1.m @@ -0,0 +1,53 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +@end + +@implementation MyRootClass +@end + +@synthesize isa; /* { dg-error ".@synthesize. not in @implementation context" } */ + +@interface Test : MyRootClass +{ + int v1; + int v2; + int v3; + int v4; + int v5; + int v6; + int v7; + int v8; +} +@property int v1; +@property int v2; +@property int v3; +@property int v4; +@property int v5; +@property int v6; +@property int v7; +@property int v8; +@end + +@implementation Test +@synthesize; /* { dg-error "expected identifier" } */ +@synthesize v1, ; /* { dg-error "expected identifier" } */ +@synthesize v2, v3 = ; /* { dg-error "expected identifier" } */ +@synthesize v4, v5=v6, v6 = v5,v7; +@synthesize v8; +/* Some of the @synthesize above will fail due to syntax errors. The + compiler will then complain that the methods implementing the + properties are missing. That is correct, but we are not + interested. The following ones shut up the compiler. */ +- (int) v1 { return v1; } +- (void) setV1: (int)a { v1 = a; } +- (int) v2 { return v2; } +- (void) setV2: (int)a { v2 = a; } +- (int) v3 { return v3; } +- (void) setV3: (int)a { v3 = a; } +@end diff --git a/gcc/testsuite/objc.dg/property/synthesize-10.m b/gcc/testsuite/objc.dg/property/synthesize-10.m new file mode 100644 index 000000000..fc4683187 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/synthesize-10.m @@ -0,0 +1,53 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test @synthesize with bitfield instance variables. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int countA : 2; + int countB : 3; + int countC : 4; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@property (nonatomic) int countA; +@property (nonatomic) int countB; +@property (nonatomic) int countC; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize countA; +@synthesize countB; +@synthesize countC; +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + object.countA = 1; + object.countB = 3; + object.countC = 4; + + if (object.countA != 1) + abort (); + + if (object.countB != 3) + abort (); + + if (object.countC != 4) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/synthesize-11.m b/gcc/testsuite/objc.dg/property/synthesize-11.m new file mode 100644 index 000000000..e49d23424 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/synthesize-11.m @@ -0,0 +1,31 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test errors when @synthesize is used with bitfield instance variables in an incorrect way. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ + Class isa; + int countA : 2; /* { dg-message "originally specified here" } */ + int countB : 3; /* { dg-message "originally specified here" } */ +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@property int countA; +@property (nonatomic) short countB; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize countA; /* { dg-error ".atomic. property .countA. is using bit-field instance variable .countA." } */ +@synthesize countB; /* { dg-error "property .countB. is using instance variable .countB. of incompatible type" } */ +@end /* { dg-warning "incomplete implementation of class" } */ +/* { dg-warning "method definition for ..setCountA.. not found" "" { target *-*-* } 29 } */ +/* { dg-warning "method definition for ..countA. not found" "" { target *-*-* } 29 } */ diff --git a/gcc/testsuite/objc.dg/property/synthesize-2.m b/gcc/testsuite/objc.dg/property/synthesize-2.m new file mode 100644 index 000000000..92170678f --- /dev/null +++ b/gcc/testsuite/objc.dg/property/synthesize-2.m @@ -0,0 +1,51 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <objc/objc.h> +#include <objc/runtime.h> +#include <stdlib.h> + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +@interface Test : MyRootClass +{ + int v1; +} +@property int v1; +/* TODO: Test more types of properties with different semantics + (retain, copy, atomic, nonatomic, and test various C and + Objective-C types). */ +@end + +@implementation Test +@synthesize v1; +@end + +int main (void) +{ + Test *object = [[Test alloc] init]; + + /* Check that the synthesized methods exist and work. Do not invoke + them via property syntax - that is another test. Here we just + want to test the synthesis of the methods. */ + [object setV1: 400]; + + if ([object v1] != 400) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/synthesize-3.m b/gcc/testsuite/objc.dg/property/synthesize-3.m new file mode 100644 index 000000000..866990531 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/synthesize-3.m @@ -0,0 +1,66 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test @synthesize for a @property which is not declared directly in + the @interface, but in a @protocol that the @interface conforms + to. */ + +#include <objc/objc.h> +#include <objc/runtime.h> +#include <stdlib.h> + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +@protocol MyProtocol +@property int v1; +@end + +@protocol MyProtocol2 +@property int v2; +@end + +@interface Test : MyRootClass <MyProtocol, MyProtocol2> +{ + int v1; + int _v2; +} +@end + +@implementation Test +@synthesize v1; +@synthesize v2 = _v2; +@end + +int main (void) +{ + Test *object = [[Test alloc] init]; + + /* Check that the synthesized methods exist and work. Do not invoke + them via property syntax - that is another test. Here we just + want to test the synthesis of the methods. */ + [object setV1: 400]; + + if ([object v1] != 400) + abort (); + + [object setV2: 31]; + + if ([object v2] != 31) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/synthesize-4.m b/gcc/testsuite/objc.dg/property/synthesize-4.m new file mode 100644 index 000000000..602dc68b4 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/synthesize-4.m @@ -0,0 +1,67 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test @synthesize for a @property where the setter/getter are also + declared by the user. This is fine. */ + +#include <objc/objc.h> +#include <objc/runtime.h> +#include <stdlib.h> + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +@protocol MyProtocol +@property int v1; +@end + +@protocol MyProtocol2 +@property int v2; +@end + +@interface Test : MyRootClass <MyProtocol, MyProtocol2> +{ + int v1; + int _v2; +} +- (int)v1; +- (void)setV1: (int)aNumber; +- (int)v2; +@end + +@implementation Test +@synthesize v1; +@synthesize v2 = _v2; +@end + +int main (void) +{ + Test *object = [[Test alloc] init]; + + /* We use dot-syntax here as this is just a general test that + user-declared setters/getters don't cause confusion. */ + object.v1 = 400; + + if (object.v1 != 400) + abort (); + + object.v2 = 31; + + if (object.v2 != 31) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/property/synthesize-5.m b/gcc/testsuite/objc.dg/property/synthesize-5.m new file mode 100644 index 000000000..0871b63ee --- /dev/null +++ b/gcc/testsuite/objc.dg/property/synthesize-5.m @@ -0,0 +1,18 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test that @synthesize does not ICE if asked to use a non-existing + ivar. */ + +#include <objc/objc.h> + +@interface Test +@property int v1; +@end + +@implementation Test +@synthesize v1; /* { dg-error "must be an existing ivar" } */ +@end +/* { dg-warning "incomplete implementation" "" { target *-*-* } 15 } */ +/* { dg-warning "method definition for .-setV1:. not found" "" { target *-*-* } 15 } */ +/* { dg-warning "method definition for .-v1. not found" "" { target *-*-* } 15 } */ diff --git a/gcc/testsuite/objc.dg/property/synthesize-6.m b/gcc/testsuite/objc.dg/property/synthesize-6.m new file mode 100644 index 000000000..19f7c9534 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/synthesize-6.m @@ -0,0 +1,32 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test that each @synthesize is using a different instance variable, + and that it must belong to the class (not to a superclass). */ + +#include <objc/objc.h> + +@interface Test +{ + int v; + int w; +} +@property int v1; +@property int v2; +@end + +@implementation Test +@synthesize v1 = v; /* { dg-message "originally specified here" } */ +@synthesize v2 = v; /* { dg-error "property .v2. is using the same instance variable as property .v1." } */ +@end + +@interface Test2 : Test +@property int w1; +@end + +@implementation Test2 +@synthesize w1; /* { dg-error "ivar .w1. used by .@synthesize. declaration must be an existing ivar" } */ +@end +/* { dg-warning "incomplete implementation" "" { target *-*-* } 29 } */ +/* { dg-warning "method definition for .-setW1:. not found" "" { target *-*-* } 29 } */ +/* { dg-warning "method definition for .-w1. not found" "" { target *-*-* } 29 } */ diff --git a/gcc/testsuite/objc.dg/property/synthesize-7.m b/gcc/testsuite/objc.dg/property/synthesize-7.m new file mode 100644 index 000000000..929e3803b --- /dev/null +++ b/gcc/testsuite/objc.dg/property/synthesize-7.m @@ -0,0 +1,86 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test @synthesize with protocols of protocols. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@protocol ProtocolA +@property int countA; +@end + +@protocol ProtocolB <ProtocolA> +@property int countB; +@end + +@protocol ProtocolC <ProtocolB> +@property int countC; +@end + +@protocol ProtocolD +@property int countD; +@end + +@interface MyRootClass <ProtocolC> +{ + Class isa; + int countA; + int countB; + int countC; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize countA; +@synthesize countB; +@synthesize countC; +@end + +@interface MySubClass : MyRootClass <ProtocolD> +{ + int countD; +} +@end + +@implementation MySubClass +@synthesize countD; +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + int i; + + for (i = 0; i < 10; i++) + { + object.countA += i; + object.countB += i + 1; + object.countC += i + 2; + object.countD += i + 3; + } + + if (object.countA != 45) + abort (); + + if (object.countB != 55) + abort (); + + if (object.countC != 65) + abort (); + + if (object.countD != 75) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/synthesize-8.m b/gcc/testsuite/objc.dg/property/synthesize-8.m new file mode 100644 index 000000000..4af3ecc74 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/synthesize-8.m @@ -0,0 +1,80 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test that when using @synthesize the instance variable and the + property have exactly the same type. */ + +#include <objc/objc.h> + +@protocol MyProtocol +- (void)aMethod; +@end + +@interface ClassA +@end + +@interface ClassB : ClassA +@end + + +/* This is all OK. */ +@interface Test +{ + int v; + float w; + id x; + Test *y; + id <MyProtocol> *z; + ClassA *a; + ClassB *b; + ClassA <MyProtocol> *c; +} +@property (assign) int v; +@property (assign) float w; +@property (assign) id x; +@property (assign) Test *y; +@property (assign) id <MyProtocol> *z; +@property (assign) ClassA *a; +@property (assign) ClassB *b; +@end + +@implementation Test +@synthesize v; +@synthesize w; +@synthesize x; +@synthesize y; +@synthesize z; +@synthesize a; +@synthesize b; +@end + + +/* This is not OK. */ +@interface Test2 +{ + int v; /* { dg-message "originally specified here" } */ + float w; /* { dg-message "originally specified here" } */ + id x; /* { dg-message "originally specified here" } */ + Test *y; /* { dg-message "originally specified here" } */ + id <MyProtocol> *z; /* { dg-message "originally specified here" } */ + ClassA *a; /* { dg-message "originally specified here" } */ + ClassB *b; /* { dg-message "originally specified here" } */ +} +@property (assign) float v; +@property (assign) id w; +@property (assign) int x; +@property (assign) id y; +@property (assign) Test *z; +@property (assign) ClassB *a; +@property (assign) ClassA *b; +@end + +@implementation Test2 +@synthesize v; /* { dg-error "property .v. is using instance variable .v. of incompatible type" } */ +@synthesize w; /* { dg-error "property .w. is using instance variable .w. of incompatible type" } */ +@synthesize x; /* { dg-error "property .x. is using instance variable .x. of incompatible type" } */ +@synthesize y; /* { dg-error "property .y. is using instance variable .y. of incompatible type" } */ +@synthesize z; /* { dg-error "property .z. is using instance variable .z. of incompatible type" } */ +@synthesize a; /* { dg-error "property .a. is using instance variable .a. of incompatible type" } */ +@synthesize b; /* { dg-error "property .b. is using instance variable .b. of incompatible type" } */ +@end diff --git a/gcc/testsuite/objc.dg/property/synthesize-9.m b/gcc/testsuite/objc.dg/property/synthesize-9.m new file mode 100644 index 000000000..7eae31d3f --- /dev/null +++ b/gcc/testsuite/objc.dg/property/synthesize-9.m @@ -0,0 +1,80 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test that when using @synthesize with a readonly property, the + instance variable can be a specialization of the property type. */ + +#include <objc/objc.h> + +@protocol MyProtocol +- (void)aMethod; +@end + +@interface ClassA +@end + +@interface ClassB : ClassA +@end + + +/* This is all OK. */ +@interface Test +{ + int v; + float w; + id x; + Test *y; + id <MyProtocol> *z; + ClassA *a; + ClassB *b; + ClassA <MyProtocol> *c; +} +@property (assign, readonly) int v; +@property (assign, readonly) float w; +@property (assign, readonly) id x; +@property (assign, readonly) Test *y; +@property (assign, readonly) id <MyProtocol> *z; +@property (assign, readonly) ClassA *a; +@property (assign, readonly) ClassB *b; +@end + +@implementation Test +@synthesize v; +@synthesize w; +@synthesize x; +@synthesize y; +@synthesize z; +@synthesize a; +@synthesize b; +@end + + +/* This is sometimes OK, sometimes not OK. */ +@interface Test2 +{ + int v; /* { dg-message "originally specified here" } */ + float w; /* { dg-message "originally specified here" } */ + id x; /* { dg-message "originally specified here" } */ + Test *y; + id <MyProtocol> *z; /* { dg-message "originally specified here" } */ + ClassA *a; /* { dg-message "originally specified here" } */ + ClassB *b; +} +@property (assign, readonly) float v; +@property (assign, readonly) id w; +@property (assign, readonly) int x; +@property (assign, readonly) id y; +@property (assign, readonly) Test *z; +@property (assign, readonly) ClassB *a; +@property (assign, readonly) ClassA *b; +@end + +@implementation Test2 +@synthesize v; /* { dg-error "property .v. is using instance variable .v. of incompatible type" } */ +@synthesize w; /* { dg-error "property .w. is using instance variable .w. of incompatible type" } */ +@synthesize x; /* { dg-error "property .x. is using instance variable .x. of incompatible type" } */ +@synthesize y; +@synthesize z; /* { dg-error "property .z. is using instance variable .z. of incompatible type" } */ +@synthesize a; /* { dg-error "property .a. is using instance variable .a. of incompatible type" } */ +@synthesize b; +@end diff --git a/gcc/testsuite/objc.dg/proto-hier-1.m b/gcc/testsuite/objc.dg/proto-hier-1.m new file mode 100644 index 000000000..99dcbc567 --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-hier-1.m @@ -0,0 +1,58 @@ +/* Test for handling of protocol hierarchies. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +/* One-line substitute for objc/objc.h */ +typedef struct objc_object { struct objc_class *class_pointer; } *id; + +@protocol NSObj +- (void)someMethod; +@end + +@protocol NSCopying +- (void)someOtherMethod; +@end + +@interface NSObject <NSObj> +- (void)someMethod; +@end + +@implementation NSObject +- (void)someMethod {} +@end + +@protocol Booing <NSObj> +- (void)boo; +@end + +@interface Boo: NSObject <Booing> // protocol has only one parent +@end + +@implementation Boo +- (void)boo {} +@end + +@protocol Fooing <NSCopying, NSObj> // Fooing has two parent protocols +- (void)foo; +@end + +@interface Foo: NSObject <Fooing> +@end + +@implementation Foo +- (void)foo {} +- (void)someOtherMethod {} +@end + +int foo(void) { + id<Booing, Fooing> stupidVar; + [stupidVar boo]; + [stupidVar foo]; + [stupidVar anotherMsg]; /* { dg-warning ".\\-anotherMsg. not found in protocol" } */ + /* { dg-warning "no .\\-anotherMsg. method found" "" { target *-*-* } 51 } */ + return 0; +} + +/* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */ +/* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 0 } */ +/* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/objc.dg/proto-hier-2.m b/gcc/testsuite/objc.dg/proto-hier-2.m new file mode 100644 index 000000000..819cf4a50 --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-hier-2.m @@ -0,0 +1,49 @@ +/* Test protocol warning. */ +/* Contributed by Devang Patel <dpatel@apple.com>. */ +/* { dg-do compile } */ + +typedef struct objc_object { struct objc_class *class_pointer; } *id; + +@protocol Bar +@end + +id <Bar> Foo_Bar () { } + +typedef struct +{ + int i; +} MyStruct; + +@interface Foo +{ + id _mainData; + MyStruct *_anotherData; +} + +-(id) mainDataSource; +-(id) anotherDataSource; +-(id) my_method: (int) i; +@end + +@implementation Foo +-(id) anotherDataSource +{ + return (id)_anotherData; +} + +-(id) mainDataSource +{ + return _mainData; +} + +-(id) my_method: (int) i +{ + id one = [self anotherDataSource]; + + i = i - 1; + // Do not issue warning about my_method not found in protocol + return [(one ? [self mainDataSource] : one) my_method:i]; +} + +@end + diff --git a/gcc/testsuite/objc.dg/proto-init-mimatch-1.m b/gcc/testsuite/objc.dg/proto-init-mimatch-1.m new file mode 100644 index 000000000..64e52e812 --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-init-mimatch-1.m @@ -0,0 +1,35 @@ +/* Test to warn on protocol mismatch in a variety of initializations. */ + +/* { dg-do compile } */ + +typedef struct objc_class *Class; + +typedef struct objc_object { + Class isa; +} *id; + +@protocol NSObject +@end + +@interface NSObject <NSObject> +@end + +@protocol NSCopying +- (void)copyWithZone; +@end + +@interface Foo:NSObject <NSCopying> +@end + + +extern id <NSObject> NSCopyObject(); + +@implementation Foo +- (void)copyWithZone { + Foo *copy = NSCopyObject(); /* { dg-warning "type \\'id <NSObject>\\' does not conform to the \\'NSCopying\\' protocol" } */ + + Foo<NSObject,NSCopying> *g = NSCopyObject(); /* { dg-warning "type \\'id <NSObject>\\' does not conform to the \\'NSCopying\\' protocol" } */ + + id<NSObject,NSCopying> h = NSCopyObject(); /* { dg-warning "type \\'id <NSObject>\\' does not conform to the \\'NSCopying\\' protocol" } */ +} +@end diff --git a/gcc/testsuite/objc.dg/proto-lossage-1.m b/gcc/testsuite/objc.dg/proto-lossage-1.m new file mode 100644 index 000000000..2f7eb9861 --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-lossage-1.m @@ -0,0 +1,44 @@ +/* Test for situations in which protocol conformance information + may be lost, leading to superfluous warnings. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +/* One-line substitute for objc/objc.h */ +typedef struct objc_object { struct objc_class *class_pointer; } *id; + +@protocol NSObject +- (int)someValue; +@end + +@interface NSObject <NSObject> +@end + +@protocol PlateMethods +- (void)someMethod; +@end + +@interface Foo { + NSObject <PlateMethods> *plate; + id <PlateMethods> plate1; + NSObject *plate2; +} +- (id <PlateMethods>) getPlate; +- (id <NSObject>) getPlate1; +- (int) getValue; +@end + +@implementation Foo +- (id <PlateMethods>) getPlate { + return plate; /* { dg-bogus "does not implement" } */ +} +- (id <NSObject>) getPlate1 { + return (id <NSObject>)plate1; /* { dg-bogus "does not conform" } */ +} +- (int) getValue { + int i = [plate1 someValue]; /* { dg-warning ".\\-someValue. not found in protocol\\(s\\)" } */ + + int j = [(id <NSObject>)plate1 someValue]; /* { dg-bogus "not found in protocol" } */ + int k = [(id)plate1 someValue]; /* { dg-bogus "not found in protocol" } */ + return i + j + k; +} +@end diff --git a/gcc/testsuite/objc.dg/proto-lossage-2.m b/gcc/testsuite/objc.dg/proto-lossage-2.m new file mode 100644 index 000000000..361bb9087 --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-lossage-2.m @@ -0,0 +1,20 @@ +/* Don't forget to look in protocols if a class (and its superclasses) do not + provide a suitable method. */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@protocol Zot +-(void) zot; +@end + +@interface Foo : Object <Zot> +@end + +int foo() +{ + Foo *f=nil; + [f zot]; /* There should be no warnings here! */ + return 0; +} + diff --git a/gcc/testsuite/objc.dg/proto-lossage-3.m b/gcc/testsuite/objc.dg/proto-lossage-3.m new file mode 100644 index 000000000..1cb7b1d91 --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-lossage-3.m @@ -0,0 +1,26 @@ +/* Crash due to descriptionFor(Instance|Class)Method applied to + a protocol with no instance/class methods respectively. + Problem report and original fix by richard@brainstorm.co.uk. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +#include "../objc-obj-c++-shared/Protocol1.h" +#include "../objc-obj-c++-shared/Object1.h" +#include <objc/objc.h> + +@protocol NoInstanceMethods ++ testMethod; +@end + +@protocol NoClassMethods +- testMethod; +@end + +int +main() +{ +[@protocol(NoInstanceMethods) descriptionForInstanceMethod: @selector(name)]; +[@protocol(NoInstanceMethods) descriptionForClassMethod: @selector(name)]; +[@protocol(NoClassMethods) descriptionForInstanceMethod: @selector(name)]; +[@protocol(NoClassMethods) descriptionForClassMethod: @selector(name)]; +return 0; +} diff --git a/gcc/testsuite/objc.dg/proto-lossage-4.m b/gcc/testsuite/objc.dg/proto-lossage-4.m new file mode 100644 index 000000000..9800d493c --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-lossage-4.m @@ -0,0 +1,54 @@ +/* Test for situations in which protocol conformance information + may be lost while casting. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +#include <stdint.h> + +/* One-line substitute for objc/objc.h */ +typedef struct objc_object { struct objc_class *class_pointer; } *id; + +@protocol Proto +- (intptr_t)someValue; +@end + +@interface Obj +- (intptr_t)anotherValue; +@end + +long foo(void) { + intptr_t receiver = 2; + Obj *objrcvr; + Obj <Proto> *objrcvr2; + + /* NB: Since 'receiver' is an invalid ObjC message receiver, the compiler + should warn but then search for methods as if we were messaging 'id'. */ + + receiver += [receiver someValue]; /* { dg-warning "invalid receiver type .intptr_t." } */ + receiver += [receiver anotherValue]; /* { dg-warning "invalid receiver type .intptr_t." } */ + + receiver += [(Obj *)receiver someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */ +/* { dg-warning "assignment makes integer from pointer without a cast" "" { target *-*-* } 30 } */ + + receiver += [(Obj *)receiver anotherValue]; + receiver += [(Obj <Proto> *)receiver someValue]; + receiver += [(Obj <Proto> *)receiver anotherValue]; + receiver += [objrcvr someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */ +/* { dg-warning "assignment makes integer from pointer without a cast" "" { target *-*-* } 36 } */ + + receiver += [objrcvr anotherValue]; + receiver += [(Obj <Proto> *)objrcvr someValue]; + receiver += [(Obj <Proto> *)objrcvr anotherValue]; + receiver += [objrcvr2 someValue]; + receiver += [objrcvr2 anotherValue]; + receiver += [(Obj *)objrcvr2 someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */ +/* { dg-warning "assignment makes integer from pointer without a cast" "" { target *-*-* } 44 } */ + + receiver += [(Obj *)objrcvr2 anotherValue]; + + return receiver; +} + +/* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */ +/* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 0 } */ +/* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/objc.dg/proto-lossage-5.m b/gcc/testsuite/objc.dg/proto-lossage-5.m new file mode 100644 index 000000000..35c0956ed --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-lossage-5.m @@ -0,0 +1,22 @@ +/* Do not lose references to forward-declared protocols. */ +/* { dg-do compile } */ +@class MyBaseClass; +@class MyClassThatFails; +@protocol _MyProtocol; + +@interface MyClassThatFails +- (MyBaseClass<_MyProtocol> *) aMethod; +@end + +@interface MyBaseClass +@end + +@protocol _MyProtocol +@end + +@implementation MyClassThatFails +- (MyBaseClass<_MyProtocol> *) aMethod +{ + return 0; +} +@end diff --git a/gcc/testsuite/objc.dg/proto-lossage-6.m b/gcc/testsuite/objc.dg/proto-lossage-6.m new file mode 100644 index 000000000..2b8720c36 --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-lossage-6.m @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +@class Base; +@protocol _Protocol; + +@interface ClassA { +} +-(void) func1:(Base<_Protocol> *)inTarget; +@end + +int main() +{ + ClassA* theA = 0; + Base<_Protocol>* myBase = 0; + [theA func1:myBase]; + + return 0; +} + diff --git a/gcc/testsuite/objc.dg/proto-lossage-7.m b/gcc/testsuite/objc.dg/proto-lossage-7.m new file mode 100644 index 000000000..b7746d7a1 --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-lossage-7.m @@ -0,0 +1,28 @@ +/* Check that typedefs of ObjC classes preserve + any @protocol qualifiers. */ +/* { dg-do compile } */ +#include <objc/Object.h> + +@protocol CanDoStuff; + +typedef Object<CanDoStuff> CanDoStuffType; +typedef Object<CanDoStuff> *CanDoStuffTypePtr; + +@protocol CanDoStuff +- (int) dostuff; +@end + +@protocol MoreStuff +- (int) morestuff; +@end + +int main(void) +{ + CanDoStuffTypePtr dice = nil; + CanDoStuffType *nodice = nil; + int count; + count = [dice dostuff]; + count = [nodice dostuff]; + return 0; +} + diff --git a/gcc/testsuite/objc.dg/proto-qual-1.m b/gcc/testsuite/objc.dg/proto-qual-1.m new file mode 100644 index 000000000..59daec5a4 --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-qual-1.m @@ -0,0 +1,70 @@ +/* Check that protocol qualifiers are compiled and encoded properly. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <objc/Protocol.h> +#ifndef __NEXT_RUNTIME__ +#include <objc/objc-api.h> +#endif +#include "../objc-obj-c++-shared/next-mapping.h" + +/* The encoded parameter sizes will be rounded up to match pointer alignment. */ +#define ROUND(s,a) (a * ((s + a - 1) / a)) +#define aligned_sizeof(T) ROUND(sizeof(T),__alignof(void *)) + +extern int sscanf(const char *str, const char *format, ...); +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +@protocol Retain ++ (oneway void)retainArgument:(out bycopy id)arg1 with:(in signed char **)arg2; +- (bycopy) address:(byref inout id)location with:(out short unsigned **)arg2; +@end + +@interface Foo <Retain> ++ (oneway void)retainArgument:(out bycopy id)arg with:(in signed char **)arg2; +@end + +@implementation Foo ++ (oneway void)retainArgument:(out bycopy id)arg1 with:(in signed char **)arg2 { } +- (bycopy) address:(byref inout id)location with:(out short unsigned **)arg2 { return nil; } +@end + +Protocol *proto; +struct objc_method_description *meth; +#ifdef NEXT_OBJC_USE_NEW_INTERFACE +struct objc_method_description meth_object; +#endif +unsigned totsize, offs0, offs1, offs2, offs3, offs4, offs5, offs6, offs7; + +static void scan_initial(const char *pattern) { + totsize = offs0 = offs1 = offs2 = offs3 = offs4 = offs5 = offs6 = offs7 = (unsigned)-1; + sscanf(meth->types, pattern, &totsize, &offs0, &offs1, &offs2, &offs3, + &offs4, &offs5, &offs6, &offs7); + CHECK_IF(!offs0 && offs1 == aligned_sizeof(id) && offs2 == offs1 + aligned_sizeof(SEL) && totsize >= offs2); +} + +int main(void) { + proto = @protocol(Retain); +#ifdef NEXT_OBJC_USE_NEW_INTERFACE + meth_object = protocol_getMethodDescription (proto, + @selector(address:with:), YES, YES); + meth = &meth_object; +#else + meth = [proto descriptionForInstanceMethod: @selector(address:with:)]; +#endif + scan_initial("O@%u@%u:%uNR@%uo^^S%u"); + CHECK_IF(offs3 == offs2 + aligned_sizeof(id) && totsize == offs3 + aligned_sizeof(unsigned)); +#ifdef NEXT_OBJC_USE_NEW_INTERFACE + meth_object = protocol_getMethodDescription (proto, + @selector(retainArgument:with:), YES, NO); + meth = &meth_object; +#else + meth = [proto descriptionForClassMethod: @selector(retainArgument:with:)]; +#endif + scan_initial("Vv%u@%u:%uOo@%un^*%u"); + CHECK_IF(offs3 == offs2 + aligned_sizeof(id) && totsize == offs3 + aligned_sizeof(char **)); + return 0; +} diff --git a/gcc/testsuite/objc.dg/protocol-forward-1.m b/gcc/testsuite/objc.dg/protocol-forward-1.m new file mode 100644 index 000000000..df8dcd70f --- /dev/null +++ b/gcc/testsuite/objc.dg/protocol-forward-1.m @@ -0,0 +1,26 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +/* Test that all protocols appearing in @interface declarations are + real (ie, we saw a full @protocol definition with list of methods), + and not just forward-references (ie, "@protocol NSObject;"). */ + +#include <objc/objc.h> + +@protocol MyProtocol; + +@protocol MyProtocol2 +- (int)method2; +@end + +@interface MyClass <MyProtocol> /* { dg-warning "definition of protocol .MyProtocol. not found" } */ +@end + +@interface MyClass2 <MyProtocol2> /* Ok */ +@end + +@interface MyClass2 (Category) <MyProtocol> /* { dg-warning "definition of protocol .MyProtocol. not found" } */ +@end + +@protocol MyProtocol3 <MyProtocol> /* Ok */ +@end diff --git a/gcc/testsuite/objc.dg/protocol-forward-2.m b/gcc/testsuite/objc.dg/protocol-forward-2.m new file mode 100644 index 000000000..9217ca8d5 --- /dev/null +++ b/gcc/testsuite/objc.dg/protocol-forward-2.m @@ -0,0 +1,95 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do compile } */ + +/* Test that all protocols appearing in @interface declarations are + real (ie, we saw a full @protocol definition with list of methods), + and not just forward-references (ie, "@protocol NSObject;"). This + test checks protocols implemented by other protocols. */ + +#include <objc/objc.h> + +@protocol MyProtocol; + +@interface MyClass <MyProtocol> /* { dg-warning "definition of protocol .MyProtocol. not found" } */ +@end + + +@protocol MyProtocol2 <MyProtocol> +- (int)method2; +@end + +@interface MyClass2 <MyProtocol2> /* { dg-warning "definition of protocol .MyProtocol. not found" } */ +- (int)method2; +@end + + +@protocol MyProtocol3 <MyProtocol2> +- (int)method3; +@end + +@interface MyClass3 <MyProtocol3> /* { dg-warning "definition of protocol .MyProtocol. not found" } */ +- (int)method2; +- (int)method3; +@end + + +@protocol MyProtocol4 <MyProtocol3, MyProtocol2> +- (int)method4; +@end + +@interface MyClass4 <MyProtocol4> /* { dg-warning "definition of protocol .MyProtocol. not found" } */ +- (int)method2; +- (int)method3; +- (int)method4; +@end + + +@protocol MyProtocol5 +- (int)method5; +@end + +@interface MyClass5 <MyProtocol5> /* Ok */ +- (int)method5; +@end + + +@protocol MyProtocol6 <MyProtocol5> +- (int)method6; +@end + +@interface MyClass6 <MyProtocol6> /* Ok */ +- (int)method5; +- (int)method6; +@end + + +@protocol MyProtocol7 <MyProtocol5, MyProtocol4> +- (int)method7; +@end + +@interface MyClass7 <MyProtocol7> /* { dg-warning "definition of protocol .MyProtocol. not found" } */ +- (int)method2; +- (int)method3; +- (int)method4; +- (int)method5; +- (int)method7; +@end + + +/* Now test that if we finally define MyProtocol, the warnings go away. */ +@protocol MyProtocol +- (int)method; +@end + +@protocol MyProtocol8 <MyProtocol5, MyProtocol4> +- (int)method8; +@end + +@interface MyClass8 <MyProtocol8> /* Ok */ +- (int)method; +- (int)method2; +- (int)method3; +- (int)method4; +- (int)method5; +- (int)method8; +@end diff --git a/gcc/testsuite/objc.dg/protocol-inheritance-1.m b/gcc/testsuite/objc.dg/protocol-inheritance-1.m new file mode 100644 index 000000000..6c23a4663 --- /dev/null +++ b/gcc/testsuite/objc.dg/protocol-inheritance-1.m @@ -0,0 +1,54 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wno-protocol" } */ + +#include <objc/objc.h> + +/* Test the -Wno-protocol flag. With this, at a class is accepted + (with no warnings) as conforming to a protocol even if some + protocol methods are implemented in the superclass. */ + +@protocol MyProtocol +- (int)method; +@end + +@protocol MyProtocol2 +- (int)method2; +@end + +/* The superclass implements the method required by the protocol. */ +@interface MyRootClass +{ + Class isa; +} +- (int)method; +@end + +@implementation MyRootClass +- (int)method +{ + return 23; +} +@end + +/* The subclass inherits the method (does not implement it directly) + but that still makes it conform to the protocol. No warnings. */ +@interface MySubClass : MyRootClass <MyProtocol> +@end + +@implementation MySubClass +@end /* No warnings here. */ + + +/* The subclass instead does not inherit the method method2 (and does + not implement it directly) so it does not conform to the + protocol MyProtocol2. */ +@interface MySubClass2 : MyRootClass <MyProtocol2> +@end + +@implementation MySubClass2 +@end /* Warnings here, below. */ + +/* { dg-warning "incomplete implementation of class .MySubClass2." "" { target *-*-* } 50 } */ +/* { dg-warning "method definition for .\\-method2. not found" "" { target *-*-* } 50 } */ +/* { dg-warning "class .MySubClass2. does not fully implement the .MyProtocol2. protocol" "" { target *-*-* } 50 } */ diff --git a/gcc/testsuite/objc.dg/protocol-inheritance-2.m b/gcc/testsuite/objc.dg/protocol-inheritance-2.m new file mode 100644 index 000000000..d76994945 --- /dev/null +++ b/gcc/testsuite/objc.dg/protocol-inheritance-2.m @@ -0,0 +1,57 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test standard warnings when a class conforms to a protocol but some + methods are implemented in the superclass. Use -Wno-protocol to + turn these off. */ + +@protocol MyProtocol +- (int)method; +@end + +@protocol MyProtocol2 +- (int)method2; +@end + +/* The superclass implements the method required by the protocol. */ +@interface MyRootClass +{ + Class isa; +} +- (int)method; +@end + +@implementation MyRootClass +- (int)method +{ + return 23; +} +@end + +/* The subclass inherits the method (does not implement it directly) + and unless -Wno-protocol is used, we emit a warning. */ +@interface MySubClass : MyRootClass <MyProtocol> +@end + +@implementation MySubClass +@end + +/* { dg-warning "incomplete implementation of class .MySubClass." "" { target *-*-* } 39 } */ +/* { dg-warning "method definition for .\\-method. not found" "" { target *-*-* } 39 } */ +/* { dg-warning "class .MySubClass. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 39 } */ + + +/* The subclass instead does not inherit the method method2 (and does + not implement it directly) so it does not conform to the + protocol MyProtocol2. */ +@interface MySubClass2 : MyRootClass <MyProtocol2> +@end + +@implementation MySubClass2 +@end /* Warnings here, below. */ + +/* { dg-warning "incomplete implementation of class .MySubClass2." "" { target *-*-* } 53 } */ +/* { dg-warning "method definition for .\\-method2. not found" "" { target *-*-* } 53 } */ +/* { dg-warning "class .MySubClass2. does not fully implement the .MyProtocol2. protocol" "" { target *-*-* } 53 } */ diff --git a/gcc/testsuite/objc.dg/protocol-optional-1.m b/gcc/testsuite/objc.dg/protocol-optional-1.m new file mode 100644 index 000000000..bc4a3d07e --- /dev/null +++ b/gcc/testsuite/objc.dg/protocol-optional-1.m @@ -0,0 +1,48 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test that @optional for @protocol works. */ + +@protocol MyProtocol ++ (int)classMethod; +- (int)method; +@optional ++ (int)optionalClassMethod; +- (int)optionalMethod; +@end + +@interface MyRootClass <MyProtocol> +@end + +/* The implementation implements both the @required methods, but none + of the @optional ones. There should be no warnings as the + @optional methods are optional. ;-) */ +@implementation MyRootClass ++ (int)classMethod +{ + return 20; +} +- (int)method +{ + return 11; +} +@end + +int function (id <MyProtocol> object1, + MyRootClass *object2) +{ + /* Test that there are no warnings if you try to use an @optional + method with an object of the class. */ + int i = 0; + + i += [object1 method]; + i += [object2 method]; + i += [MyRootClass classMethod]; + i += [object1 optionalMethod]; + i += [object2 optionalMethod]; + i += [MyRootClass optionalClassMethod]; + + return i; +} diff --git a/gcc/testsuite/objc.dg/protocol-qualifier-1.m b/gcc/testsuite/objc.dg/protocol-qualifier-1.m new file mode 100644 index 000000000..c84bfbfa2 --- /dev/null +++ b/gcc/testsuite/objc.dg/protocol-qualifier-1.m @@ -0,0 +1,33 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test that protocol qualifiers work in the same way with @class and @interface. */ + +#include <objc/objc.h> + +@protocol MyProtocol +- (void) method; +@end + + +/* This first snippet gives no warnings, which is correct as 'object' + implements <MyProtocol> and hence responds to 'method'. Note how + the details of the class 'MyClass' are never used. */ +@interface MyClass +@end + +void test (MyClass <MyProtocol> *object) +{ + [object method]; +} + + +/* This second snippet should behave identically. 'object' still implements + the same protocol and responds to 'method'. The details of MyClass or + MyClass2 are irrelevant. */ +@class MyClass2; + +void test2 (MyClass2 <MyProtocol> *object) +{ + [object method]; +} diff --git a/gcc/testsuite/objc.dg/protocol-qualifier-2.m b/gcc/testsuite/objc.dg/protocol-qualifier-2.m new file mode 100644 index 000000000..fd25d8ff6 --- /dev/null +++ b/gcc/testsuite/objc.dg/protocol-qualifier-2.m @@ -0,0 +1,31 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test that protocol qualifiers are maintained correctly when a + @class is replaced by its @interface. */ + +#include <objc/objc.h> + +@protocol MyProtocol +- (void) method; +@end + +@class MyClass; + +static MyClass <MyProtocol> *object1; +static MyClass *object2; + +/* Declarating the @interface now will need to update all the existing + ObjC types referring to MyClass with the new information. We need + to test that protocol information is not lost in the process. */ +@interface MyClass +@end + +void test1 (void) +{ + [object1 method]; /* Ok */ + [object2 method]; /* { dg-warning ".MyClass. may not respond to ..method." } */ + /* { dg-warning "without a matching method" "" { target *-*-* } 27 } */ + /* { dg-warning "will be assumed to return" "" { target *-*-* } 27 } */ + /* { dg-warning "as arguments" "" { target *-*-* } 27 } */ +} diff --git a/gcc/testsuite/objc.dg/selector-1.m b/gcc/testsuite/objc.dg/selector-1.m new file mode 100644 index 000000000..f0781b68c --- /dev/null +++ b/gcc/testsuite/objc.dg/selector-1.m @@ -0,0 +1,27 @@ +/* Test warning for non existing selectors. */ +/* Contributed by Devang Patel <dpatel@apple.com>. */ +/* { dg-options "-Wselector" } */ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ + +typedef struct objc_object { struct objc_class *class_pointer; } *id; +typedef struct objc_selector *SEL; + +@interface Foo +- (void) foo; +- (void) bar; +@end + +@implementation Foo +- (void) bar +{ +} + +- (void) foo +{ + SEL a,b,c; + a = @selector(b1ar); /* { dg-warning "creating selector for nonexistent method .b1ar." } */ + b = @selector(bar); +} +@end + diff --git a/gcc/testsuite/objc.dg/selector-2.m b/gcc/testsuite/objc.dg/selector-2.m new file mode 100644 index 000000000..ab8eb3e45 --- /dev/null +++ b/gcc/testsuite/objc.dg/selector-2.m @@ -0,0 +1,16 @@ +/* Test that we don't ICE when issuing a -Wselector warning. */ +/* { dg-options "-Wselector" } */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@interface Foo +@end +@implementation Foo +-(void) foo +{ + SEL a; + a = @selector(b1ar); +} +@end +/* { dg-warning "creating selector for nonexistent method .b1ar." "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/objc.dg/selector-3.m b/gcc/testsuite/objc.dg/selector-3.m new file mode 100644 index 000000000..c0c5f3d8f --- /dev/null +++ b/gcc/testsuite/objc.dg/selector-3.m @@ -0,0 +1,30 @@ +/* Test warning for non-existent selectors. */ +/* This is the "-fgnu-runtime" variant of objc.dg/selector-1.m. */ +/* { dg-options "-Wselector" } */ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +typedef struct objc_object { struct objc_class *class_pointer; } *id; +typedef const struct objc_selector *SEL; + +@interface Foo +- (void) foo; +- (void) bar; +@end + +@implementation Foo +- (void) bar +{ +} + +- (void) foo +{ + SEL a,b,c; + a = @selector(b1ar); + b = @selector(bar); +} +@end + +/* FIXME: The error message should be on the correct line. */ +/* { dg-warning "creating selector for nonexistent method .b1ar." "" { target *-*-* } 0 } */ + diff --git a/gcc/testsuite/objc.dg/selector-4.m b/gcc/testsuite/objc.dg/selector-4.m new file mode 100644 index 000000000..d34f8c89c --- /dev/null +++ b/gcc/testsuite/objc.dg/selector-4.m @@ -0,0 +1,30 @@ +/* Test whether including C++ keywords such as 'and', 'or', + 'not', etc., is allowed inside ObjC selectors (as it must be). */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do compile } */ + +@interface Int1 ++ (int)and_eq:(int)arg1 and:(int)arg2; +- (int)or_eq:(int)arg1 or:(int)arg3; +- (int)not:(int)arg1 xor:(int)arg2; +- (void)bitand:(char)c1 bitor:(char)c2; +- (void)compl:(float)f1 xor_eq:(double)d1; +- (void)not_eq; +@end + +@implementation Int1 ++ (int)and_eq:(int)arg1 and:(int)arg2 { return arg1 + arg2; } +- (int)or_eq:(int)arg1 or:(int)arg3 { return arg1 + arg3; } +- (int)not:(int)arg1 xor:(int)arg2 { return arg1 + arg2; } +- (void)bitand:(char)c1 bitor:(char)c2 { } +- (void)compl:(float)f1 xor_eq:(double)d1 { } +- (void)not_eq { } +@end + +/* { dg-final { scan-assembler "\\+\\\[Int1 and_eq:and:\\]|c_Int1__and_eq_and" } } */ +/* { dg-final { scan-assembler "\\-\\\[Int1 or_eq:or:\\]|i_Int1__or_eq_or" } } */ +/* { dg-final { scan-assembler "\\-\\\[Int1 not:xor:\\]|i_Int1__not_xor" } } */ +/* { dg-final { scan-assembler "\\-\\\[Int1 bitand:bitor:\\]|i_Int1__bitand_bitor" } } */ +/* { dg-final { scan-assembler "\\-\\\[Int1 compl:xor_eq:\\]|i_Int1__compl_xor_eq" } } */ +/* { dg-final { scan-assembler "\\-\\\[Int1 not_eq\\]|i_Int1__not_eq" } } */ diff --git a/gcc/testsuite/objc.dg/selector-warn-1.m b/gcc/testsuite/objc.dg/selector-warn-1.m new file mode 100644 index 000000000..b4b308d7b --- /dev/null +++ b/gcc/testsuite/objc.dg/selector-warn-1.m @@ -0,0 +1,16 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, January 2011. */ +/* { dg-options "-Wselector" } */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface RootObject +@end + +@interface MyObject : RootObject +- (void) method; /* { dg-message "found" } */ +@end + +@interface MyObject2 : RootObject +- (int) method; /* { dg-message "also found" } */ +@end /* { dg-warning "multiple selectors named .-method. found" } */ diff --git a/gcc/testsuite/objc.dg/set-not-used-1.m b/gcc/testsuite/objc.dg/set-not-used-1.m new file mode 100644 index 000000000..6380ec9df --- /dev/null +++ b/gcc/testsuite/objc.dg/set-not-used-1.m @@ -0,0 +1,36 @@ + +/* { dg-do compile } */ +/* { dg-options "-Wunused-but-set-variable" } */ + +#import "../objc-obj-c++-shared/Object1.h" +#include <objc/objc-api.h> + +@interface obj : Object +{ + int value; +} +- (int) value; +- (void) setValue: (int)number; +@end + +@implementation obj : Object + +- (int) value { return value; } +- (void) setValue: (int)number { value = number; } + +@end + +int main (void) +{ + obj *a; /* { dg-bogus "set but not used" } */ + obj *b; /* { dg-bogus "set but not used" } */ + obj *c; /* { dg-warning "set but not used" } */ + + a = [obj new]; + b = [obj new]; + c = [obj new]; + + [b setValue: [a value]]; + + return [a value]; +} diff --git a/gcc/testsuite/objc.dg/sizeof-1.m b/gcc/testsuite/objc.dg/sizeof-1.m new file mode 100644 index 000000000..ae505c1e8 --- /dev/null +++ b/gcc/testsuite/objc.dg/sizeof-1.m @@ -0,0 +1,34 @@ +/* Check that the sizeof() operator works with ObjC classes and their aliases. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "" } */ +/* { dg-do run } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include <objc/objc.h> + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort(); + +@interface Foo: Object { + int a, b; + float c, d; +} +@end + +@implementation Foo +@end + +typedef Object MyObject; +typedef struct Foo Foo_type; + +@compatibility_alias AliasObject Object; + +int main(void) { + CHECK_IF(sizeof(Foo) > sizeof(Object) && sizeof(Object) > 0); + CHECK_IF(sizeof(Foo) == sizeof(Foo_type)); + CHECK_IF(sizeof(Object) == sizeof(MyObject)); + CHECK_IF(sizeof(Object) == sizeof(AliasObject)); + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/special/load-category-1.h b/gcc/testsuite/objc.dg/special/load-category-1.h new file mode 100644 index 000000000..7810487df --- /dev/null +++ b/gcc/testsuite/objc.dg/special/load-category-1.h @@ -0,0 +1,20 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ + +/* Test that +load works when a category is defined in a different + module than the main class. */ + +/* This function should be called any time +load is invoked, so we can + keep the count. */ +extern int increase_load_count (void); + +@interface TestClass1 +{ + id isa; +} +@end + +@interface TestClass2 +{ + id isa; +} +@end diff --git a/gcc/testsuite/objc.dg/special/load-category-1.m b/gcc/testsuite/objc.dg/special/load-category-1.m new file mode 100644 index 000000000..cb221436f --- /dev/null +++ b/gcc/testsuite/objc.dg/special/load-category-1.m @@ -0,0 +1,39 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <stdlib.h> +#include <objc/objc.h> + +#include "load-category-1.h" + +@implementation TestClass1 ++ initialize { return self; } ++ load +{ + increase_load_count (); +} +@end + +@implementation TestClass2 (Category) ++ load +{ + increase_load_count (); +} +@end + + +static int load_count = 0; + +int increase_load_count (void) +{ + load_count++; +} + +int main (void) +{ + if (load_count != 4) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/special/load-category-1a.m b/gcc/testsuite/objc.dg/special/load-category-1a.m new file mode 100644 index 000000000..cdcb7d829 --- /dev/null +++ b/gcc/testsuite/objc.dg/special/load-category-1a.m @@ -0,0 +1,21 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ + +#include <stdlib.h> +#include <objc/objc.h> + +#include "load-category-1.h" + +@implementation TestClass2 ++ initialize { return self; } ++ load +{ + increase_load_count (); +} +@end + +@implementation TestClass1 (Category) ++ load +{ + increase_load_count (); +} +@end diff --git a/gcc/testsuite/objc.dg/special/load-category-2.h b/gcc/testsuite/objc.dg/special/load-category-2.h new file mode 100644 index 000000000..ae7e84278 --- /dev/null +++ b/gcc/testsuite/objc.dg/special/load-category-2.h @@ -0,0 +1,19 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ + +/* Test the order of calling +load between classes and categories. */ + +void complete_load_step (int load_step); +void check_that_load_step_was_completed (int load_step); +void check_that_load_step_was_not_completed (int load_step); + +@interface TestClass1 +{ + id isa; +} +@end + +@interface TestClass2 : TestClass1 +@end + +@interface TestClass3 : TestClass2 +@end diff --git a/gcc/testsuite/objc.dg/special/load-category-2.m b/gcc/testsuite/objc.dg/special/load-category-2.m new file mode 100644 index 000000000..7dc745952 --- /dev/null +++ b/gcc/testsuite/objc.dg/special/load-category-2.m @@ -0,0 +1,105 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <stdio.h> +#include <stdlib.h> +#include <objc/objc.h> + +#include "load-category-2.h" + +/* This test tests that +load is called in the correct order for + classes and categories. +load needs to be called in superclasses + before subclasses, and in the main class before categories. */ + +/* Compile the classes in random order to prevent the runtime from + sending +load in the correct order just because the classes happen + to have been compiled in that order. */ +@implementation TestClass2 ++ load +{ + printf ("[TestClass2 +load]\n"); + /* Check superclasses/subclasses +load order. */ + check_that_load_step_was_completed (0); + check_that_load_step_was_not_completed (1); + check_that_load_step_was_not_completed (2); + + /* Check that the corresponding category's +load was not done. */ + check_that_load_step_was_not_completed (4); + + complete_load_step (1); +} +@end + +@implementation TestClass3 ++ load +{ + printf ("[TestClass3 +load]\n"); + + /* Check superclasses/subclasses +load order. */ + check_that_load_step_was_completed (0); + check_that_load_step_was_completed (1); + check_that_load_step_was_not_completed (2); + + /* Check that the corresponding category's +load was not done. */ + check_that_load_step_was_not_completed (5); + + complete_load_step (2); +} +@end + +@implementation TestClass1 ++ initialize { return self; } ++ load +{ + printf ("[TestClass1 +load]\n"); + + /* Check superclasses/subclasses +load order. */ + check_that_load_step_was_not_completed (0); + check_that_load_step_was_not_completed (1); + check_that_load_step_was_not_completed (2); + + /* Check that the corresponding category's +load was not done. */ + check_that_load_step_was_not_completed (3); + + complete_load_step (0); +} +@end + + +static BOOL load_step_completed[6] = { NO, NO, NO, NO, NO, NO }; + +void complete_load_step (int load_step) +{ + load_step_completed[load_step] = YES; +} + +void check_that_load_step_was_completed (int load_step) +{ + if (load_step_completed[load_step] == NO) + { + printf ("Load step %d was not completed but should have been\n", load_step); + abort (); + } +} + +void check_that_load_step_was_not_completed (int load_step) +{ + if (load_step_completed[load_step] == YES) + { + printf ("Load step %d was completed but shouldn't have been\n", load_step); + abort (); + } +} + +int main (void) +{ + check_that_load_step_was_completed (0); + check_that_load_step_was_completed (1); + check_that_load_step_was_completed (2); + check_that_load_step_was_completed (3); + check_that_load_step_was_completed (4); + check_that_load_step_was_completed (5); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/special/load-category-2a.m b/gcc/testsuite/objc.dg/special/load-category-2a.m new file mode 100644 index 000000000..6b81240db --- /dev/null +++ b/gcc/testsuite/objc.dg/special/load-category-2a.m @@ -0,0 +1,46 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ + +#include <stdio.h> +#include <stdlib.h> +#include <objc/objc.h> + +#include "load-category-2.h" + +/* Compile the categories in random order to prevent the runtime from + sending +load in the correct order just because the classes happen + to have been compiled in that order. */ +@implementation TestClass2 (Category) ++ load +{ + printf ("[TestClass2(Category) +load]\n"); + + /* Check that the corresponding class's +load was done. */ + check_that_load_step_was_completed (1); + + complete_load_step (4); +} +@end + +@implementation TestClass3 (Category) ++ load +{ + printf ("[TestClass3(Category) +load]\n"); + + /* Check that the corresponding class's +load was done. */ + check_that_load_step_was_completed (2); + + complete_load_step (5); +} +@end + +@implementation TestClass1 (Category) ++ load +{ + printf ("[TestClass1(Category) +load]\n"); + + /* Check that the corresponding class's +load was done. */ + check_that_load_step_was_completed (0); + + complete_load_step (3); +} +@end diff --git a/gcc/testsuite/objc.dg/special/load-category-3.h b/gcc/testsuite/objc.dg/special/load-category-3.h new file mode 100644 index 000000000..9d6d8acc9 --- /dev/null +++ b/gcc/testsuite/objc.dg/special/load-category-3.h @@ -0,0 +1,17 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ + +void complete_load_step (int load_step); +void check_that_load_step_was_completed (int load_step); +void check_that_load_step_was_not_completed (int load_step); + +@interface TestClass1 +{ + id isa; +} +@end + +@interface TestClass2 : TestClass1 +@end + +@interface TestClass3 : TestClass2 +@end diff --git a/gcc/testsuite/objc.dg/special/load-category-3.m b/gcc/testsuite/objc.dg/special/load-category-3.m new file mode 100644 index 000000000..b89d8f152 --- /dev/null +++ b/gcc/testsuite/objc.dg/special/load-category-3.m @@ -0,0 +1,87 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* This test is identical to load-category-2, but the classes and + categories are created in inverted order in the modules, to test + that you can load classes first, or categories first, and it all + still works in both cases. */ + +#include <stdio.h> +#include <stdlib.h> +#include <objc/objc.h> + +#include "load-category-3.h" + +@implementation TestClass2 (Category) ++ load +{ + printf ("[TestClass2(Category) +load]\n"); + + /* Check that the corresponding class's +load was done. */ + check_that_load_step_was_completed (1); + + complete_load_step (4); +} +@end + +@implementation TestClass3 (Category) ++ load +{ + printf ("[TestClass3(Category) +load]\n"); + + /* Check that the corresponding class's +load was done. */ + check_that_load_step_was_completed (2); + + complete_load_step (5); +} +@end + +@implementation TestClass1 (Category) ++ load +{ + printf ("[TestClass1(Category) +load]\n"); + + /* Check that the corresponding class's +load was done. */ + check_that_load_step_was_completed (0); + + complete_load_step (3); +} +@end + +static BOOL load_step_completed[6] = { NO, NO, NO, NO, NO, NO }; + +void complete_load_step (int load_step) +{ + load_step_completed[load_step] = YES; +} + +void check_that_load_step_was_completed (int load_step) +{ + if (load_step_completed[load_step] == NO) + { + printf ("Load step %d was not completed but should have been\n", load_step); + abort (); + } +} + +void check_that_load_step_was_not_completed (int load_step) +{ + if (load_step_completed[load_step] == YES) + { + printf ("Load step %d was completed but shouldn't have been\n", load_step); + abort (); + } +} + +int main (void) +{ + check_that_load_step_was_completed (0); + check_that_load_step_was_completed (1); + check_that_load_step_was_completed (2); + check_that_load_step_was_completed (3); + check_that_load_step_was_completed (4); + check_that_load_step_was_completed (5); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/special/load-category-3a.m b/gcc/testsuite/objc.dg/special/load-category-3a.m new file mode 100644 index 000000000..5ce5fac65 --- /dev/null +++ b/gcc/testsuite/objc.dg/special/load-category-3a.m @@ -0,0 +1,65 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ + +/* This test is identical to load-category-2, but the classes and + categories are created in inverted order in the modules, to test + that you can load classes first, or categories first, and it all + still works. */ + +#include <stdio.h> +#include <stdlib.h> +#include <objc/objc.h> + +#include "load-category-3.h" + +@implementation TestClass2 ++ load +{ + printf ("[TestClass2 +load]\n"); + /* Check superclasses/subclasses +load order. */ + check_that_load_step_was_completed (0); + check_that_load_step_was_not_completed (1); + check_that_load_step_was_not_completed (2); + + /* Check that the corresponding category's +load was not done. */ + check_that_load_step_was_not_completed (4); + + complete_load_step (1); +} +@end + +@implementation TestClass3 ++ load +{ + printf ("[TestClass3 +load]\n"); + + /* Check superclasses/subclasses +load order. */ + check_that_load_step_was_completed (0); + check_that_load_step_was_completed (1); + check_that_load_step_was_not_completed (2); + + /* Check that the corresponding category's +load was not done. */ + check_that_load_step_was_not_completed (5); + + complete_load_step (2); +} +@end + +@implementation TestClass1 ++ initialize { return self; } ++ load +{ + printf ("[TestClass1 +load]\n"); + + /* Check superclasses/subclasses +load order. */ + check_that_load_step_was_not_completed (0); + check_that_load_step_was_not_completed (1); + check_that_load_step_was_not_completed (2); + + /* Check that the corresponding category's +load was not done. */ + check_that_load_step_was_not_completed (3); + + complete_load_step (0); +} +@end + + diff --git a/gcc/testsuite/objc.dg/special/special.exp b/gcc/testsuite/objc.dg/special/special.exp new file mode 100644 index 000000000..bab6798d9 --- /dev/null +++ b/gcc/testsuite/objc.dg/special/special.exp @@ -0,0 +1,145 @@ +# GCC Objective-C testsuite that uses the `dg.exp' driver. +# Copyright (C) 1997, 2001, 2007, 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Load support procs. +load_lib objc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS "" +} + +# Initialize `dg'. +dg-init + +# TODO: All these testcases compile and link two Objective-C modules. +# Remove code duplication and factor the common code out. + +# +# unclaimed-category-1 test +# +# This test is special because we must compile two different modules, +# unclaimed-category-1a.m and unclaimed-category-1.m, then link +# together, then run the resulting executable. +# for all systems we point to the libobjc includes and use the -fgnu-runtime +set add_flags "additional_flags=-I${srcdir}/../../libobjc" +lappend add_flags "additional_flags=-fgnu-runtime" +set lines [objc_target_compile "$srcdir/$subdir/unclaimed-category-1a.m" "unclaimed-category-1a.o" object $add_flags ] +if ![string match "" $lines] then { + fail "unclaimed-category-1a.o" +} else { + dg-runtest "$srcdir/$subdir/unclaimed-category-1.m" "unclaimed-category-1a.o" "-I${srcdir}/../../libobjc -fgnu-runtime" + file delete unclaimed-category-1a.o +} + +if [istarget "*-*-darwin*" ] { +set add_flags "" +lappend add_flags "additional_flags=-fnext-runtime" +set lines [objc_target_compile "$srcdir/$subdir/unclaimed-category-1a.m" "unclaimed-category-1a.o" object $add_flags ] +if ![string match "" $lines] then { + fail "unclaimed-category-1a.o" +} else { + dg-runtest "$srcdir/$subdir/unclaimed-category-1.m" "unclaimed-category-1a.o" "-fnext-runtime" + file delete unclaimed-category-1a.o +} +} + +# +# load-category-1 test +# +# This test is similar to the one above. We compile load-category-1.m +# and load-category-1a.m, link them together, and execute the result. +set add_flags "additional_flags=-I${srcdir}/../../libobjc" +lappend add_flags "additional_flags=-fgnu-runtime" +set lines [objc_target_compile "$srcdir/$subdir/load-category-1a.m" "load-category-1a.o" object $add_flags ] +if ![string match "" $lines] then { + fail "load-category-1a.o" +} else { + dg-runtest "$srcdir/$subdir/load-category-1.m" "load-category-1a.o" "-I${srcdir}/../../libobjc -fgnu-runtime" + file delete load-category-1a.o +} + +if [istarget "*-*-darwin*" ] { +set add_flags "" +lappend add_flags "additional_flags=-fnext-runtime" +set lines [objc_target_compile "$srcdir/$subdir/load-category-1a.m" "load-category-1a.o" object $add_flags ] +if ![string match "" $lines] then { + fail "load-category-1a.o" +} else { + dg-runtest "$srcdir/$subdir/load-category-1.m" "load-category-1a.o" "-fnext-runtime" + file delete load-category-1a.o +} +} + +# +# load-category-2 test +# +# This test is similar to the one above. We compile load-category-2.m +# and load-category-2a.m, link them together, and execute the result. +set add_flags "additional_flags=-I${srcdir}/../../libobjc" +lappend add_flags "additional_flags=-fgnu-runtime" +set lines [objc_target_compile "$srcdir/$subdir/load-category-2a.m" "load-category-2a.o" object $add_flags ] +if ![string match "" $lines] then { + fail "load-category-2a.o" +} else { + dg-runtest "$srcdir/$subdir/load-category-2.m" "load-category-2a.o" "-I${srcdir}/../../libobjc -fgnu-runtime" + file delete load-category-2a.o +} + +if [istarget "*-*-darwin*" ] { +set add_flags "" +lappend add_flags "additional_flags=-fnext-runtime" +set lines [objc_target_compile "$srcdir/$subdir/load-category-2a.m" "load-category-2a.o" object $add_flags ] +if ![string match "" $lines] then { + fail "load-category-2a.o" +} else { + dg-runtest "$srcdir/$subdir/load-category-2.m" "load-category-2a.o" "-fnext-runtime" + file delete load-category-2a.o +} +} + +# +# load-category-3 test +# +# This test is similar to the one above. We compile load-category-3.m +# and load-category-3a.m, link them together, and execute the result. +set add_flags "additional_flags=-I${srcdir}/../../libobjc" +lappend add_flags "additional_flags=-fgnu-runtime" +set lines [objc_target_compile "$srcdir/$subdir/load-category-3a.m" "load-category-3a.o" object $add_flags ] +if ![string match "" $lines] then { + fail "load-category-3a.o" +} else { + dg-runtest "$srcdir/$subdir/load-category-3.m" "load-category-3a.o" "-I${srcdir}/../../libobjc -fgnu-runtime" + file delete load-category-3a.o +} + +if [istarget "*-*-darwin*" ] { +set add_flags "" +lappend add_flags "additional_flags=-fnext-runtime" +set lines [objc_target_compile "$srcdir/$subdir/load-category-3a.m" "load-category-3a.o" object $add_flags ] +if ![string match "" $lines] then { + fail "load-category-3a.o" +} else { + dg-runtest "$srcdir/$subdir/load-category-3.m" "load-category-3a.o" "-fnext-runtime" + file delete load-category-3a.o +} +} + +# All done. +dg-finish + diff --git a/gcc/testsuite/objc.dg/special/unclaimed-category-1.h b/gcc/testsuite/objc.dg/special/unclaimed-category-1.h new file mode 100644 index 000000000..bf507a788 --- /dev/null +++ b/gcc/testsuite/objc.dg/special/unclaimed-category-1.h @@ -0,0 +1,29 @@ +/* Contributed by Nicola Pero - Fri Dec 14 08:36:00 GMT 2001 */ + +/* Test loading unclaimed categories - categories of a class defined + separately from the class itself. */ + +@interface TestClass +{ +#ifdef __OBJC2__ + Class isa; +#else + id isa; +#endif +} +- (int)D; +@end + +@interface TestClass (A) +- (int)A; +@end + +@interface TestClass (B) +- (int)B; +@end + +@interface TestClass (C) +- (int)C; +@end + + diff --git a/gcc/testsuite/objc.dg/special/unclaimed-category-1.m b/gcc/testsuite/objc.dg/special/unclaimed-category-1.m new file mode 100644 index 000000000..88e3d8ea7 --- /dev/null +++ b/gcc/testsuite/objc.dg/special/unclaimed-category-1.m @@ -0,0 +1,75 @@ +/* Contributed by Nicola Pero - Fri Dec 14 08:36:00 GMT 2001 */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <objc/objc.h> +#ifndef __NEXT_RUNTIME__ +#include <objc/objc-api.h> +#endif +#include "../../objc-obj-c++-shared/next-mapping.h" + +extern void abort (void); + +/* Test loading unclaimed categories - categories of a class defined + separately from the class itself. */ + + +/* unclaimed-category-1.m contains only the class definition but not + the categories. unclaimed-category-1a.m contains only the + categories of the class, but not the class itself. We want to + check that the runtime can load the class from one module (file) + and the categories from another module (file). */ + +#include "unclaimed-category-1.h" + +@implementation TestClass +- (int)D +{ + return 4; +} +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif +@end + + +int main (void) +{ + TestClass *test; + Class testClass; + + testClass = objc_get_class ("TestClass"); + if (testClass == Nil) + { + abort (); + } + + test = (TestClass *)(class_create_instance (testClass)); + if (test == nil) + { + abort (); + } + + if ([test A] != 1) + { + abort (); + } + + if ([test B] != 2) + { + abort (); + } + + if ([test C] != 3) + { + abort (); + } + + + if ([test D] != 4) + { + abort (); + } + + return 0; +} diff --git a/gcc/testsuite/objc.dg/special/unclaimed-category-1a.m b/gcc/testsuite/objc.dg/special/unclaimed-category-1a.m new file mode 100644 index 000000000..4fb2d4619 --- /dev/null +++ b/gcc/testsuite/objc.dg/special/unclaimed-category-1a.m @@ -0,0 +1,29 @@ +/* Contributed by Nicola Pero - Fri Dec 14 08:36:00 GMT 2001 */ + +/* Test loading unclaimed categories - categories of a class defined + separately from the class itself. */ + +#include "unclaimed-category-1.h" + +@implementation TestClass (A) +- (int)A +{ + return 1; +} +@end + +@implementation TestClass (B) +- (int)B +{ + return 2; +} +@end + +@implementation TestClass (C) +- (int)C +{ + return 3; +} +@end + + diff --git a/gcc/testsuite/objc.dg/stabs-1.m b/gcc/testsuite/objc.dg/stabs-1.m new file mode 100644 index 000000000..f1f2e8e12 --- /dev/null +++ b/gcc/testsuite/objc.dg/stabs-1.m @@ -0,0 +1,18 @@ +/* Check if the final SO STABS record goes into the .text section. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile } */ +/* { dg-skip-if "No stabs" { mmix-*-* *-*-aix* alpha*-*-* hppa*64*-*-* ia64-*-* } { "*" } { "" } } */ +/* { dg-options "-gstabs" } */ + +@interface MyClass ++ newWithArg: arg; +@end + +@implementation MyClass ++ newWithArg: arg +{ +} +@end + +/* { dg-final { scan-assembler "(.SUBSPA.*\[\$\]CODE\[\$\]|.text\"?)\n\t.stabs.*100,0,0,(\[\.\$\])?L?L\[\$\]?etext\[0-9\]*\n(\[\.\$\])?L?L\[\$\]?etext" } } */ diff --git a/gcc/testsuite/objc.dg/static-1.m b/gcc/testsuite/objc.dg/static-1.m new file mode 100644 index 000000000..d62015859 --- /dev/null +++ b/gcc/testsuite/objc.dg/static-1.m @@ -0,0 +1,33 @@ +/* Test out static (non-heap) allocations of ObjC class instances. + These should elicit errors. */ +/* Developed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +@interface Object { + struct objc_class *isa; +} +@end + +@compatibility_alias MyObject Object; + +@interface Foo: Object { + int a; + Object *b; + Object c; /* { dg-error "statically allocated instance of Objective-C class .Object." } */ +} +@end + +@compatibility_alias MyFoo Foo; + +typedef Foo FooAlias1; +typedef FooAlias1 FooAlias2; +typedef Object ObjectAlias1; +typedef struct Object ObjectAlias2; +Object staticObject1; /* { dg-error "statically allocated instance of Objective-C class .Object." } */ +struct Object staticObject2; /* { dg-error "statically allocated instance of Objective-C class .Object." } */ +static ObjectAlias1 staticObject3; /* { dg-error "statically allocated instance of Objective-C class .Object." } */ +FooAlias1 staticFoo1; /* { dg-error "statically allocated instance of Objective-C class .Foo." } */ +extern FooAlias2 externFoo1; /* { dg-error "statically allocated instance of Objective-C class .Foo." } */ +static Foo staticFoo2; /* { dg-error "statically allocated instance of Objective-C class .Foo." } */ +MyObject staticMyObject1; /* { dg-error "statically allocated instance of Objective-C class .Object." } */ +MyFoo staticMyFoo1; /* { dg-error "statically allocated instance of Objective-C class .Foo." } */ diff --git a/gcc/testsuite/objc.dg/stret-1.m b/gcc/testsuite/objc.dg/stret-1.m new file mode 100644 index 000000000..cae7d6dd6 --- /dev/null +++ b/gcc/testsuite/objc.dg/stret-1.m @@ -0,0 +1,65 @@ +/* Test for handling of struct-returning methods. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +struct astruct { + float a, b; +} globa = { 1.0, 2.0 }; + +struct bstruct { + float a, b, c, d, e, f; +} globb = { 1, 2, 3, 4, 5, 6 }; + +@interface foo : Object +- (struct astruct) stret; +- (struct bstruct) stretb; +@end + +@implementation foo : Object +- (struct astruct) stret { return globa; } +- (struct bstruct) stretb { return globb; } +@end + +@interface bar: foo +- (struct astruct) stret; +- (struct bstruct) stretb; +@end + +@implementation bar +- (struct astruct) stret { struct astruct a = [super stret]; a.b = 77; return a; } +- (struct bstruct) stretb { struct bstruct b = [super stretb]; b.e = 99; return b; } +@end + +int main(void) +{ + foo *obj = [foo new]; + bar *obj2 = [bar new]; + struct astruct loc, loc2; + struct bstruct locb, locb2; + + loc = [obj stret]; + CHECK_IF(loc.a == 1.0 && loc.b == 2.0); + + locb = [obj stretb]; + CHECK_IF(locb.f == 6 && locb.c == 3); + CHECK_IF(locb.e == 5 && locb.b == 2); + CHECK_IF(locb.d == 4 && locb.a == 1); + + loc2 = [obj2 stret]; + CHECK_IF(loc2.a == 1.0 && loc2.b == 77); + + locb2 = [obj2 stretb]; + CHECK_IF(locb2.f == 6 && locb2.c == 3); + CHECK_IF(locb2.e == 99 && locb2.b == 2); + CHECK_IF(locb2.d == 4 && locb2.a == 1); + + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/stret-2.m b/gcc/testsuite/objc.dg/stret-2.m new file mode 100644 index 000000000..e0fd8c2d8 --- /dev/null +++ b/gcc/testsuite/objc.dg/stret-2.m @@ -0,0 +1,49 @@ +/* Test for handling of struct-returning methods + for the Mac OS X ("NeXT") runtime (which uses specialized entry + points). */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-require-effective-target ilp32 } */ + +#include "../objc-obj-c++-shared/Object1.h" + +struct astruct { + float a, b; + char c; +} glob = { 1.0, 2.0, 'a' }; + +struct bstruct { + float a, b, c, d, e, f; +} globb = { 1, 2, 3, 4, 5, 6 }; + +@interface foo : Object +- (struct astruct) stret; +- (struct bstruct) stretb; +@end + +@implementation foo : Object +- (struct astruct) stret { return glob; } +- (struct bstruct) stretb { return globb; } +@end + +@interface bar: foo +- (struct astruct) stret; +- (struct bstruct) stretb; +@end + +@implementation bar +- (struct astruct) stret { return [super stret]; } +- (struct bstruct) stretb { return [super stretb]; } +@end + +struct astruct afunc(foo *foo_obj) { + return [foo_obj stret]; +} + +/* { dg-final { scan-assembler "objc_msgSend_stret" } } */ +/* { dg-final { scan-assembler "objc_msgSendSuper_stret" } } */ + +/* { dg-final { scan-assembler-not "objc_msgSend\[^_S\]" } } */ +/* { dg-final { scan-assembler-not "objc_msgSendSuper\[^_\]" } } */ + diff --git a/gcc/testsuite/objc.dg/strings/const-cfstring-2.m b/gcc/testsuite/objc.dg/strings/const-cfstring-2.m new file mode 100644 index 000000000..14ae68c6c --- /dev/null +++ b/gcc/testsuite/objc.dg/strings/const-cfstring-2.m @@ -0,0 +1,27 @@ +/* Test the -Wnonportable-cfstrings option, which should give + warnings if non-ASCII characters are embedded in constant + CFStrings. This will only work on MacOS X 10.2 and later. */ +/* Developed by Ziemowit Laski <zlaski@apple.com>. */ + +/* So far, CFString is darwin-only. */ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "NeXT only" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-mconstant-cfstrings -Wnonportable-cfstrings" } */ + +#import <Foundation/NSString.h> +#import <CoreFoundation/CFString.h> + +#ifndef __CONSTANT_CFSTRINGS__ +#error The -fconstant-cfstrings option is not functioning properly +#endif + +void foo(void) { + NSString *s1 = @"Compile-time string literal"; + CFStringRef s2 = CFSTR("Compile-time string literal"); + NSString *s3 = @"Non-ASCII literal - \222"; /* { dg-warning "non-ASCII character in CFString literal" } */ + CFStringRef s4 = CFSTR("\222 - Non-ASCII literal"); /* { dg-warning "non-ASCII character in CFString literal" } */ + CFStringRef s5 = CFSTR("Non-ASCII (\222) literal"); /* { dg-warning "non-ASCII character in CFString literal" } */ + NSString *s6 = @"\0Embedded NUL"; /* { dg-warning "embedded NUL in CFString literal" } */ + CFStringRef s7 = CFSTR("Embedded \0NUL"); /* { dg-warning "embedded NUL in CFString literal" } */ + CFStringRef s8 = CFSTR("Embedded NUL\0"); /* { dg-warning "embedded NUL in CFString literal" } */ +} diff --git a/gcc/testsuite/objc.dg/strings/const-cfstring-5.m b/gcc/testsuite/objc.dg/strings/const-cfstring-5.m new file mode 100644 index 000000000..13cb78957 --- /dev/null +++ b/gcc/testsuite/objc.dg/strings/const-cfstring-5.m @@ -0,0 +1,26 @@ +/* Test if constant CFStrings may be passed back as ObjC strings. */ +/* Author: Ziemowit Laski */ + +/* So far, CFString is darwin-only. */ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "NeXT only" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-mconstant-cfstrings" } */ + +#include <objc/Object.h> + +@interface Foo: Object { + char *cString; + unsigned int len; +} ++ (Foo *)description; +@end + +@interface Bar: Object ++ (Foo *) getString: (int) which; +@end + +@implementation Bar ++ (Foo *) getString: (int) which { + return which? [Foo description]: @"Hello"; +} +@end diff --git a/gcc/testsuite/objc.dg/strings/const-str-1.m b/gcc/testsuite/objc.dg/strings/const-str-1.m new file mode 100644 index 000000000..754c99bf1 --- /dev/null +++ b/gcc/testsuite/objc.dg/strings/const-str-1.m @@ -0,0 +1,25 @@ +/* Test errors for constant strings. */ +/* { dg-do compile } */ +/* { dg-options "-mno-constant-cfstrings" { target *-*-darwin* } } */ + +#ifdef __cplusplus +extern void baz(...); +#endif + +void foo() +{ + baz(@"hiya"); /* { dg-error "annot find interface declaration" } */ +} + +@interface NXConstantString +{ + void *isa; + char *str; + int len; +} +@end + +void bar() +{ + baz(@"howdah"); +} diff --git a/gcc/testsuite/objc.dg/strings/const-str-12.m b/gcc/testsuite/objc.dg/strings/const-str-12.m new file mode 100644 index 000000000..930590186 --- /dev/null +++ b/gcc/testsuite/objc.dg/strings/const-str-12.m @@ -0,0 +1,16 @@ +/* { dg-options "-Wall -funit-at-a-time" } */ +/* { dg-do compile } */ +/* PR objc/27438, make sure that the decl produced by the front-end + does not cause a warning to be produced. */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +@interface NXConstantString +{ + void *isa; + const char * const nxcsptr; + const unsigned int nxcslen; +} +@end +NXConstantString *a = @"NSInconsistentArchiveException"; /* { dg-bogus "defined but not used" } */ + + diff --git a/gcc/testsuite/objc.dg/strings/const-str-12b.m b/gcc/testsuite/objc.dg/strings/const-str-12b.m new file mode 100644 index 000000000..430ab5db2 --- /dev/null +++ b/gcc/testsuite/objc.dg/strings/const-str-12b.m @@ -0,0 +1,28 @@ +/* Test if ObjC types play nice in conditional expressions. */ +/* Author: Ziemowit Laski */ + +/* { dg-do compile } */ +/* { dg-options "-fconstant-string-class=Foo" } */ +/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=Foo" { target *-*-darwin* } } */ + +#include <objc/Object.h> +#include "../../objc-obj-c++-shared/objc-test-suite-types.h" + +@interface Foo: Object { + char *cString; + unsigned int len; +} ++ (id)description; +@end + +@interface Bar: Object ++ (Foo *) getString: (int) which; +@end + +TNS_STRING_REF_T _FooClassReference; /* Only used by NeXT. */ + +@implementation Bar ++ (Foo *) getString: (int) which { + return which? [Foo description]: @"Hello"; +} +@end diff --git a/gcc/testsuite/objc.dg/strings/const-str-2.m b/gcc/testsuite/objc.dg/strings/const-str-2.m new file mode 100644 index 000000000..49ab06304 --- /dev/null +++ b/gcc/testsuite/objc.dg/strings/const-str-2.m @@ -0,0 +1,8 @@ +/* Test the -fconstant-string-class flag error. */ +/* { dg-do compile } */ +/* { dg-options "-fconstant-string-class=" { target *-*-* } } */ +/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=" { target *-*-darwin* } } */ + +{ dg-error "no class name specified|missing argument" "" { target *-*-* } 0 } + +void foo () {} diff --git a/gcc/testsuite/objc.dg/strings/const-str-5.m b/gcc/testsuite/objc.dg/strings/const-str-5.m new file mode 100644 index 000000000..42071767a --- /dev/null +++ b/gcc/testsuite/objc.dg/strings/const-str-5.m @@ -0,0 +1,28 @@ +/* Positive test case for constant string layout. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do compile } */ +/* { dg-options "-fconstant-string-class=MyConstantString" } */ +/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=MyConstantString" { target *-*-darwin* } } */ + +@interface MyBase { + const char *p; +} +@end + +@interface MyConstantString: MyBase { + union { + void *u; + unsigned char *c; + } _contents; + unsigned int _count; +} +@end + +/* The NeXT runtime initializes the 'isa' pointer of string constants at + compile time. */ +#ifdef __NEXT_RUNTIME__ +extern void *_MyConstantStringClassReference; +#endif + +MyConstantString *str = @"Hello"; diff --git a/gcc/testsuite/objc.dg/strings/const-str-6.m b/gcc/testsuite/objc.dg/strings/const-str-6.m new file mode 100644 index 000000000..fca7643af --- /dev/null +++ b/gcc/testsuite/objc.dg/strings/const-str-6.m @@ -0,0 +1,28 @@ +/* Negative test case for constant string layout. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do compile } */ +/* { dg-options "-fconstant-string-class=MyConstantString" } */ +/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=MyConstantString" { target *-*-darwin* } } */ + +@interface MyBase { + char p; +} +@end + +@interface MyConstantString: MyBase { + union { + void *u; + unsigned char *c; + } _contents; + char _count; +} +@end + +/* The NeXT runtime initializes the 'isa' pointer of string constants at + compile time. */ +#ifdef __NEXT_RUNTIME__ +extern void *_MyConstantStringClassReference; +#endif + +MyConstantString *str = @"Hello"; /* { dg-error "interface .MyConstantString. does not have valid constant string layout" } */ diff --git a/gcc/testsuite/objc.dg/strings/strings-1.m b/gcc/testsuite/objc.dg/strings/strings-1.m new file mode 100644 index 000000000..fc3f21185 --- /dev/null +++ b/gcc/testsuite/objc.dg/strings/strings-1.m @@ -0,0 +1,33 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +#include "../../objc-obj-c++-shared/Object1.h" +#include "../../objc-obj-c++-shared/next-mapping.h" +#ifndef __NEXT_RUNTIME__ +#include <objc/NXConstStr.h> +#endif + +/* The following are correct. */ +id test_valid1 = @"test"; +id test_valid2 = @"te" @"st"; +id test_valid3 = @"te" @"s" @"t"; +id test_valid4 = @ "t" @ "e" @ "s" @ "t"; + +/* The following are accepted too; you can concat an ObjC string to a + C string, the result being an ObjC string. */ +id test_valid5 = @"te" "st"; +id test_valid6 = @"te" "s" @"t"; +id test_valid7 = @"te" @"s" "t"; + +/* The following are not correct. */ +id test_invalid1 = @@"test"; /* { dg-error "stray .@. in program" } */ +const char *test_invalid2 = "test"@; /* { dg-error "stray .@. in program" } */ +const char *test_invalid3 = "test"@@; /* { dg-error "stray .@. in program" } */ +const char *test_invalid4 = "te" @"st"; /* { dg-error "expected" } */ +id test_invalid5 = @"te" @@"st"; /* { dg-error "repeated .@. before Objective-C string" } */ +id test_invalid6 = @@"te" @"st"; /* { dg-error "stray .@. in program" } */ +id test_invalid7 = @"te" @"s" @@"t"; /* { dg-error "repeated .@. before Objective-C string" } */ +id test_invalid8 = @"te" @@"s" @"t"; /* { dg-error "repeated .@. before Objective-C string" } */ +id test_invalid9 = @"te" @"s" @"t" @; /* { dg-error "stray .@. in program" } */ +id test_invalidA = @"te" @ st; /* { dg-error "stray .@. in program" } */ + /* { dg-error "expected" "" { target *-*-* } 32 } */ diff --git a/gcc/testsuite/objc.dg/strings/strings-2.m b/gcc/testsuite/objc.dg/strings/strings-2.m new file mode 100644 index 000000000..b07ac0f78 --- /dev/null +++ b/gcc/testsuite/objc.dg/strings/strings-2.m @@ -0,0 +1,67 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ + +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-options "-fconstant-string-class=MyTestString" } */ +/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=MyTestString" { target *-*-darwin* } } */ + +#include "../../objc-obj-c++-shared/objc-test-suite-types.h" + +#include <stdlib.h> /* For abort() */ + +@interface MyTestString +{ + void *dummy_class_ptr; + char *string; + unsigned int len; +} ++ initialize; +/* All strings should contain the C string 'test'. Call -check to + test that this is true. */ +- (void) check; +@end + +@implementation MyTestString ++ initialize {return self;} + +- (void) check +{ + if (len != 4 || string[0] != 't' || string[1] != 'e' + || string[2] != 's' || string[3] != 't' || string[4] != '\0') + abort (); +} +@end + +TNS_STRING_REF_T _MyTestStringClassReference; /* Only used by NeXT. */ + +int main (void) +{ + MyTestString *test_valid1 = @"test"; + MyTestString *test_valid2 = @"te" @"st"; + MyTestString *test_valid3 = @"te" @"s" @"t"; + MyTestString *test_valid4 = @ "t" @ "e" @ "s" @ "t"; + MyTestString *test_valid5 = @ "t" "e" "s" "t"; + MyTestString *test_valid6 = @ "t" "e" "s" @ "t"; + + [test_valid1 check]; + [test_valid2 check]; + [test_valid3 check]; + [test_valid4 check]; + [test_valid5 check]; + [test_valid6 check]; + + return 0; +} + +#ifdef __NEXT_RUNTIME__ +/* The MyTestString metaclass will need to be initialized before we can + send messages to strings. */ +#include <string.h> + +void testsuite_mytest_string_init (void) __attribute__((constructor)); +void testsuite_mytest_string_init (void) { + memcpy (&_MyTestStringClassReference, + objc_getClass ("MyTestString"), + sizeof (_MyTestStringClassReference)); +} +#endif
\ No newline at end of file diff --git a/gcc/testsuite/objc.dg/strings/strings.exp b/gcc/testsuite/objc.dg/strings/strings.exp new file mode 100644 index 000000000..823c2871a --- /dev/null +++ b/gcc/testsuite/objc.dg/strings/strings.exp @@ -0,0 +1,46 @@ +# String tests that only need to run at default optimization. + +# Copyright (C) 2010 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Load support procs. + +load_lib objc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS "" +} + +# Initialize `dg'. +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]] + +# Main loop. +dg-runtest $tests "-fgnu-runtime" $DEFAULT_CFLAGS + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { + dg-runtest $tests "-fnext-runtime" $DEFAULT_CFLAGS +} + +# All done. +dg-finish diff --git a/gcc/testsuite/objc.dg/stubify-1.m b/gcc/testsuite/objc.dg/stubify-1.m new file mode 100644 index 000000000..91bf73a14 --- /dev/null +++ b/gcc/testsuite/objc.dg/stubify-1.m @@ -0,0 +1,35 @@ +/* All calls must be properly stubified. Complain about any "call + _objc_msgSend<end-of-line>" without the $stub suffix. */ + +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-require-effective-target ilp32 } */ +/* { dg-options "-Os -mdynamic-no-pic -mmacosx-version-min=10.4" } */ + +typedef struct objc_object { } *id ; +int x = 41 ; +extern id objc_msgSend(id self, char * op, ...); +extern int bogonic (int, int, int) ; +@interface Document {} +- (Document *) window; +- (Document *) class; +- (Document *) close; +@end +@implementation Document +- (Document *) class { } +- (Document *) close { } +- (Document *) window { } +- (void)willEndCloseSheet:(void *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo { + [[self window] close]; + ((void (*)(id, char *, int))objc_msgSend)([self class], (char *)contextInfo, 1); + ((void (*)(id, char *, int))bogonic)([self class], (char *)contextInfo, 1); + bogonic (3, 4, 5); + x++; +} +@end + +/* { dg-final { scan-assembler-not "\(bl|call\)\[ \t\]+_objc_msgSend\n" } } */ +/* { dg-final { scan-assembler "\(bl|call\)\[ \t\]+L_objc_msgSend\\\$stub\n" } } */ +/* { dg-final { scan-assembler-not "\(bl|call\)\[ \t\]+_bogonic\n" } } */ +/* { dg-final { scan-assembler "\(bl|call\)\[ \t\]+L_bogonic\\\$stub\n" } } */ +/* { dg-final { scan-assembler-not "\\\$non_lazy_ptr" } } */ diff --git a/gcc/testsuite/objc.dg/stubify-2.m b/gcc/testsuite/objc.dg/stubify-2.m new file mode 100644 index 000000000..eaf4b964e --- /dev/null +++ b/gcc/testsuite/objc.dg/stubify-2.m @@ -0,0 +1,33 @@ +/* All calls must be properly stubified, m32 only. */ +/* Testcase extracted from TextEdit:Document.m. */ + +/* { dg-do compile { target powerpc*-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-require-effective-target ilp32 } */ +/* { dg-options "-mdynamic-no-pic -fdump-rtl-jump -mmacosx-version-min=10.4" } */ + +typedef struct objc_object { } *id ; +int x = 41 ; +extern id objc_msgSend(id self, char * op, ...); +extern int bogonic (int, int, int) ; +@interface Document {} +- (Document *) window; +- (Document *) class; +- (Document *) close; +@end +@implementation Document +- (Document *) class { } +- (Document *) close { } +- (Document *) window { } +- (void)willEndCloseSheet:(void *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo { + [[self window] close]; + ((void (*)(id, char *, int))objc_msgSend)([self class], (char *)contextInfo, 1); + ((void (*)(id, char *, int))bogonic)([self class], (char *)contextInfo, 1); + bogonic (3, 4, 5); + x++; +} +@end + +/* Any symbol_ref of an un-stubified objc_msgSend is an error; look + for "objc_msgSend" in quotes, without the $stub suffix. */ +/* { dg-final { scan-rtl-dump-not "symbol_ref.*\"objc_msgSend\"" "jump" } } */ diff --git a/gcc/testsuite/objc.dg/super-class-1.m b/gcc/testsuite/objc.dg/super-class-1.m new file mode 100644 index 000000000..9c8ab86d3 --- /dev/null +++ b/gcc/testsuite/objc.dg/super-class-1.m @@ -0,0 +1,5 @@ +/* Test super classes. */ +/* { dg-do compile } */ + +@interface class0 : supclass0 +@end /* { dg-error "annot find interface declaration for .*, superclass" } */ diff --git a/gcc/testsuite/objc.dg/super-class-2.m b/gcc/testsuite/objc.dg/super-class-2.m new file mode 100644 index 000000000..144ea81b5 --- /dev/null +++ b/gcc/testsuite/objc.dg/super-class-2.m @@ -0,0 +1,44 @@ +/* Test calling super from within a category class method. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ + +typedef struct objc_object { struct objc_class *isa; } *id; + +@interface NSObject ++ (int) test_func0; +@end +@interface NSMenuItem: NSObject ++ (int) test_func0; +@end + +@implementation NSObject ++ (int) test_func0 +{} +@end + +@implementation NSMenuItem ++ (int) test_func0 +{ + return [super test_func0]; +} +@end + +@interface NSObject (Test) ++ (int) test_func; +@end + +@implementation NSObject (Test) ++ (int) test_func +{} +@end + +@interface NSMenuItem (Test) ++ (int) test_func; +@end + +@implementation NSMenuItem (Test) ++ (int) test_func +{ + return [super test_func]; /* { dg-bogus "dereferencing pointer to incomplete type" } */ +} +@end diff --git a/gcc/testsuite/objc.dg/super-class-3.m b/gcc/testsuite/objc.dg/super-class-3.m new file mode 100644 index 000000000..fc74871db --- /dev/null +++ b/gcc/testsuite/objc.dg/super-class-3.m @@ -0,0 +1,46 @@ +/* Ensure that the compiler does not emit spurious extern declarations named '_Foo', where 'Foo' + is an ObjC class name. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" + +#include <stdlib.h> +#define CHECK_IF(expr) if(!(expr)) abort() + +@interface _Child: Object ++ (int) flashCache; +@end + +@interface Child: _Child ++ (int) flushCache1; +@end + +@interface Child (Categ) ++ (int) flushCache2; +@end + +int _Object = 23; /* Should not conflict with @interface Object. */ + +@implementation _Child ++ (int) flashCache { return 12 + _Object; } +@end + +@implementation Child ++ (int) flushCache1 { return 7 + [super flashCache]; } +@end + +@implementation Child (Categ) ++ (int) flushCache2 { return 9 + [super flashCache]; } +@end + +int main(void) { + CHECK_IF([_Child flashCache] == 35); + CHECK_IF([Child flushCache1] == 42); + CHECK_IF([Child flushCache2] == 44); + + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/super-class-4.m b/gcc/testsuite/objc.dg/super-class-4.m new file mode 100644 index 000000000..a5ff9088b --- /dev/null +++ b/gcc/testsuite/objc.dg/super-class-4.m @@ -0,0 +1,34 @@ +/* Bail out gracefully if attempting to derive from a class that has only been + forward-declared (via @class). Conversely, @compatibility_alias declarations + should be traversed to find the @interface. */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@class MyWpModule; + +@compatibility_alias MyObject Object; +@compatibility_alias FictitiousModule MyWpModule; + +@protocol MySelTarget +- (id) meth1; +@end + +@protocol Img +- (id) meth2; +@end + +@interface FunnyModule: FictitiousModule <Img> /* { dg-error ".MyWpModule., superclass of .FunnyModule." } */ +- (id) meth2; +@end + +@interface MyProjWpModule : MyWpModule <MySelTarget, Img> /* { dg-error ".MyWpModule., superclass of .MyProjWpModule." } */ { + id i1, i2; +} +- (id) meth1; +- (id) meth2; +@end + +@interface AnotherModule: MyObject <MySelTarget> +- (id) meth1; +@end diff --git a/gcc/testsuite/objc.dg/super-dealloc-1.m b/gcc/testsuite/objc.dg/super-dealloc-1.m new file mode 100644 index 000000000..0ab177bb7 --- /dev/null +++ b/gcc/testsuite/objc.dg/super-dealloc-1.m @@ -0,0 +1,46 @@ +/* Check for warnings about missing [super dealloc] calls. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile } */ + +@interface Foo { + void *isa; +} +- (void) dealloc; +- (void) some_other; +@end + +@interface Bar: Foo { + void *casa; +} +- (void) dealloc; +@end + +@interface Baz: Bar { + void *usa; +} +- (void) dealloc; +@end + +@implementation Foo +- (void) dealloc { + isa = 0; /* Should not warn here. */ +} +- (void) some_other { + isa = (void *)-1; +} +@end + +@implementation Bar +- (void) dealloc { + casa = 0; + [super some_other]; +} /* { dg-warning "method possibly missing a .super dealloc. call" } */ +@end + +@implementation Baz +- (void) dealloc { + usa = 0; + [super dealloc]; /* Should not warn here. */ +} +@end diff --git a/gcc/testsuite/objc.dg/super-dealloc-2.m b/gcc/testsuite/objc.dg/super-dealloc-2.m new file mode 100644 index 000000000..80dcf4950 --- /dev/null +++ b/gcc/testsuite/objc.dg/super-dealloc-2.m @@ -0,0 +1,46 @@ +/* Check for warnings about missing [super dealloc] calls. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile } */ + +@interface Foo { + void *isa; +} +- (void) dealloc; +- (void) some_other; +@end + +@interface Bar: Foo { + void *casa; +} +- (void) dealloc0; +@end + +@interface Baz: Bar { + void *usa; +} +- (void) dealloc; +@end + +@implementation Foo +- (void) dealloc { + isa = 0; /* Should not warn here. */ +} +- (void) some_other { + isa = (void *)-1; +} +@end + +@implementation Bar +- (void) dealloc0 { + casa = 0; + [super some_other]; /* Should not warn here. */ +} +@end + +@implementation Baz +- (void) dealloc { + usa = 0; + [super dealloc0]; +} /* { dg-warning "method possibly missing a .super dealloc. call" } */ +@end diff --git a/gcc/testsuite/objc.dg/symtab-1.m b/gcc/testsuite/objc.dg/symtab-1.m new file mode 100644 index 000000000..936f8d494 --- /dev/null +++ b/gcc/testsuite/objc.dg/symtab-1.m @@ -0,0 +1,27 @@ +/* Check if the objc_symtab descriptor is being laid out correctly. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do compile { target { *-*-darwin* } } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ + +#include <objc/Object.h> + +@interface Base: Object +- (void)setValues; +@end + +@interface Derived: Base +- (void)checkValues; +@end + +@implementation Base +-(void)setValues { } +@end + +@implementation Derived +-(void)checkValues { } +@end + +/* { dg-final { scan-assembler "L_OBJC_Symbols.*:\n\t.long\t0\n\t.long\t0\n\t.word\t2\n\t.word\t0\n\t.long\tL_OBJC_Class_Derived.*\n\t.long\tL_OBJC_Class_Base.*\n" { target { *86*-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler "L_OBJC_Symbols.*:\n\t.long\t0\n\t.long\t0\n\t.short\t2\n\t.short\t0\n\t.long\tL_OBJC_Class_Derived.*\n\t.long\tL_OBJC_Class_Base.*\n" { target { powerpc*-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler-not "L_OBJC_Symbols" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/sync-1.m b/gcc/testsuite/objc.dg/sync-1.m new file mode 100644 index 000000000..fe1f65c78 --- /dev/null +++ b/gcc/testsuite/objc.dg/sync-1.m @@ -0,0 +1,12 @@ +/* Make sure that @synchronized parses. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +void foo(id sem) +{ + @synchronized (sem) { + return; + } +} diff --git a/gcc/testsuite/objc.dg/sync-2.m b/gcc/testsuite/objc.dg/sync-2.m new file mode 100644 index 000000000..c2143a4e9 --- /dev/null +++ b/gcc/testsuite/objc.dg/sync-2.m @@ -0,0 +1,35 @@ +/* Make sure that @synchronized parses and a very basic test runs. */ +/* { dg-options "-fobjc-exceptions -fgnu-runtime" } */ + +#include "../objc-obj-c++-shared/Object1.h" + +int main (void) +{ + Object *a = [Object new]; + Object *b = [Object new]; + Object *c = [Object new]; + + /* This single-threaded test just checks that @synchronized() uses a + recursive mutex, and that the runtime at least doesn't crash + immediately upon finding it. + */ + @synchronized (a) + { + @synchronized (a) + { + @synchronized (b) + { + @synchronized (b) + { + @synchronized (c) + { + @synchronized (c) + { + return 0; + } + } + } + } + } + } +} diff --git a/gcc/testsuite/objc.dg/sync-3.m b/gcc/testsuite/objc.dg/sync-3.m new file mode 100644 index 000000000..5cee890bb --- /dev/null +++ b/gcc/testsuite/objc.dg/sync-3.m @@ -0,0 +1,128 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +/* Test that the compiler is checking the argument of @synchronized(), + and produce errors when invalid types are used. */ + +#include <objc/objc.h> + +@interface MyObject +{ + Class isa; +} +@end + +@implementation MyObject +@end + +@protocol MyProtocol; + +typedef MyObject MyObjectTypedef; +typedef MyObject *MyObjectPtrTypedef; +typedef int intTypedef; + +typedef struct { float x; float y; } point, *point_ptr; + +int test (id object) +{ + int dummy = 0; + + { + int x; + @synchronized (x) /* { dg-error ".@synchronized. argument is not an object" } */ + { dummy++; } + } + + { + intTypedef x; + @synchronized (x) /* { dg-error ".@synchronized. argument is not an object" } */ + { dummy++; } + } + + { + int *x; + @synchronized (x) /* { dg-error ".@synchronized. argument is not an object" } */ + { dummy++; } + } + + { + point x; + @synchronized (x) /* { dg-error ".@synchronized. argument is not an object" } */ + { dummy++; } + } + + { + point_ptr x; + @synchronized (x) /* { dg-error ".@synchronized. argument is not an object" } */ + { dummy++; } + } + + { + id x; + @synchronized (x) /* Ok */ + { dummy++; } + } + + { + id <MyProtocol> x; + @synchronized (x) /* Ok */ + { dummy++; } + } + + { + MyObject *x; + @synchronized (x) /* Ok */ + { dummy++; } + } + + { + MyObject <MyProtocol> *x; + @synchronized (x) /* Ok */ + { dummy++; } + } + + { + static MyObject *x; + @synchronized (x) /* Ok */ + { dummy++; } + } + + { + MyObjectTypedef *x; + @synchronized (x) /* Ok */ + { dummy++; } + } + + { + MyObjectTypedef <MyProtocol> *x; + @synchronized (x) /* Ok */ + { dummy++; } + } + + { + MyObjectPtrTypedef x; + @synchronized (x) /* Ok */ + { dummy++; } + } + + { + Class x; + @synchronized (x) /* Ok */ + { dummy++; } + } + + @synchronized (1) /* { dg-error ".@synchronized. argument is not an object" } */ + { dummy++; } + + @synchronized ("Test") /* { dg-error ".@synchronized. argument is not an object" } */ + { dummy++; } + + @synchronized () /* { dg-error "expected expression" } */ + { dummy++; } + + @synchronized (int) /* { dg-error "expected expression" } */ + { dummy++; } + + return dummy; +} diff --git a/gcc/testsuite/objc.dg/threedotthree-abi-1.m b/gcc/testsuite/objc.dg/threedotthree-abi-1.m new file mode 100644 index 000000000..5eb00014e --- /dev/null +++ b/gcc/testsuite/objc.dg/threedotthree-abi-1.m @@ -0,0 +1,69 @@ +/* This file tests that things are encoded using the gcc-3.3 ABI which is only + used by the NeXT runtime. */ +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-require-effective-target ilp32 } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Protocol1.h" +#include <stdio.h> +#include <string.h> + +extern void abort(); + +@protocol CommonProtocol + +-(oneway void)methodCall_On:(in bycopy id)someValue_On; +-(oneway void)methodCall_nO:(bycopy in id)someValue_nO; + +-(oneway void)methodCall_Oo:(out bycopy id)someValue_Oo; +-(oneway void)methodCall_oO:(bycopy out id)someValue_oO; + +-(oneway void)methodCall_rn:(in const id)someValue_rn; + +-(oneway void)methodCall_oOn:(in bycopy out id)someValue_oOn; + +@end + +@interface ObjCClass <CommonProtocol> +{ + +} + +@end + +@implementation ObjCClass +-(oneway void)methodCall_On:(in bycopy id)someValue_On { } +-(oneway void)methodCall_nO:(bycopy in id)someValue_nO { } + +-(oneway void)methodCall_Oo:(out bycopy id)someValue_Oo { } +-(oneway void)methodCall_oO:(bycopy out id)someValue_oO { } + +-(oneway void)methodCall_rn:(in const id)someValue_rn { } +-(oneway void)methodCall_oOn:(in bycopy out id)someValue_oOn { } +@end + +Protocol *proto = @protocol(CommonProtocol); +struct objc_method_description *meth; + +int main() +{ + meth = [proto descriptionForInstanceMethod: @selector(methodCall_On:)]; + if (strcmp (meth->types, "Vv12@0:4On@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_nO:)]; + if (strcmp (meth->types, "Vv12@0:4nO@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_Oo:)]; + if (strcmp (meth->types, "Vv12@0:4Oo@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_oO:)]; + if (strcmp (meth->types, "Vv12@0:4oO@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_rn:)]; + if (strcmp (meth->types, "Vv12@0:4rn@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_oOn:)]; + if (strcmp (meth->types, "Vv12@0:4oOn@8")) + abort(); + return 0; +} diff --git a/gcc/testsuite/objc.dg/tls/diag-2.m b/gcc/testsuite/objc.dg/tls/diag-2.m new file mode 100644 index 000000000..4f22281eb --- /dev/null +++ b/gcc/testsuite/objc.dg/tls/diag-2.m @@ -0,0 +1,26 @@ +/* Invalid __thread specifiers. */ +/* { dg-require-effective-target tls } */ + +__thread extern int g1; /* { dg-error "'__thread' before 'extern'" } */ +__thread static int g2; /* { dg-error "'__thread' before 'static'" } */ +__thread __thread int g3; /* { dg-error "duplicate '__thread'" } */ +typedef __thread int g4; /* { dg-error " '__thread' used with 'typedef'" } */ + +void foo() +{ + __thread int l1; /* { dg-error "implicitly auto and declared '__thread'" } */ + auto __thread int l2; /* { dg-error "'__thread' used with 'auto'" } */ + __thread extern int l3; /* { dg-error "'__thread' before 'extern'" } */ + register __thread int l4; /* { dg-error "'__thread' used with 'register'" } */ +} + +__thread void f1 (); /* { dg-error "invalid storage class for function 'f1'" } */ +extern __thread void f2 (); /* { dg-error "invalid storage class for function 'f2'" } */ +static __thread void f3 (); /* { dg-error "invalid storage class for function 'f3'" } */ +__thread void f4 () { } /* { dg-error "function definition declared '__thread'" } */ + +void bar(__thread int p1); /* { dg-error "(invalid in parameter)|(specified for parameter)" } */ + +struct A { + __thread int i; /* { dg-error "expected specifier-qualifier-list before '__thread'" } */ +}; diff --git a/gcc/testsuite/objc.dg/tls/diag-3.m b/gcc/testsuite/objc.dg/tls/diag-3.m new file mode 100644 index 000000000..c71f66fb8 --- /dev/null +++ b/gcc/testsuite/objc.dg/tls/diag-3.m @@ -0,0 +1,11 @@ +/* Report invalid extern and __thread combinations. */ +/* { dg-require-effective-target tls } */ + +extern int j; /* { dg-message "previous declaration of 'j' was here" } */ +__thread int j; /* { dg-error "follows non-thread-local" } */ + +extern __thread int i; /* { dg-message "previous declaration of 'i' was here" } */ +int i; /* { dg-error "follows thread-local" } */ + +extern __thread int k; /* This is fine. */ +__thread int k; diff --git a/gcc/testsuite/objc.dg/tls/diag-4.m b/gcc/testsuite/objc.dg/tls/diag-4.m new file mode 100644 index 000000000..38a5b3aba --- /dev/null +++ b/gcc/testsuite/objc.dg/tls/diag-4.m @@ -0,0 +1,10 @@ +/* Invalid __thread specifiers. */ +/* { dg-require-effective-target tls } */ + +__thread typedef int g4; /* { dg-error "'__thread' used with 'typedef'" } */ + +void foo() +{ + __thread auto int l2; /* { dg-error "'__thread' used with 'auto'" } */ + __thread register int l4; /* { dg-error "'__thread' used with 'register'" } */ +} diff --git a/gcc/testsuite/objc.dg/tls/diag-5.m b/gcc/testsuite/objc.dg/tls/diag-5.m new file mode 100644 index 000000000..ac78cb295 --- /dev/null +++ b/gcc/testsuite/objc.dg/tls/diag-5.m @@ -0,0 +1,4 @@ +/* __thread specifiers on empty declarations. */ +/* { dg-require-effective-target tls } */ + +__thread struct foo; /* { dg-warning "useless '__thread' in empty declaration" } */ diff --git a/gcc/testsuite/objc.dg/tls/init-1.m b/gcc/testsuite/objc.dg/tls/init-1.m new file mode 100644 index 000000000..fa4208dce --- /dev/null +++ b/gcc/testsuite/objc.dg/tls/init-1.m @@ -0,0 +1,5 @@ +/* Invalid initializations. */ +/* { dg-require-effective-target tls } */ + +extern __thread int i; +int *p = &i; /* { dg-error "initializer element is not constant" } */ diff --git a/gcc/testsuite/objc.dg/tls/init-2.m b/gcc/testsuite/objc.dg/tls/init-2.m new file mode 100644 index 000000000..882e5f809 --- /dev/null +++ b/gcc/testsuite/objc.dg/tls/init-2.m @@ -0,0 +1,14 @@ +/* Invalid initializations. */ +/* { dg-require-effective-target tls } */ + +extern __thread int i; +__thread int *p = &i; /* { dg-error "initializer element is not constant" } */ + +extern int f(); +__thread int j = f(); /* { dg-error "initializer element is not constant" } */ + +struct S +{ + S(); /* { dg-error "expected specifier-qualifier-list before 'S'" } */ +}; +__thread S s; /* { dg-error "unknown type name" } */ diff --git a/gcc/testsuite/objc.dg/tls/tls.exp b/gcc/testsuite/objc.dg/tls/tls.exp new file mode 100644 index 000000000..5b30a70ff --- /dev/null +++ b/gcc/testsuite/objc.dg/tls/tls.exp @@ -0,0 +1,26 @@ + +# Load support procs. +load_lib objc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS "" +} + +# Initialize `dg'. +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]] + +# Main loop. +dg-runtest $tests "-fgnu-runtime" $DEFAULT_CFLAGS + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { + dg-runtest $tests "-fnext-runtime" $DEFAULT_CFLAGS +} + +# All done. +dg-finish diff --git a/gcc/testsuite/objc.dg/too-many-args.m b/gcc/testsuite/objc.dg/too-many-args.m new file mode 100644 index 000000000..6fee1b31b --- /dev/null +++ b/gcc/testsuite/objc.dg/too-many-args.m @@ -0,0 +1,10 @@ +/* { dg-do compile } */ + +@interface SomeClass ++ method:(int)foo; +@end + +int main(void) { + [SomeClass method:3, 4]; /* { dg-error "too many arguments to method \\'method:\\'" } */ + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/dg-torture.exp b/gcc/testsuite/objc.dg/torture/dg-torture.exp new file mode 100644 index 000000000..4b1869e9c --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/dg-torture.exp @@ -0,0 +1,17 @@ +# This harness is for tests that should be run at all optimisation levels. + +load_lib objc-dg.exp + +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]] + +objc-dg-runtest $tests "-fgnu-runtime" + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { + objc-dg-runtest $tests "-fnext-runtime" +} + +dg-finish diff --git a/gcc/testsuite/objc.dg/torture/forward-1.m b/gcc/testsuite/objc.dg/torture/forward-1.m new file mode 100644 index 000000000..bccf4a112 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/forward-1.m @@ -0,0 +1,87 @@ +/* { dg-do run } */ +/* See if -forward::/-performv:: is able to work. */ +/* { dg-xfail-run-if "PR36610" { ! { { i?86-*-* x86_64-*-* } && ilp32 } } { "-fgnu-runtime" } { "" } } */ +/* { dg-skip-if "Needs OBJC2 Implementation" { *-*-darwin* && { lp64 } } { "-fnext-runtime" } { "" } } */ +/* There is no implementation of forward: in the NeXT m64 libobjc/Object + neither have we implemented this in our extensions - so we have to skip it + for now. */ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef __NEXT_RUNTIME__ +# include <objc/objc-api.h> +#endif +#include <objc/Object.h> + +#define VALUETOUSE 1234567890 + +id forwarder, receiver; + +@interface Forwarder: Object +{ + id receiver; +} + +-initWithReceiver:theReceiver; + +@end + +@interface Receiver:Object +{ + int foo; +} +-display; +-initWithFoo:(int)theFoo; +@end +@implementation Receiver + +-initWithFoo: (int)theFoo +{ + foo = theFoo; + return self; +} + +-display +{ + /* Check to see if we are really the reciever. */ + if (self != receiver) + abort (); + /* And the value of foo is set correctly. */ + if (foo != VALUETOUSE) + abort (); + return self; +} + +@end + +@implementation Forwarder +-initWithReceiver: theReceiver +{ + [super init]; + receiver = theReceiver; + return self; +} +#ifdef __NEXT_RUNTIME__ +- forward: (SEL)theSel: (marg_list)theArgFrame +#else +-(retval_t) forward: (SEL)theSel: (arglist_t)theArgFrame +#endif +{ + /* If we have a reciever try to perform on that object */ + if (receiver) + return [receiver performv: theSel: theArgFrame]; + return [self doesNotRecognize:theSel]; +} +@end +int main() +{ + /* Init the reciever. */ + receiver = [[Receiver alloc] initWithFoo: VALUETOUSE]; + /* Init the fowarder. */ + forwarder = [[Forwarder alloc] initWithReceiver: receiver]; + /* Call display on the forwarder which in turns calls display on + the reciever. */ + [forwarder display]; + exit(0); +} diff --git a/gcc/testsuite/objc.dg/torture/strings/const-cfstring-1.m b/gcc/testsuite/objc.dg/torture/strings/const-cfstring-1.m new file mode 100644 index 000000000..7e9891564 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/const-cfstring-1.m @@ -0,0 +1,62 @@ +/* Test the -fconstant-cfstrings option for constructing + compile-time immutable CFStrings, and their interoperation + with both Cocoa and CoreFoundation. This will only work + on MacOS X 10.1.2 and later. */ +/* Developed by Ziemowit Laski <zlaski@apple.com>. */ + +/* So far, CFString is darwin-only. */ +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-skip-if "NeXT only" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-options "-mconstant-cfstrings -framework Cocoa" } */ +/* Darwin10's linker emits a warning that the constant strings are incompatible with writable ones. + Well, we don't implement writable ones at this juncture. */ +/* { dg-options "-mconstant-cfstrings -framework Cocoa -Wl,-w" { target *-*-darwin[123]* } } */ + +#import <Foundation/NSString.h> +#import <CoreFoundation/CFString.h> +#include <stdlib.h> + +void printOut(NSString *str) { + NSLog(@"The value of str is: %@", str); +} + +CFStringRef s0a = CFSTR("Compile-time string literal"); +CFStringRef s0b = CFSTR("Compile-time string literal"); + +void checkNSRange(NSRange r) { + if (r.location != 6 || r.length != 5) { + printOut(@"Range check failed"); + abort(); + } +} + +void checkCFRange(CFRange r) { + if (r.location != 6 || r.length != 5) { + printOut(@"Range check failed"); + abort(); + } +} + +int main(void) { + const NSString *s1 = @"Compile-time string literal"; + CFStringRef s2 = CFSTR("Compile-time string literal"); + + checkNSRange([@"Hello World" rangeOfString:@"World"]); + checkNSRange([(id)CFSTR("Hello World") rangeOfString:@"World"]); + checkNSRange([@"Hello World" rangeOfString:(id)CFSTR("World")]); + checkNSRange([(id)CFSTR("Hello World") rangeOfString:(id)CFSTR("World")]); + + checkCFRange(CFStringFind((CFStringRef)@"Hello World", (CFStringRef)@"World", 0)); + checkCFRange(CFStringFind(CFSTR("Hello World"), (CFStringRef)@"World", 0)); + checkCFRange(CFStringFind((CFStringRef)@"Hello World", CFSTR("World"), 0)); + checkCFRange(CFStringFind(CFSTR("Hello World"), CFSTR("World"), 0)); + + /* Check for string uniquing. */ + if (s0a != s0b || s0a != s2 || s1 != (id)s2) { + NSLog(@"String uniquing failed"); + abort (); + } + + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/strings/const-cfstring-3.m b/gcc/testsuite/objc.dg/torture/strings/const-cfstring-3.m new file mode 100644 index 000000000..4a6142988 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/const-cfstring-3.m @@ -0,0 +1,27 @@ +/* Test for assigning compile-time constant-string objects to static variables. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ + +/* So far, CFString is darwin-only. */ +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-skip-if "NeXT only" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-mconstant-cfstrings -framework Foundation" } */ + +#include <stdlib.h> + +typedef const struct __CFString * CFStringRef; +static CFStringRef appKey = (CFStringRef) @"com.apple.soundpref"; + +static int CFPreferencesSynchronize (CFStringRef ref) { + return ref == appKey; +} + +static void PrefsSynchronize() +{ + if(!CFPreferencesSynchronize(appKey)) + abort(); +} + +int main(void) { + PrefsSynchronize(); + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/strings/const-cfstring-4.m b/gcc/testsuite/objc.dg/torture/strings/const-cfstring-4.m new file mode 100644 index 000000000..1155db5f8 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/const-cfstring-4.m @@ -0,0 +1,21 @@ +/* Test if constant CFStrings get placed in the correct section and that the + layout of the object is correct for both m32 and m64. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ + +/* So far, CFString is darwin-only. */ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "NeXT only" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-mconstant-cfstrings" } */ + +typedef const struct __CFString * CFStringRef; +static CFStringRef appKey = (CFStringRef) @"com.apple.soundpref"; + +void *foo (void) +{ + void *a = (void *)appKey; + return a; +} + +/* { dg-final { scan-assembler ".section __DATA, __cfstring" } } */ +/* { dg-final { scan-assembler ".long\t___CFConstantStringClassReference\n\t.long\t1992\n\t.long\t.*\n\t.long\t19\n" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".quad\t___CFConstantStringClassReference\n\t.long\t1992\n\t.space 4\n\t.quad\t.*\n\t.quad\t19\n" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-10.m b/gcc/testsuite/objc.dg/torture/strings/const-str-10.m new file mode 100644 index 000000000..f0f28238d --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/const-str-10.m @@ -0,0 +1,35 @@ +/* Test if ObjC constant string layout is checked properly, regardless of how + constant string classes get derived. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile { target { *-*-darwin* } } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-mno-constant-cfstrings" { target *-*-darwin* } } */ + +#include "../../../objc-obj-c++-shared/Object1.h" + +@interface NSString: Object +@end + +@interface NSSimpleCString : NSString { +@protected + char *bytes; + unsigned int numBytes; +} +@end + +@interface NSConstantString : NSSimpleCString +@end + +#ifndef NEXT_OBJC_USE_NEW_INTERFACE +extern struct objc_class _NSConstantStringClassReference; +#else +extern Class _NSConstantStringClassReference; +#endif + +const NSConstantString *appKey = @"MyApp"; + +/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler ".long\t__NSConstantStringClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._NSConstantString\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-11.m b/gcc/testsuite/objc.dg/torture/strings/const-str-11.m new file mode 100644 index 000000000..fa9dbd985 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/const-str-11.m @@ -0,0 +1,35 @@ +/* Test if ObjC constant string layout is checked properly, regardless of how + constant string classes get derived. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-fconstant-string-class=XStr" } */ +/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=XStr" { target *-*-darwin* } } */ + +#include "../../../objc-obj-c++-shared/Object1.h" + +@interface XString: Object { +@protected + char *bytes; +} +@end + +@interface XStr : XString { +@public + unsigned int len; +} +@end + +#ifndef NEXT_OBJC_USE_NEW_INTERFACE +extern struct objc_class _XStrClassReference; +#else +extern Class _XStrClassReference; +#endif + +const XStr *appKey = @"MyApp"; + +/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler ".long\t__XStrClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._XStr\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-3.m b/gcc/testsuite/objc.dg/torture/strings/const-str-3.m new file mode 100644 index 000000000..0eb2d6a01 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/const-str-3.m @@ -0,0 +1,54 @@ +/* Test the -fconstant-string-class=Foo option under the NeXT runtime. */ +/* Developed by Markus Hitter <mah@jump-ing.de>. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-options "-fconstant-string-class=Foo" } */ +/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=Foo" { target *-*-darwin* } } */ + +#include "../../../objc-obj-c++-shared/objc-test-suite-types.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +@interface Foo { + void *dummy_class_ref; + char *cString; + unsigned int len; +} ++ initialize; +- (char *)customString; +@end + +TNS_STRING_REF_T _FooClassReference; /* Only used by NeXT. */ + +@implementation Foo ++ initialize {return self;} + +- (char *)customString { + return cString; +} +@end + +int main () { + Foo *string = @"bla"; + Foo *string2 = @"bla"; + + if(string != string2) + abort(); + printf("Strings are being uniqued properly\n"); + +#ifdef __NEXT_RUNTIME__ + /* This memcpy has to be done before the first message is sent to a + constant string object. Can't be moved to +initialize since _that_ + is already a message. */ + + memcpy(&_FooClassReference, objc_getClass("Foo"), sizeof(_FooClassReference)); +#endif + if (strcmp ([string customString], "bla")) { + abort (); + } + + printf([@"This is a working constant string object\n" customString]); + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-4.m b/gcc/testsuite/objc.dg/torture/strings/const-str-4.m new file mode 100644 index 000000000..446b075da --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/const-str-4.m @@ -0,0 +1,32 @@ +/* Ensure that the preprocessor handles ObjC string constants gracefully. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do run } */ +/* { dg-options "-fconstant-string-class=MyString " } */ +/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=MyString " { target *-*-darwin* } } */ + +extern void abort(void); + +@interface MyString +{ + void *isa; + char *str; + int len; +} +@end + +#define kMyStringMacro1 "My String" +#define kMyStringMacro2 @"My String" + +void *_MyStringClassReference; + +@implementation MyString +@end + +int main(void) { + MyString* aString1 = @kMyStringMacro1; + MyString* aString2 = kMyStringMacro2; + if(aString1 != aString2) { + abort(); + } + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-7.m b/gcc/testsuite/objc.dg/torture/strings/const-str-7.m new file mode 100644 index 000000000..7221e28d4 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/const-str-7.m @@ -0,0 +1,42 @@ +/* Test to make sure that the const objc strings are the same across scopes. */ +/* Developed by Andrew Pinski <pinskia@physics.uc.edu> */ +/* { dg-do run } */ +/* { dg-options "-fconstant-string-class=Foo " } */ +/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=Foo" { target *-*-darwin* } } */ +/* { dg-additional-sources "../../../objc-obj-c++-shared/Object1.m" } */ + +#include "../../../objc-obj-c++-shared/Object1.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +@interface Foo: Object { + char *cString; + unsigned int len; +} +- (char *)customString; +@end + +#ifdef NEXT_OBJC_USE_NEW_INTERFACE +Class _FooClassReference; +#else +struct objc_class _FooClassReference; +#endif + +@implementation Foo : Object +- (char *)customString { + return cString; +} +@end + +int main () { + Foo *string = @"bla"; + { + Foo *string2 = @"bla"; + + if(string != string2) + abort(); + printf("Strings are being uniqued properly\n"); + } + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-8.m b/gcc/testsuite/objc.dg/torture/strings/const-str-8.m new file mode 100644 index 000000000..c5bacaf43 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/const-str-8.m @@ -0,0 +1,43 @@ +/* Test for assigning compile-time constant-string objects to static variables. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do run } */ +/* { dg-options "-fconstant-string-class=Foo" } */ +/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=Foo" { target *-*-darwin* } } */ +/* { dg-additional-sources "../../../objc-obj-c++-shared/Object1.m" } */ + +#include "../../../objc-obj-c++-shared/Object1.h" +#include <stdlib.h> + +@interface Foo: Object { + char *cString; + unsigned int len; +} +@end + +#ifdef NEXT_OBJC_USE_NEW_INTERFACE +Class _FooClassReference; +#else +struct objc_class _FooClassReference; +#endif + +@implementation Foo : Object +- (char *)customString { + return cString; +} +@end + +static const Foo *appKey = @"MyApp"; +static int CFPreferencesSynchronize (const Foo *ref) { + return ref == appKey; +} + +static void PrefsSynchronize(void) +{ + if(!CFPreferencesSynchronize(appKey)) + abort(); +} + +int main () { + PrefsSynchronize(); + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-9.m b/gcc/testsuite/objc.dg/torture/strings/const-str-9.m new file mode 100644 index 000000000..39bd10274 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/const-str-9.m @@ -0,0 +1,27 @@ +/* Test if ObjC constant strings get placed in the correct section. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-mno-constant-cfstrings" { target *-*-darwin* } } */ + +#include "../../../objc-obj-c++-shared/Object1.h" + +@interface NSConstantString: Object { + char *cString; + unsigned int len; +} +@end + +#ifndef NEXT_OBJC_USE_NEW_INTERFACE +extern struct objc_class _NSConstantStringClassReference; +#else +Class _NSConstantStringClassReference; +#endif + +const NSConstantString *appKey = @"MyApp"; + +/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler ".long\t__NSConstantStringClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._NSConstantString\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/torture/strings/string1.m b/gcc/testsuite/objc.dg/torture/strings/string1.m new file mode 100644 index 000000000..455b5f1bf --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/string1.m @@ -0,0 +1,22 @@ +/* Based on a test case contributed by Nicola Pero. */ + +/* { dg-do run } */ +/* { dg-options "-mno-constant-cfstrings -Wno-deprecated-declarations" { target *-*-darwin* } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../../../objc-obj-c++-shared/nsconstantstring-class-impl.m" } */ + +#include <string.h> +#include <stdlib.h> + +#ifndef __NEXT_RUNTIME__ +#include <objc/NXConstStr.h> +#else +#include "../../../objc-obj-c++-shared/nsconstantstring-class.h" +#endif + +int main(int argc, void **args) +{ + if (strcmp ([@"this is a string" cString], "this is a string")) + abort (); + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/strings/string2.m b/gcc/testsuite/objc.dg/torture/strings/string2.m new file mode 100644 index 000000000..030ba602d --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/string2.m @@ -0,0 +1,23 @@ +/* Based on a test case contributed by Nicola Pero. */ + +/* { dg-do run } */ +/* { dg-options "-mno-constant-cfstrings -Wno-deprecated-declarations" { target *-*-darwin* } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../../../objc-obj-c++-shared/nsconstantstring-class-impl.m" } */ + +#include <string.h> +#include <stdlib.h> + +#ifndef __NEXT_RUNTIME__ +#include <objc/NXConstStr.h> +#else +#include "../../../objc-obj-c++-shared/nsconstantstring-class.h" +#endif + +int main(int argc, void **args) +{ + if (strcmp ([@"this " @"is " @"a " @"string" cString], + "this " "is " "a " "string")) + abort (); + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/strings/string3.m b/gcc/testsuite/objc.dg/torture/strings/string3.m new file mode 100644 index 000000000..b08dfb242 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/string3.m @@ -0,0 +1,24 @@ +/* Based on a test case contributed by Nicola Pero. */ + +/* { dg-do run } */ +/* { dg-options "-mno-constant-cfstrings -Wno-deprecated-declarations" { target *-*-darwin* } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../../../objc-obj-c++-shared/nsconstantstring-class-impl.m" } */ + +#include <string.h> +#include <stdlib.h> + +#ifndef __NEXT_RUNTIME__ +#include <objc/NXConstStr.h> +#else +#include "../../../objc-obj-c++-shared/nsconstantstring-class.h" +#endif + +#define STRING "this is a string" + +int main (int argc, void **args) +{ + if (strcmp ([@STRING cString], STRING)) + abort (); + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/strings/string4.m b/gcc/testsuite/objc.dg/torture/strings/string4.m new file mode 100644 index 000000000..425ccc080 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/string4.m @@ -0,0 +1,22 @@ +/* Based on a test case contributed by Nicola Pero. */ + +/* { dg-do run } */ +/* { dg-options "-mno-constant-cfstrings -Wno-deprecated-declarations" { target *-*-darwin* } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../../../objc-obj-c++-shared/nsconstantstring-class-impl.m" } */ + +#include <string.h> +#include <stdlib.h> + +#ifndef __NEXT_RUNTIME__ +#include <objc/NXConstStr.h> +#else +#include "../../../objc-obj-c++-shared/nsconstantstring-class.h" +#endif + +int main(int argc, void **args) +{ + if ([@"this is a string" length] != strlen ("this is a string")) + abort (); + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/strings/strings.exp b/gcc/testsuite/objc.dg/torture/strings/strings.exp new file mode 100644 index 000000000..e30918613 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/strings/strings.exp @@ -0,0 +1,34 @@ +# String tests that should be run at all optimization levels. + +# Copyright (C) 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +load_lib objc-dg.exp +load_lib target-supports-dg.exp + +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]] + +objc-dg-runtest $tests "-fgnu-runtime" + +# Darwin targets also test with the NeXT runtime. +if [istarget "*-*-darwin*" ] { + objc-dg-runtest $tests "-fnext-runtime" +} + +dg-finish diff --git a/gcc/testsuite/objc.dg/torture/tls/diag-1.m b/gcc/testsuite/objc.dg/torture/tls/diag-1.m new file mode 100644 index 000000000..7c3245d9f --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/tls/diag-1.m @@ -0,0 +1,12 @@ +// Valid __thread specifiers. +// { dg-require-effective-target tls } + +__thread int g1; +extern __thread int g2; +static __thread int g3; + +void foo() +{ + extern __thread int l1; + static __thread int l2; +} diff --git a/gcc/testsuite/objc.dg/torture/tls/thr-init-2.m b/gcc/testsuite/objc.dg/torture/tls/thr-init-2.m new file mode 100644 index 000000000..cdbef4d77 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/tls/thr-init-2.m @@ -0,0 +1,43 @@ +// { dg-do run } +// { dg-require-effective-target tls_runtime } +// { dg-add-options tls } + +extern void _exit(int); + +__thread int glb =1 ; + +static __thread int fstat = 2; + +int fa(int a) +{ +static __thread int as = 3; + as += a ; + return as; +} + +int fb(int b) +{ +static __thread int bs = 4; + bs += b ; + glb = bs; + return bs; +} + +int main (int ac, char *av[]) +{ + int a = 1; + + a = fa(fstat); + if ( a != 5 ) + _exit (-(__LINE__)) ; + + a = fa(glb); + if ( a != 6 ) + _exit (-(__LINE__)) ; + + a = fb(a); + if ( a != 10 || glb != 10 ) + _exit (-(__LINE__)) ; + + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/tls/thr-init-3.m b/gcc/testsuite/objc.dg/torture/tls/thr-init-3.m new file mode 100644 index 000000000..b52c87391 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/tls/thr-init-3.m @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-require-effective-target tls_runtime } */ +/* { dg-add-options tls } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../../../objc-obj-c++-shared/Object1.m" } */ + +#include "../../../objc-obj-c++-shared/Object1.h" +extern void _exit(int); + +@interface tsObj: Object { + int ai ; +} + +- (int) fa:(int) n; + +@end + +@implementation tsObj + +- (int) fa:(int) n +{ +static __thread int as = 3; + as += n ; + return as ; +} + +@end + +int main (int ac, char *av[]) +{ + int a ; + tsObj *to = [tsObj new]; + + a = [to fa:5]; + if ( a != 8 ) + _exit (-(__LINE__)) ; + + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/tls/thr-init.m b/gcc/testsuite/objc.dg/torture/tls/thr-init.m new file mode 100644 index 000000000..986b425f7 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/tls/thr-init.m @@ -0,0 +1,26 @@ +/* { dg-do run } */ +/* { dg-require-effective-target tls_runtime } */ +/* { dg-add-options tls } */ + +extern void _exit(int); + +static __thread int fstat ; + +static __thread int fstat = 1; + +static __thread int fstat ; + +int test_code(int b) +{ + fstat += b ; + return fstat; +} + +int main (int ac, char *av[]) +{ + int a = test_code(1); + + if ( a != 2 || fstat != 2 ) _exit (-(__LINE__)) ; + + return 0; +} diff --git a/gcc/testsuite/objc.dg/torture/tls/tls.exp b/gcc/testsuite/objc.dg/torture/tls/tls.exp new file mode 100644 index 000000000..4b1869e9c --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/tls/tls.exp @@ -0,0 +1,17 @@ +# This harness is for tests that should be run at all optimisation levels. + +load_lib objc-dg.exp + +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]] + +objc-dg-runtest $tests "-fgnu-runtime" + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { + objc-dg-runtest $tests "-fnext-runtime" +} + +dg-finish diff --git a/gcc/testsuite/objc.dg/torture/tls/trivial.m b/gcc/testsuite/objc.dg/torture/tls/trivial.m new file mode 100644 index 000000000..e2b8f45b8 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/tls/trivial.m @@ -0,0 +1,3 @@ +// { dg-require-effective-target tls } + +__thread int i; diff --git a/gcc/testsuite/objc.dg/torture/trivial.m b/gcc/testsuite/objc.dg/torture/trivial.m new file mode 100644 index 000000000..a1ac22ed4 --- /dev/null +++ b/gcc/testsuite/objc.dg/torture/trivial.m @@ -0,0 +1,11 @@ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../../objc-obj-c++-shared/Object1.m" } */ + +#import "../../objc-obj-c++-shared/Object1.h" + +int main(void) +{ + [Object class]; + return 0; +} diff --git a/gcc/testsuite/objc.dg/try-catch-1.m b/gcc/testsuite/objc.dg/try-catch-1.m new file mode 100644 index 000000000..5b2a209dd --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-1.m @@ -0,0 +1,41 @@ +/* Test if the compiler accepts @throw / @try..@catch..@finally syntax. */ +/* Developed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include <stdio.h> +#include <setjmp.h> + +@interface Frob: Object +@end + +@implementation Frob: Object +@end + +static int exc_control = 0; + +int proc() { + if(exc_control) { + printf ("Throwing (%d)... ", exc_control); + @throw [Frob new]; + } + return 1; +} + +int foo() +{ + @try { + return proc(); + } + @catch (Frob* ex) { + if(exc_control > 1) { + printf("Rethrowing (%d)... ", exc_control); + @throw; + } + return 0; + } + @finally { + printf("In @finally block (%d)... ", exc_control); + } +} diff --git a/gcc/testsuite/objc.dg/try-catch-10.m b/gcc/testsuite/objc.dg/try-catch-10.m new file mode 100644 index 000000000..49e2c0cef --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-10.m @@ -0,0 +1,40 @@ +/* Ensure that @try/@catch blocks do not mess with types of + local objects (other than their volatile bits). */ + +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@protocol Proto1 +- (int)meth1; +@end + +@protocol Proto2 +- (int)meth2; +@end + +@interface MyClass: Object <Proto2> { + int a; +} +- (int)meth2; +- (Object *)parm1: (id)p1 parm2: (id<Proto1>)p2; +@end + +MyClass *mc1, *mc2; + +@implementation MyClass +- (int)meth2 { + return a; +} +- (Object *)parm1: (id)p1 parm2: (id<Proto1>)p2 { + @try { + mc2 = p2; /* { dg-warning "type .id <Proto1>. does not conform to the .Proto2. protocol" } */ + } + @catch (id exc) { + return exc; + } + mc1 = p1; /* no warning here! */ + return self; +} +@end diff --git a/gcc/testsuite/objc.dg/try-catch-11.m b/gcc/testsuite/objc.dg/try-catch-11.m new file mode 100644 index 000000000..e08f321e8 --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-11.m @@ -0,0 +1,51 @@ +/* Ensure that typeof()-typed variables inside the @try { } block that + "inherit" their EH-volatileness from other variables in the stack frame + do not trigger "discards qualifiers from target pointer type" warnings. */ + +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +typedef volatile int IOSharedLockData; + +@interface TestMyTests +- (void) testSpoon; +@end + +extern void some_func (int *); + +@implementation TestMyTests +- (void) testSpoon { + int i = 5; + + do { + @try { + typeof(i) j = 6; + some_func (&j); + } + @catch (id exc) { + @throw; + } + } while(0); + + do { + @try { + typeof(i) j = 7; + some_func (&j); + } + @catch (id exc) { + @throw; + } + } while(0); + + do { + @try { + typeof(i) j = 8; + some_func (&j); + } + @catch (id exc) { + @throw; + } + } while(0); + +} +@end diff --git a/gcc/testsuite/objc.dg/try-catch-12.m b/gcc/testsuite/objc.dg/try-catch-12.m new file mode 100644 index 000000000..61e27031d --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-12.m @@ -0,0 +1,63 @@ +/* Ensure that variables declared volatile by the user (as opposed to + synthesized by the EH-volatization machinery) _do_ trigger + "discards qualifiers from target pointer type" warnings. */ + +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +@interface TestMyTests +- (void) testSpoon; +@end + +extern void some_func (int *); + +@implementation TestMyTests +- (void) testSpoon { + volatile int i = 5; + int q = 99; + + do { + @try { + typeof(i) j = 6; + typeof(q) k = 66; + some_func (&j); /* { dg-warning "discards .volatile. qualifier from pointer target type" } */ + /* { dg-message "but argument is of type" "" { target *-*-* } 12 } */ + some_func (&k); + } + @catch (id exc) { + @throw; + } + } while(0); + + do { + @try { + typeof(i) j = 7; + typeof(q) k = 77; + some_func (&k); + some_func (&j); /* { dg-warning "discards .volatile. qualifier from pointer target type" } */ + /* The following is disabled as it is already checked above and the testsuites seems + to count multiple different identical errors on the same line only once */ + /* dg-message "but argument is of type" "" { target *-*-* } 12 */ + } + @catch (id exc) { + @throw; + } + } while(0); + + do { + @try { + typeof(q) k = 88; + typeof(i) j = 8; + some_func (&j); /* { dg-warning "discards .volatile. qualifier from pointer target type" } */ + /* The following is disabled as it is already checked above and the testsuites seems + to count multiple different identical errors on the same line only once */ + /* dg-message "but argument is of type" "" { target *-*-* } 12 */ + some_func (&k); + } + @catch (id exc) { + @throw; + } + } while(0); + +} +@end diff --git a/gcc/testsuite/objc.dg/try-catch-3.m b/gcc/testsuite/objc.dg/try-catch-3.m new file mode 100644 index 000000000..2094d29ce --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-3.m @@ -0,0 +1,19 @@ +/* Test if caught exception objects are accessible inside the + @catch block. (Yes, I managed to break this.) */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile } */ +/* { dg-options "-fobjc-exceptions" } */ + +#include "../objc-obj-c++-shared/Object1.h" + +const char *foo(void) +{ + @try { + return "foo"; + } + @catch (Object* theException) { + return [theException name]; + } +} + diff --git a/gcc/testsuite/objc.dg/try-catch-4.m b/gcc/testsuite/objc.dg/try-catch-4.m new file mode 100644 index 000000000..dedcc4ec4 --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-4.m @@ -0,0 +1,26 @@ +/* Check that the compiler does not incorrectly complain about + exceptions being caught by previous @catch blocks. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile } */ +/* { dg-options "-Wall -fobjc-exceptions" } */ + +@interface Exception +@end + +@interface FooException : Exception +@end + +extern void foo(); + +void test() +{ + @try { + foo(); + } + @catch (FooException* fe) { + } + @catch (Exception* e) { + } +} + diff --git a/gcc/testsuite/objc.dg/try-catch-5.m b/gcc/testsuite/objc.dg/try-catch-5.m new file mode 100644 index 000000000..f943e9c7e --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-5.m @@ -0,0 +1,27 @@ +/* Check that the compiler does correctly complain about + exceptions being caught by previous @catch blocks. */ +/* Force the use of NeXT runtime to see that we don't ICE after + generating the warning message. */ + +/* { dg-do compile } */ +/* { dg-options "-Wall -fobjc-exceptions" } */ + +@interface Exception +@end + +@interface FooException : Exception +@end + +extern void foo(); + +void test() +{ + @try { + foo(); + } + @catch (Exception* e) { /* { dg-warning "earlier handler" } */ + } + @catch (FooException* fe) { /* { dg-warning "will be caught" } */ + } +} + diff --git a/gcc/testsuite/objc.dg/try-catch-6.m b/gcc/testsuite/objc.dg/try-catch-6.m new file mode 100644 index 000000000..548c320b4 --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-6.m @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-fobjc-exceptions" } */ + +#include "../objc-obj-c++-shared/Object1.h" + +int main (int argc, const char * argv[]) { + Object * pool = [Object new]; + int a; + + if ( 1 ) { + + @try { + a = 1; + } + @catch (Object *e) { + a = 2; + } + @finally { + a = 3; + } + } + + [pool free]; + return 0; +} diff --git a/gcc/testsuite/objc.dg/try-catch-7.m b/gcc/testsuite/objc.dg/try-catch-7.m new file mode 100644 index 000000000..b66662370 --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-7.m @@ -0,0 +1,27 @@ +/* Test for graceful compilation of @synchronized statements. */ + +/* { dg-do compile } */ +/* { dg-options "-fobjc-exceptions" } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@interface Derived: Object +- (id) meth; +@end + +@implementation Derived +- (id) meth { + return self; +} + +static Derived* rewriteDict(void) { + static Derived *sDict = 0; + if (sDict == 0) { + @synchronized ([Derived class]) { + if (sDict == 0) + sDict = [Derived new]; + } + } + return sDict; +} +@end diff --git a/gcc/testsuite/objc.dg/try-catch-9.m b/gcc/testsuite/objc.dg/try-catch-9.m new file mode 100644 index 000000000..454e841b3 --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-9.m @@ -0,0 +1,24 @@ +/* Check that taking the address of a local variable marked 'volatile' + by the compiler does not generate untoward errors. */ +/* Developed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +void foo (int *arg1, int *arg2) +{ + *arg1 = *arg2; +} + +void bar (int arg) { + int rcvr; + + @try { + rcvr = arg; + } + @finally { + int *rcvr0 = &rcvr; + foo (rcvr0, &arg); + } +} + diff --git a/gcc/testsuite/objc.dg/two-types-1.m b/gcc/testsuite/objc.dg/two-types-1.m new file mode 100644 index 000000000..da902a3e3 --- /dev/null +++ b/gcc/testsuite/objc.dg/two-types-1.m @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */ + +@interface foo +struct f {} +struct g { int a; }; /* { dg-error "expected ';', identifier or " "" } */ + +- (struct f *) a; +- (struct g *) b; +@end + +int f(struct g *x) +{ + return x->a; /* { dg-bogus " has no member " "" } */ +} diff --git a/gcc/testsuite/objc.dg/type-size-1.m b/gcc/testsuite/objc.dg/type-size-1.m new file mode 100644 index 000000000..f2fdae5c3 --- /dev/null +++ b/gcc/testsuite/objc.dg/type-size-1.m @@ -0,0 +1,17 @@ +/* Reject ivars with an unknown size. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +struct unknownStruct; + +@interface ArrayTest +{ + short unknownSize[unknownValue]; /* { dg-error ".unknownValue. (undeclared|was not declared)" } */ + /* { dg-error "instance variable .unknownSize. has unknown size" "" { target *-*-* } 9 } */ + struct unknownStruct unknownObj; /* { dg-error "field .unknownObj. has incomplete type" } */ + /* { dg-error "instance variable .unknownObj. has unknown size" "" { target *-*-* } 11 } */ + long knownSize[3]; /* ok */ + char zeroSize[2 - 2]; /* ok (apparently) */ + int missingSize[]; /* { dg-error "instance variable .missingSize. has unknown size" } */ +} +@end diff --git a/gcc/testsuite/objc.dg/type-size-2.m b/gcc/testsuite/objc.dg/type-size-2.m new file mode 100644 index 000000000..656d85a57 --- /dev/null +++ b/gcc/testsuite/objc.dg/type-size-2.m @@ -0,0 +1,75 @@ +/* Make sure that array arguments to methods are given the size of pointers. */ +/* As in the case of ivars, arrays without size (e.g., 'int []') are + encoded as pointers. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m" } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include "../objc-obj-c++-shared/next-mapping.h" +#include <stdio.h> +#include <stdlib.h> +#ifdef __NEXT_RUNTIME__ +#include <objc/objc-runtime.h> +#define METHOD Method +#else +#include <objc/objc-api.h> +#define METHOD Method_t +#define method_get_types(M) (M)->method_types +#endif + +extern int sscanf(const char *str, const char *format, ...); +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +enum Enum { one, two, three, four }; + +@interface ArrayTest +- (const char *)str:(signed char [])arg1 with:(unsigned char *)arg2 and:(enum Enum[4])en; +- (int)meth1:(int [])arg1 with:(int [0])arg2 with:(int [2])arg3; +@end + +@implementation ArrayTest +- (int)meth1:(int [])arg1 with:(int [0])arg2 with:(int [2])arg3 { return 0; } +- (const char *)str:(signed char [])arg1 with:(unsigned char *)arg2 and:(enum Enum[4])en { return "str"; } +@end + +Class cls; +METHOD meth ; + +unsigned totsize, offs0, offs1, offs2, offs3, offs4, offs5, offs6, offs7; + +static void scan_initial(const char *pattern) { + totsize = offs0 = offs1 = offs2 = offs3 = offs4 = offs5 = offs6 = offs7 = (unsigned)-1; + sscanf(method_get_types(meth), pattern, &totsize, &offs0, &offs1, &offs2, &offs3, + &offs4, &offs5, &offs6, &offs7); + CHECK_IF(!offs0 && offs1 == sizeof(id) && offs2 == offs1 + sizeof(SEL) && totsize >= offs2); +} + +int main(void) { + cls = objc_get_class("ArrayTest"); + + meth = class_get_instance_method(cls, @selector(str:with:and:)); + + /* Here we have the complication that 'enum Enum' could be encoded + as 'i' on __NEXT_RUNTIME_, and (most likely) as 'I' on the GNU + runtime. So we get the @encode(enum Enum), then put it into the + string in place of the traditional 'i'. + */ + /* scan_initial("r*%u@%u:%u*%u*%u[4i]%u"); */ + { + char pattern[1024]; + + sprintf (pattern, "r*%%u@%%u:%%u*%%u*%%u[4%s]%%u", @encode(enum Enum)); + scan_initial(pattern); + } + + CHECK_IF(offs3 == offs2 + sizeof(signed char *) && offs4 == offs3 + sizeof(unsigned char *)); + CHECK_IF(totsize == offs4 + sizeof(enum Enum *)); + meth = class_get_instance_method(cls, @selector(meth1:with:with:)); + scan_initial("i%u@%u:%u^i%u[0i]%u[2i]%u"); + CHECK_IF(offs3 == offs2 + sizeof(int *) && offs4 == offs3 + sizeof(int *)); + CHECK_IF(totsize == offs4 + sizeof(int *)); + return 0; +} diff --git a/gcc/testsuite/objc.dg/type-size-3.m b/gcc/testsuite/objc.dg/type-size-3.m new file mode 100644 index 000000000..bc66b0be6 --- /dev/null +++ b/gcc/testsuite/objc.dg/type-size-3.m @@ -0,0 +1,18 @@ +/* Reject ivars that use flexible array members. */ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com> */ +/* { dg-do compile } */ + +typedef struct +{ + unsigned long int a; + double b[]; +} test_type; + +@interface Test +{ + test_type c; /* { dg-error "instance variable .c. uses flexible array member" } */ +} +@end + +@implementation Test +@end diff --git a/gcc/testsuite/objc.dg/type-size-4.m b/gcc/testsuite/objc.dg/type-size-4.m new file mode 100644 index 000000000..7e26da34a --- /dev/null +++ b/gcc/testsuite/objc.dg/type-size-4.m @@ -0,0 +1,23 @@ +/* Allow ivars that are pointers to structs with an unknown size. */ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com> */ +/* PR objc/47832 */ +/* { dg-do compile } */ + +typedef struct +{ + unsigned long int a; + double b[]; +} test_type; + +@interface Test +{ + /* These are all fine. */ + double *a; + struct { int x; double y[]; } *b; + test_type *c; + union union_type { int x; test_type y; } *d; +} +@end + +@implementation Test +@end diff --git a/gcc/testsuite/objc.dg/type-size-5.m b/gcc/testsuite/objc.dg/type-size-5.m new file mode 100644 index 000000000..d89af32b4 --- /dev/null +++ b/gcc/testsuite/objc.dg/type-size-5.m @@ -0,0 +1,22 @@ +/* Reject ivars that use flexible array members. */ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com> */ +/* { dg-do compile } */ + +typedef struct +{ + unsigned long int a; + double b[]; +} test_type; + +@interface Test +{ + double a[]; /* { dg-error "instance variable .a. has unknown size" } */ + struct { int x; double y[]; } b; /* { dg-error "instance variable .b. uses flexible array member" } */ + test_type c; /* { dg-error "instance variable .c. uses flexible array member" } */ + test_type d[4]; /* { dg-error "instance variable .d. uses flexible array member" } */ + union union_type { int x; test_type y; } e; /* { dg-error "instance variable .e. uses flexible array member" } */ +} +@end + +@implementation Test +@end diff --git a/gcc/testsuite/objc.dg/type-stream-1.m b/gcc/testsuite/objc.dg/type-stream-1.m new file mode 100644 index 000000000..9f2d509fb --- /dev/null +++ b/gcc/testsuite/objc.dg/type-stream-1.m @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +/* Test warning for deprecated typedstream functions. These functions + will be removed in the release after 4.6.0, at which point this + testcase can be removed too. + */ + +#include <objc/typedstream.h> + +void dummy (void) +{ + TypedStream* t = objc_open_typed_stream_for_file ("dummy", 0); /* { dg-warning "deprecated" } */ + + objc_write_object (t, nil); /* { dg-warning "deprecated" } */ + objc_read_object (t, NULL); /* { dg-warning "deprecated" } */ +} diff --git a/gcc/testsuite/objc.dg/typedef-alias-1.m b/gcc/testsuite/objc.dg/typedef-alias-1.m new file mode 100644 index 000000000..79db8765e --- /dev/null +++ b/gcc/testsuite/objc.dg/typedef-alias-1.m @@ -0,0 +1,16 @@ +/* Typedefs of ObjC types should work without any bogus warnings. */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +typedef Object MyObject; + +int main (int argc, const char * argv[]) +{ + Object* a = nil; + MyObject* b = a; + Object* c = b; + + return 0; +} + diff --git a/gcc/testsuite/objc.dg/undeclared-selector.m b/gcc/testsuite/objc.dg/undeclared-selector.m new file mode 100644 index 000000000..1cfc6c834 --- /dev/null +++ b/gcc/testsuite/objc.dg/undeclared-selector.m @@ -0,0 +1,48 @@ +/* Test for -Wundeclared-selector. */ +/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */ +/* { dg-do compile } */ +/* { dg-options "-Wundeclared-selector" } */ + +#include <objc/objc.h> + +@interface MyClass + ++ (void) methodA; +- (void) methodB; ++ (void) methodD; +- (void) methodF; + +@end + +@implementation MyClass + ++ (void) methodA {} +- (void) methodB {} ++ (void) methodD +{ + SEL d = @selector(methodD); /* Ok */ + SEL e = @selector(methodE); /* { dg-warning "undeclared selector" } */ +} + +- (void) methodE +{ + SEL e = @selector(methodE); /* Ok */ +} + +- (void) methodF +{ + SEL e = @selector(methodE); /* Ok */ +} + +@end + +int main (void) +{ + SEL a = @selector(methodA); /* Ok */ + SEL b = @selector(methodB); /* Ok */ + SEL c = @selector(methodC); /* { dg-warning "undeclared selector" } */ + SEL d = @selector(methodD); /* Ok */ + SEL e = @selector(methodE); /* Ok */ + return 0; + +} diff --git a/gcc/testsuite/objc.dg/va-meth-1.m b/gcc/testsuite/objc.dg/va-meth-1.m new file mode 100644 index 000000000..15bbe97c9 --- /dev/null +++ b/gcc/testsuite/objc.dg/va-meth-1.m @@ -0,0 +1,73 @@ +/* Based on objc/execute/va_method.m, by Nicola Pero */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" + +#include <stdarg.h> +#include <stdlib.h> + +/* Test methods with "C-style" trailing arguments, with or without ellipsis. */ + +@interface MathClass: Object +/* sum positive numbers; -1 ends the list */ ++ (int) sum: (int)firstNumber, int secondNumber, ...; ++ (int) prod: (int) firstNumber, int secondNumber, int thirdNumber; ++ (int) minimum: (int) firstNumber, ...; +@end + +@implementation MathClass ++ (int) sum: (int)firstNumber, int secondNumber, ... +{ + va_list ap; + int sum = 0, number = 0; + + va_start (ap, secondNumber); + number = firstNumber + secondNumber; + + while (number >= 0) + { + sum += number; + number = va_arg (ap, int); + } + + va_end (ap); + + return sum; +} ++ (int) prod: (int) firstNumber, int secondNumber, int thirdNumber { + return firstNumber * secondNumber * thirdNumber; +} ++ (int) minimum: (int)firstNumber, ... +{ + va_list ap; + int minimum = 999, number = 0; + + va_start (ap, firstNumber); + number = firstNumber; + + while (number >= 0) + { + minimum = (minimum < number ? minimum: number); + number = va_arg (ap, int); + } + + va_end (ap); + + return minimum; +} +@end + +int main (void) +{ + if ([MathClass sum: 1, 2, 3, 4, 5, -1] != 15) + abort (); + if ([MathClass prod: 4, 5, 6] != 120) + abort (); + if ([MathClass minimum: 17, 9, 133, 84, 35, -1] != 9) + abort (); + + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/volatile-1.m b/gcc/testsuite/objc.dg/volatile-1.m new file mode 100644 index 000000000..8b5381a98 --- /dev/null +++ b/gcc/testsuite/objc.dg/volatile-1.m @@ -0,0 +1,18 @@ +/* Test for proper handling of volatile parameters in ObjC methods. */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ + +@interface Test +-(void) test2: (volatile int) a; +@end + +@implementation Test +-(void) test2: (volatile int) a +{ + /* The following assignment should NOT be optimized away. */ + a = 1; +} +@end + +/* { dg-final { scan-assembler "li r\[0-9\]+,1" { target powerpc*-*-darwin* } } } */ diff --git a/gcc/testsuite/objc.dg/weak-1.m b/gcc/testsuite/objc.dg/weak-1.m new file mode 100644 index 000000000..f39fbc4bb --- /dev/null +++ b/gcc/testsuite/objc.dg/weak-1.m @@ -0,0 +1,13 @@ +/* Test for #pragma weak where the weak alias symbol isn't declared, + although the symbol it is an alias for is defined in the + translation unit. Bug 7544. */ +/* Origin: Joseph Myers <joseph@codesourcery.com> */ +/* { dg-do compile } */ +/* { dg-require-weak "" } */ +/* { dg-require-alias "" } */ +/* { dg-options "-fno-common" } */ + +/* { dg-final { scan-assembler "weak\[^ \t\]*\[ \t\]_?bar1" } } */ + +#pragma weak bar1 = foo1 +void foo1 (void) {} diff --git a/gcc/testsuite/objc.dg/zero-link-1.m b/gcc/testsuite/objc.dg/zero-link-1.m new file mode 100644 index 000000000..c04003111 --- /dev/null +++ b/gcc/testsuite/objc.dg/zero-link-1.m @@ -0,0 +1,31 @@ +/* Check if the '-fzero-link' flag correctly emits an objc_getClass() call. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-fzero-link" } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include <objc/objc.h> + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort(); + +@interface Base: Object ++ (int) getValue; +@end + +@implementation Base ++ (int) getValue { return 1593; } +@end + +int main(void) { + int val = [Base getValue]; + CHECK_IF(val == 1593); + return 0; +} + +/* { dg-final { scan-assembler-not "_OBJC_ClassRefs_0" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler-not "_OBJC_ClassRef_Base" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler "objc_getClass" } } */ + diff --git a/gcc/testsuite/objc.dg/zero-link-2.m b/gcc/testsuite/objc.dg/zero-link-2.m new file mode 100644 index 000000000..ff82e5ed6 --- /dev/null +++ b/gcc/testsuite/objc.dg/zero-link-2.m @@ -0,0 +1,29 @@ +/* Check if the '-fno-zero-link' flag correctly _omits_ an objc_getClass() call. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-fno-zero-link" } */ + +#include <objc/Object.h> + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort(); + +@interface Base: Object ++ (int) getValue; +@end + +@implementation Base ++ (int) getValue { return 1593; } +@end + +int main(void) { + int val = [Base getValue]; + CHECK_IF(val == 1593); + return 0; +} + +/* { dg-final { scan-assembler "_OBJC_ClassRefs_0" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler "_OBJC_ClassRef_Base" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler-not "objc_getClass" } } */ diff --git a/gcc/testsuite/objc.dg/zero-link-3.m b/gcc/testsuite/objc.dg/zero-link-3.m new file mode 100644 index 000000000..2b95b952b --- /dev/null +++ b/gcc/testsuite/objc.dg/zero-link-3.m @@ -0,0 +1,28 @@ +/* Check that the '-fzero-link' flag doesn't prevent messaging from working. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-options "-fzero-link" } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" +//#import <objc/objc.h> + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort(); + +@interface Base: Object ++ (int) getValue; +@end + +@implementation Base ++ (int) getValue { return 1593; } +@end + +int main(void) { + int val = [Base getValue]; + CHECK_IF(val == 1593); + return 0; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" |