diff options
Diffstat (limited to 'gcc/testsuite/obj-c++.dg')
365 files changed, 16911 insertions, 0 deletions
diff --git a/gcc/testsuite/obj-c++.dg/at-class-1.mm b/gcc/testsuite/obj-c++.dg/at-class-1.mm new file mode 100644 index 000000000..63721aa99 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/at-class-1.mm @@ -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/obj-c++.dg/attributes/attributes.exp b/gcc/testsuite/obj-c++.dg/attributes/attributes.exp new file mode 100644 index 000000000..1d4cae4ef --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/attributes.exp @@ -0,0 +1,43 @@ +# 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 obj-c++-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_OBJCXXFLAGS +if ![info exists DEFAULT_OBJCXXFLAGS] then { + set DEFAULT_OBJCXXFLAGS " -ansi -pedantic-errors -Wno-long-long" +} + +# Initialize `dg'. +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]] + +# Main loop. +dg-runtest $tests "-fgnu-runtime" $DEFAULT_OBJCXXFLAGS + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { + dg-runtest $tests "-fnext-runtime" $DEFAULT_OBJCXXFLAGS +} + +# All done. +dg-finish diff --git a/gcc/testsuite/obj-c++.dg/attributes/categ-attribute-1.mm b/gcc/testsuite/obj-c++.dg/attributes/categ-attribute-1.mm new file mode 100644 index 000000000..6c48e0ad1 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/categ-attribute-1.mm @@ -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) /* { dg-warning "category attributes are not available in this version" } */ +- (int) depmth; +@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/obj-c++.dg/attributes/categ-attribute-2.mm b/gcc/testsuite/obj-c++.dg/attributes/categ-attribute-2.mm new file mode 100644 index 000000000..d2fb78913 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/categ-attribute-2.mm @@ -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) /* { dg-warning "category attributes are not available in this version" } */ +- (int) depmth; +@end + +__attribute__ ((deprecated)) +@implementation obj (dep_categ) /* { dg-warning "prefix attributes are ignored before" } */ +- (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/obj-c++.dg/attributes/class-attribute-1.mm b/gcc/testsuite/obj-c++.dg/attributes/class-attribute-1.mm new file mode 100644 index 000000000..f078339b8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/class-attribute-1.mm @@ -0,0 +1,61 @@ +/* { dg-do compile } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ + +/* Test deprecate attribute with an @interface declaration. */ + +#include <objc/objc.h> +#include <objc/runtime.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) /* { dg-warning "is deprecated" } */ +@end + +@interface Subclass : DeprecatedClass /* { dg-warning "is deprecated" } */ +@end + +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/obj-c++.dg/attributes/class-attribute-2.mm b/gcc/testsuite/obj-c++.dg/attributes/class-attribute-2.mm new file mode 100644 index 000000000..35015c037 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/class-attribute-2.mm @@ -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" } */ ++ (id) new { return nil; } +@end + +void function (void) +{ + DeprecatedClass *object = [DeprecatedClass new]; /* { dg-warning "is deprecated" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/attributes/class-attribute-3.mm b/gcc/testsuite/obj-c++.dg/attributes/class-attribute-3.mm new file mode 100644 index 000000000..f96500de4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/class-attribute-3.mm @@ -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/obj-c++.dg/attributes/invalid-attribute-1.mm b/gcc/testsuite/obj-c++.dg/attributes/invalid-attribute-1.mm new file mode 100644 index 000000000..96ee178d7 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/invalid-attribute-1.mm @@ -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 "attributes may not be specified before the ..class. Objective-C.. keyword" } */ diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-attribute-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-attribute-1.mm new file mode 100644 index 000000000..747deab0d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-attribute-1.mm @@ -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 "method attributes must be specified at the end " } */ +- (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/obj-c++.dg/attributes/method-attribute-2.mm b/gcc/testsuite/obj-c++.dg/attributes/method-attribute-2.mm new file mode 100644 index 000000000..4a56b3aa8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-attribute-2.mm @@ -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/obj-c++.dg/attributes/method-attribute-3.mm b/gcc/testsuite/obj-c++.dg/attributes/method-attribute-3.mm new file mode 100644 index 000000000..bab40d342 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-attribute-3.mm @@ -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/obj-c++.dg/attributes/method-deprecated-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-1.mm new file mode 100644 index 000000000..8343856a5 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-1.mm @@ -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/obj-c++.dg/attributes/method-deprecated-2.mm b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-2.mm new file mode 100644 index 000000000..1e5d87f3e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-2.mm @@ -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/obj-c++.dg/attributes/method-deprecated-3.mm b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-3.mm new file mode 100644 index 000000000..5c715a20b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-3.mm @@ -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/obj-c++.dg/attributes/method-format-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-format-1.mm new file mode 100644 index 000000000..11ce8eebb --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-format-1.mm @@ -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/obj-c++.dg/attributes/method-noreturn-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-noreturn-1.mm new file mode 100644 index 000000000..717d6e65e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-noreturn-1.mm @@ -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/obj-c++.dg/attributes/method-sentinel-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-sentinel-1.mm new file mode 100644 index 000000000..2b8e6fd25 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-sentinel-1.mm @@ -0,0 +1,36 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +#include <objc/objc.h> +#include <stdlib.h> +/* Ensure a compatible definition of nil. */ +#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/obj-c++.dg/attributes/parameter-attribute-1.mm b/gcc/testsuite/obj-c++.dg/attributes/parameter-attribute-1.mm new file mode 100644 index 000000000..a4ba25943 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/parameter-attribute-1.mm @@ -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/obj-c++.dg/attributes/parameter-attribute-2.mm b/gcc/testsuite/obj-c++.dg/attributes/parameter-attribute-2.mm new file mode 100644 index 000000000..3908faf99 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/parameter-attribute-2.mm @@ -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/obj-c++.dg/attributes/proto-attribute-1.mm b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-1.mm new file mode 100644 index 000000000..a852a7a6c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-1.mm @@ -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/obj-c++.dg/attributes/proto-attribute-2.mm b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-2.mm new file mode 100644 index 000000000..aba58ff33 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-2.mm @@ -0,0 +1,33 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ + +/* Test deprecate attribute with a forward declarations of + @protocol. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.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/obj-c++.dg/attributes/proto-attribute-3.mm b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-3.mm new file mode 100644 index 000000000..fc5251eee --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-3.mm @@ -0,0 +1,62 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ +/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ + + +/* Test deprecate attribute with normal @protocol declarations. */ + + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.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/obj-c++.dg/attributes/proto-attribute-4.mm b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-4.mm new file mode 100644 index 000000000..d2e5f28a1 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-4.mm @@ -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 /* { dg-warning "ignored" } */ +- (id) new; +@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/obj-c++.dg/attributes/unused-parameter-1.mm b/gcc/testsuite/obj-c++.dg/attributes/unused-parameter-1.mm new file mode 100644 index 000000000..8fbb11e20 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/unused-parameter-1.mm @@ -0,0 +1,50 @@ +/* { dg-do compile } */ + +#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; +- (id) method6: (id) argument1 + andArgument: (id) argument2; +@end + +@implementation MyRootClass +- (id) method1: (id) argument1 +{ + return nil; +} +- (id) method2: (id) __attribute__((unused)) argument1 +{ + return nil; +} +- (id) method3: (id) __attribute__((unused)) argument1 + andArgument: (id) 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 +{ + return nil; +} +- (id) method6: (id) argument1 + andArgument: (id) argument2 +{ + return nil; +} +@end diff --git a/gcc/testsuite/obj-c++.dg/bad-forward-decl.mm b/gcc/testsuite/obj-c++.dg/bad-forward-decl.mm new file mode 100644 index 000000000..e16db7e52 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/bad-forward-decl.mm @@ -0,0 +1,3 @@ +class TestCPP { }; /* { dg-error "previous declaration of" } */ + +@class TestCPP; /* { dg-error "redeclared as different kind of symbol" } */ diff --git a/gcc/testsuite/obj-c++.dg/bad-receiver-type.mm b/gcc/testsuite/obj-c++.dg/bad-receiver-type.mm new file mode 100644 index 000000000..1d6699f99 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/bad-receiver-type.mm @@ -0,0 +1,15 @@ +// { dg-do compile } +// { dg-options "" } + +@interface A + +- (void)test; + +@end + +extern int foo(); + +void baz() +{ + [foo test]; /* { dg-warning "invalid receiver type" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/basic.mm b/gcc/testsuite/obj-c++.dg/basic.mm new file mode 100644 index 000000000..bd593c13b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/basic.mm @@ -0,0 +1,41 @@ +// A basic sanity check for Objective-C++. +// { dg-do run } +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +//#include "../objc-obj-c++-shared/Object1.h" +#include <iostream> + +#include <objc/Object.h> + +#ifdef __OBJC2__ +@interface Object (ADDITIONS) ++ initialize; +- init; ++ alloc; ++ new; +@end +@implementation Object (ADDITIONS) ++ initialize { return self; } +- init { return self; } ++ alloc { return class_createInstance (self, 0); } ++ new { return [[self alloc] init]; } +@end +#endif + +@interface Greeter : Object +- (void) greet: (const char *)msg; +@end + +@implementation Greeter +- (void) greet: (const char *)msg +{ std::cout << msg << __VERSION__ << std::endl;} +@end + +int +main () +{ + std::cout << "Hello from C++" << __VERSION__ << std::endl; + Greeter *obj = [Greeter new]; + [obj greet: "Hello from Objective-C++"]; +} +//#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/bitfield-1.mm b/gcc/testsuite/obj-c++.dg/bitfield-1.mm new file mode 100644 index 000000000..7b8e861ca --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/bitfield-1.mm @@ -0,0 +1,124 @@ +/* Check if 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-do run } */ +/* { dg-options "-Wpadded -Wabi" } */ + +/* Leave blank lines here to keep warnings on the same lines. */ + +#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 { /* { dg-warning "padding struct size to alignment boundary" } */ + Class isa; + unsigned a: 2; + int b: 3; + enum Enum c: 4; + unsigned d: 5; +}; + +@interface Derived: Base { +@public + signed e: 5; + unsigned f: 4; + enum Enum g: 3; +} +@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; +}; + +@interface Leaf: Derived { +@public + signed h: 2; +} +@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; +}; + +/* 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; +typedef struct { @defs(Leaf); } Leaf_t; + +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; +} + +/* { dg-prune-output "In file included from" } Ignore this message. */ +/* { dg-bogus "padding struct to align" "PR23610" { target *-*-* } 0 } */ +/* { dg-bogus "padding struct size" "PR23610" { xfail lp64 } 42 } */ +/* { dg-bogus "padding struct size" "PR23610" { xfail lp64 } 45 } */ +/* { dg-bogus "padding struct size" "PR23610" { xfail lp64 } 59 } */ +/* { dg-bogus "padding struct size" "PR23610" { xfail lp64 } 62 } */ +/* { dg-bogus "padding struct size" "PR23610" { xfail lp64 } 77 } */ +/* { dg-bogus "padding struct size" "PR23610" { xfail lp64 } 78 } */ diff --git a/gcc/testsuite/obj-c++.dg/bitfield-2.mm b/gcc/testsuite/obj-c++.dg/bitfield-2.mm new file mode 100644 index 000000000..f384f24dd --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/bitfield-2.mm @@ -0,0 +1,80 @@ +/* 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 <stdlib.h> + +#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/obj-c++.dg/bitfield-3.mm b/gcc/testsuite/obj-c++.dg/bitfield-3.mm new file mode 100644 index 000000000..d81976ab6 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/bitfield-3.mm @@ -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-do run { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-fsigned-char" } */ + +typedef struct objc_object { struct objc_class *class_pointer; } *id; + +#include <stdlib.h> +#include <string.h> + +#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/obj-c++.dg/bitfield-4.mm b/gcc/testsuite/obj-c++.dg/bitfield-4.mm new file mode 100644 index 000000000..35c32ee98 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/bitfield-4.mm @@ -0,0 +1,56 @@ +/* Check if the @defs() construct preserves the correct + layout of bitfields. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ +/* { dg-options "-Wpadded" } */ + +#include "../objc-obj-c++-shared/Object1.h" + +#include <stdlib.h> +#include <string.h> + +#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; +} +@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; + +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; +} + +/* { dg-prune-output "In file included from" } Ignore this message. */ +/* { dg-bogus "padding struct to align" "PR23610" { target *-*-* } 0 } */ + +/* { dg-bogus "padding struct size" "PR23610" { xfail lp64 } 28 } */ +/* { dg-bogus "padding struct size" "PR23610" { xfail lp64 } 34 } */ diff --git a/gcc/testsuite/obj-c++.dg/bitfield-5.mm b/gcc/testsuite/obj-c++.dg/bitfield-5.mm new file mode 100644 index 000000000..b6716df8d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/bitfield-5.mm @@ -0,0 +1,29 @@ + +/* 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 *-*-* } 13 } */ + unsigned a: 5; /* { dg-error "conflicting instance variable type .unsigned( int)? a: 5." } */ + /* { dg-error "previous declaration of .unsigned( int)? a: 3." "" { target *-*-* } 14 } */ + 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 *-*-* } 16 } */ +} +@end diff --git a/gcc/testsuite/obj-c++.dg/class-extension-1.mm b/gcc/testsuite/obj-c++.dg/class-extension-1.mm new file mode 100644 index 000000000..eab59c413 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/class-extension-1.mm @@ -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/obj-c++.dg/class-extension-2.mm b/gcc/testsuite/obj-c++.dg/class-extension-2.mm new file mode 100644 index 000000000..79b126f52 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/class-extension-2.mm @@ -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/obj-c++.dg/class-extension-3.mm b/gcc/testsuite/obj-c++.dg/class-extension-3.mm new file mode 100644 index 000000000..69e570539 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/class-extension-3.mm @@ -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/obj-c++.dg/class-extension-4.mm b/gcc/testsuite/obj-c++.dg/class-extension-4.mm new file mode 100644 index 000000000..9e19aa70d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/class-extension-4.mm @@ -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 () /* { dg-error "class extension for class .MyObject. declared after its ..implementation." } */ +- (void) test; +@end diff --git a/gcc/testsuite/obj-c++.dg/class-protocol-1.mm b/gcc/testsuite/obj-c++.dg/class-protocol-1.mm new file mode 100644 index 000000000..2ab702a4d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/class-protocol-1.mm @@ -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-error "between pointer" } */ + objP1 == num; /* { dg-error "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-error "between pointer" } */ + clsP1 == num; /* { dg-error "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-error "invalid conversion" } */ + objP1 = num; /* { dg-error "invalid conversion" } */ + + ptr = objP1; + objP1 = ptr; /* { dg-error "invalid conversion" } */ + } + { /* 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-error "invalid conversion" } */ + clsP1 = num; /* { dg-error "invalid conversion" } */ + + ptr = clsP1; + clsP1 = ptr; /* { dg-error "invalid conversion" } */ + } + { /* 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/obj-c++.dg/comp-types-1.mm b/gcc/testsuite/obj-c++.dg/comp-types-1.mm new file mode 100644 index 000000000..6d4e86e4b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-1.mm @@ -0,0 +1,16 @@ +/* { dg-do compile } */ + +@interface A ++ new; +@end + +@interface B : A +@end + +int main(int argc, char **argv) { + B *b = [B new]; + A *a = b; + + return (b == a); +} + diff --git a/gcc/testsuite/obj-c++.dg/comp-types-10.mm b/gcc/testsuite/obj-c++.dg/comp-types-10.mm new file mode 100644 index 000000000..c7f0cb635 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-10.mm @@ -0,0 +1,20 @@ +/* Yet another mysterious gimplifier crasher. */ +/* { dg-do compile } */ +/* { dg-prune-output ".*internal compiler error.*" } */ +/* { 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/obj-c++.dg/comp-types-11.mm b/gcc/testsuite/obj-c++.dg/comp-types-11.mm new file mode 100644 index 000000000..3d8598399 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-11.mm @@ -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/obj-c++.dg/comp-types-12.mm b/gcc/testsuite/obj-c++.dg/comp-types-12.mm new file mode 100644 index 000000000..37feff0a7 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-12.mm @@ -0,0 +1,13 @@ +/* { 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/obj-c++.dg/comp-types-13.mm b/gcc/testsuite/obj-c++.dg/comp-types-13.mm new file mode 100644 index 000000000..3a919d5d0 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-13.mm @@ -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/obj-c++.dg/comp-types-2.mm b/gcc/testsuite/obj-c++.dg/comp-types-2.mm new file mode 100644 index 000000000..07043785a --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-2.mm @@ -0,0 +1,88 @@ +/* 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/obj-c++.dg/comp-types-3.mm b/gcc/testsuite/obj-c++.dg/comp-types-3.mm new file mode 100644 index 000000000..2bea01534 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-3.mm @@ -0,0 +1,38 @@ +/* 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/obj-c++.dg/comp-types-4.mm b/gcc/testsuite/obj-c++.dg/comp-types-4.mm new file mode 100644 index 000000000..6867f8278 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-4.mm @@ -0,0 +1,64 @@ +/* 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/obj-c++.dg/comp-types-5.mm b/gcc/testsuite/obj-c++.dg/comp-types-5.mm new file mode 100644 index 000000000..99f6772bd --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-5.mm @@ -0,0 +1,74 @@ +/* Test errors 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 = (int *)NULL; + + /* These should all generate warnings. */ + + obj = i; /* { dg-error "invalid conversion" } */ + obj = j; /* { dg-error "cannot convert" } */ + + obj_p = i; /* { dg-error "invalid conversion" } */ + obj_p = j; /* { dg-error "cannot convert" } */ + + obj_c = i; /* { dg-error "invalid conversion" } */ + obj_c = j; /* { dg-error "cannot convert" } */ + + obj_C = i; /* { dg-error "invalid conversion" } */ + obj_C = j; /* { dg-error "cannot convert" } */ + + i = obj; /* { dg-error "invalid conversion" } */ + i = obj_p; /* { dg-error "invalid conversion" } */ + i = obj_c; /* { dg-error "invalid conversion" } */ + i = obj_C; /* { dg-error "invalid conversion" } */ + + j = obj; /* { dg-error "cannot convert" } */ + j = obj_p; /* { dg-error "cannot convert" } */ + j = obj_c; /* { dg-error "cannot convert" } */ + j = obj_C; /* { dg-error "cannot convert" } */ + + if (obj == i) ; /* { dg-error "comparison between pointer and integer" } */ + if (i == obj) ; /* { dg-error "comparison between pointer and integer" } */ + if (obj == j) ; /* { dg-error "lacks a cast" } */ + if (j == obj) ; /* { dg-error "lacks a cast" } */ + + if (obj_c == i) ; /*{ dg-error "comparison between pointer and integer" }*/ + if (i == obj_c) ; /*{ dg-error "comparison between pointer and integer" }*/ + if (obj_c == j) ; /* { dg-error "lacks a cast" } */ + if (j == obj_c) ; /* { dg-error "lacks a cast" } */ + + if (obj_p == i) ; /*{ dg-error "comparison between pointer and integer" }*/ + if (i == obj_p) ; /*{ dg-error "comparison between pointer and integer" }*/ + if (obj_p == j) ; /* { dg-error "lacks a cast" } */ + if (j == obj_p) ; /* { dg-error "lacks a cast" } */ + + if (obj_C == i) ; /*{ dg-error "comparison between pointer and integer" }*/ + if (i == obj_C) ; /*{ dg-error "comparison between pointer and integer" }*/ + if (obj_C == j) ; /* { dg-error "lacks a cast" } */ + if (j == obj_C) ; /* { dg-error "lacks a cast" } */ + + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/comp-types-6.mm b/gcc/testsuite/obj-c++.dg/comp-types-6.mm new file mode 100644 index 000000000..23b84edd3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-6.mm @@ -0,0 +1,33 @@ +/* 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/obj-c++.dg/comp-types-7.mm b/gcc/testsuite/obj-c++.dg/comp-types-7.mm new file mode 100644 index 000000000..e23558114 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-7.mm @@ -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/obj-c++.dg/comp-types-8.mm b/gcc/testsuite/obj-c++.dg/comp-types-8.mm new file mode 100644 index 000000000..490f4ff19 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-8.mm @@ -0,0 +1,33 @@ +/* { 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/obj-c++.dg/comp-types-9.mm b/gcc/testsuite/obj-c++.dg/comp-types-9.mm new file mode 100644 index 000000000..079140ac4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/comp-types-9.mm @@ -0,0 +1,25 @@ +/* { 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/obj-c++.dg/cxx-class-1.mm b/gcc/testsuite/obj-c++.dg/cxx-class-1.mm new file mode 100644 index 000000000..6cde9beb5 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/cxx-class-1.mm @@ -0,0 +1,18 @@ +/* Test that Objective-C++ is able to chew through a simple C++ class hierarchy. + This was broken in earlier ObjC++ incarnations. */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +struct foo +{ + foo(void *a) {}; +}; + +struct bar : foo +{ + bar() : foo((char*)0) {}; +}; + +class apple : foo +{ +public: + apple() : foo(0) { }; +}; diff --git a/gcc/testsuite/obj-c++.dg/cxx-ivars-1.mm b/gcc/testsuite/obj-c++.dg/cxx-ivars-1.mm new file mode 100644 index 000000000..6e0c3fded --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/cxx-ivars-1.mm @@ -0,0 +1,43 @@ +// Check if ivars may be accessed via the C++ dot notation. +// { dg-do run } +// { dg-options "-fno-objc-call-cxx-cdtors" } +// { 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() + +struct cxx_struct { + int a, b; + void set_values (int _a, int _b = 3) { + a = _a; b = _b; + } + ~cxx_struct (void) { + a = b = 99; + } +}; + +@interface Manip : Object { + int c; + cxx_struct s; // { dg-warning "user-defined destructor" } + // { dg-warning "constructors and destructors will not be invoked" "" { target *-*-* } 22 } +} +- (void) manipulate_ivars; +@end + +@implementation Manip +- (void) manipulate_ivars { + s.set_values (7); + CHECK_IF (s.a == 7 && s.b == 3); + s.~cxx_struct(); + CHECK_IF (s.a == 99 && s.b == 99); +} +@end + +int main (void) +{ + Manip *obj = [Manip new]; + [obj manipulate_ivars]; + [obj free]; +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/cxx-ivars-2.mm b/gcc/testsuite/obj-c++.dg/cxx-ivars-2.mm new file mode 100644 index 000000000..8f836ce90 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/cxx-ivars-2.mm @@ -0,0 +1,79 @@ +// Check if the '- .cxx_construct' and '-.cxx_destruct' methods get called +// and if they perform their desired function. + +// { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } +// { dg-do run { target *-*-darwin* } } +// { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } +// { dg-options "-fobjc-call-cxx-cdtors" } + +#include "../objc-obj-c++-shared/Object1.h" +#include <stdlib.h> +#define CHECK_IF(expr) if(!(expr)) abort() + +static int ctor1_called, ctor2_called, dtor1_called; + +struct bar { + int a, b; + bar(void) { + a = 5; b = 6; + ctor1_called++; + } + ~bar(void) { + a = b = 99; + dtor1_called++; + } +}; + +struct boo: bar { + int c; + boo(int _c = 9): c(_c) { + ctor2_called++; + } +}; + +@interface Baz: Object { +@public + bar aa; +} +@end + +@implementation Baz +@end + +@interface Foo: Baz { +@public + int a; + boo bb; + bar b; + float c; + bar d; +} +@end + +@implementation Foo +@end + +int main (void) +{ + CHECK_IF(!ctor1_called && !ctor2_called && !dtor1_called); /* are we sane? */ + + Baz *baz = [Baz new]; + CHECK_IF(ctor1_called && !ctor2_called && !dtor1_called); + CHECK_IF(baz->aa.a == 5 && baz->aa.b == 6); + ctor1_called = 0; /* reset */ + + [baz free]; + CHECK_IF(!ctor1_called && !ctor2_called && dtor1_called); + dtor1_called = 0; /* reset */ + + Foo *foo = [Foo new]; + CHECK_IF(ctor1_called && ctor2_called && !dtor1_called); + CHECK_IF(foo->bb.a == 5 && foo->bb.b == 6 && foo->bb.c == 9); + CHECK_IF(foo->b.a == 5 && foo->b.b == 6); + CHECK_IF(foo->d.a == 5 && foo->d.b == 6); + ctor1_called = ctor2_called = 0; /* reset */ + + [foo free]; + CHECK_IF(!ctor1_called && !ctor2_called && dtor1_called); +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/cxx-ivars-3.mm b/gcc/testsuite/obj-c++.dg/cxx-ivars-3.mm new file mode 100644 index 000000000..e94e6ec57 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/cxx-ivars-3.mm @@ -0,0 +1,54 @@ +// Check if ObjC classes with non-POD C++ ivars are specially marked in the metadata. + +// { dg-do run { target *-*-darwin* } } +// { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } +// { dg-options "-fobjc-call-cxx-cdtors -mmacosx-version-min=10.4" } +// This test has no equivalent or meaning for m64/ABI V2 +// { dg-xfail-run-if "No Test Avail" { *-*-darwin* && lp64 } { "-fnext-runtime" } { "" } } + +#include <objc/objc-runtime.h> +#include <stdlib.h> +#define CHECK_IF(expr) if(!(expr)) abort() + +#ifndef CLS_HAS_CXX_STRUCTORS +#define CLS_HAS_CXX_STRUCTORS 0x2000L +#endif + +struct cxx_struct { + int a, b; + cxx_struct (void) { a = b = 55; } +}; + +@interface Foo { + int c; + cxx_struct s; +} +@end + +@interface Bar: Foo { + float f; +} +@end + +@implementation Foo +@end + +@implementation Bar +@end + +int main (void) +{ +#ifndef __LP64__ + Class cls; + + cls = objc_getClass("Foo"); + CHECK_IF(cls->info & CLS_HAS_CXX_STRUCTORS); + cls = objc_getClass("Bar"); + CHECK_IF(!(cls->info & CLS_HAS_CXX_STRUCTORS)); + +#else + /* No test needed or available. */ + abort (); +#endif + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/cxx-scope-1.mm b/gcc/testsuite/obj-c++.dg/cxx-scope-1.mm new file mode 100644 index 000000000..a576bbd4f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/cxx-scope-1.mm @@ -0,0 +1,54 @@ +/* Handle C++ scoping ('::') operators in ObjC message receivers gracefully. */ +/* Author: 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> + +@class Derived; + +Derived *inst[3]; + +struct CxxClass { + static Derived *get_instance(int); +}; + +Derived *CxxClass::get_instance(int offs) { + return inst[offs]; +} + +@interface Derived: Object { + int value; +} +-(id)initWithValue:(int)val; +-(int)derived_meth; +@end + +@implementation Derived +-(id)initWithValue:(int)val { + [super init]; + value = val; + return self; +} +- (int)derived_meth { + return value; +} +@end + +int main(void) { + int r; + inst[1] = [[::Derived alloc] initWithValue:7]; + inst[2] = [[Derived alloc] initWithValue:77]; + + r = [CxxClass::get_instance(2) derived_meth]; + if (r != 77) + abort(); + + r = [CxxClass::get_instance(1) derived_meth]; + if (r != 7) + abort(); + + return 0; +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/cxx-scope-2.mm b/gcc/testsuite/obj-c++.dg/cxx-scope-2.mm new file mode 100644 index 000000000..c793b282f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/cxx-scope-2.mm @@ -0,0 +1,19 @@ +/* Make sure Objective-C++ can distinguish ObjC classes from C++ classes. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include <iostream> +#include <string> + +@interface iostream: Object +@end + +int main(void) { + id i = [std::iostream new]; /* { dg-error "not an Objective\\-C class name or alias" } */ + i = [iostream new]; + i = [std::basic_string<char> new]; /* { dg-error "not an Objective\\-C class name or alias" } */ + + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/defs.mm b/gcc/testsuite/obj-c++.dg/defs.mm new file mode 100644 index 000000000..0e8b26c72 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/defs.mm @@ -0,0 +1,43 @@ +/* Check @defs() in Objective-C++ */ +/* Contributed by Devang Patel <dpatel@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 <stdlib.h> +#include <objc/objc.h> + +extern "C" void abort(void); + +@interface A : Object +{ + @public + int a; +} +@end + +struct A_defs +{ + @defs(A); +}; + +@implementation A +- init +{ + a = 42; + return self; +} +@end + + +int main() +{ + A *a = [A init]; + struct A_defs *a_defs = (struct A_defs *)a; + + if (a->a != a_defs->a) + abort (); + + return 0; +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/demangle-1.mm b/gcc/testsuite/obj-c++.dg/demangle-1.mm new file mode 100644 index 000000000..015a3aff8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/demangle-1.mm @@ -0,0 +1,35 @@ +/* Test demangling a C++ function. */ +/* { dg-do run } */ + +#include <cstring> +#include <cstdlib> +#include <iostream> + +class demangle_test +{ +public: + /* Return 0 if the demangling test succeeds. */ + static int test_function1 () + { + std::cout << __PRETTY_FUNCTION__ << "\n"; + return std::strcmp (__PRETTY_FUNCTION__, "static int demangle_test::test_function1()"); + } + + /* Return 0 if the demangling test succeeds. */ + static int test_function2 (int ignored) + { + std::cout << __PRETTY_FUNCTION__ << "\n"; + return std::strcmp (__PRETTY_FUNCTION__, "static int demangle_test::test_function2(int)"); + } +}; + +int main () +{ + if (demangle_test::test_function1 () != 0) + abort (); + + if (demangle_test::test_function2 (0) != 0) + abort (); + + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/demangle-2.mm b/gcc/testsuite/obj-c++.dg/demangle-2.mm new file mode 100644 index 000000000..f28208591 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/demangle-2.mm @@ -0,0 +1,53 @@ +/* Test demangling an Objective-C method. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <cstring> +#include <cstdlib> +#include <iostream> +#include <objc/objc.h> + +@interface DemangleTest +{ + Class isa; +} ++ (int) testFunction1; ++ (int) test_function2; ++ (int) __testFunction3: (int)unused andArgument: (char)unused2; ++ (id) initialize; +@end + +@implementation DemangleTest ++ (int) testFunction1 +{ + std::cout << __PRETTY_FUNCTION__ << "\n"; + return std::strcmp (__PRETTY_FUNCTION__, "+[DemangleTest testFunction1]"); +} ++ (int) test_function2 +{ + std::cout << __PRETTY_FUNCTION__ << "\n"; + return std::strcmp (__PRETTY_FUNCTION__, "+[DemangleTest test_function2]"); +} ++ (int) __testFunction3: (int)unused andArgument: (char)unused2 +{ + std::cout << __PRETTY_FUNCTION__ << "\n"; + return std::strcmp (__PRETTY_FUNCTION__, "+[DemangleTest __testFunction3:andArgument:]"); +} ++ (id) initialize { return self; } +@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/obj-c++.dg/demangle-3.mm b/gcc/testsuite/obj-c++.dg/demangle-3.mm new file mode 100644 index 000000000..01e6c618e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/demangle-3.mm @@ -0,0 +1,21 @@ +/* Test demangling an Objective-C method in error messages. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface DemangleTest +{ + Class isa; +} ++ (int) testFunction1; +@end + +@implementation DemangleTest ++ (int) testFunction1 +{ + /* TODO: Hack the testsuite so we can test that we get + dg-error "In function .+[DemangleTest testFunction1]." + At the moment, the message is filtered out. */ + z; /* { dg-error "was not declared" } */ +} +@end diff --git a/gcc/testsuite/obj-c++.dg/dg.exp b/gcc/testsuite/obj-c++.dg/dg.exp new file mode 100644 index 000000000..fb809b484 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/dg.exp @@ -0,0 +1,42 @@ +# GCC Objective-C++ testsuite that uses the `dg.exp' driver. +# Copyright (C) 2004, 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 obj-c++-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_OBJCXXFLAGS +if ![info exists DEFAULT_OBJCXXFLAGS] then { + set DEFAULT_OBJCXXFLAGS " -ansi -pedantic-errors -Wno-long-long" +} + +# Initialize `dg'. +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]] + +# Main loop. +dg-runtest $tests "-fgnu-runtime" $DEFAULT_OBJCXXFLAGS + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { +dg-runtest $tests "-fnext-runtime" $DEFAULT_OBJCXXFLAGS +} + +# All done. +dg-finish diff --git a/gcc/testsuite/obj-c++.dg/duplicate-class-1.mm b/gcc/testsuite/obj-c++.dg/duplicate-class-1.mm new file mode 100644 index 000000000..9476533d1 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/duplicate-class-1.mm @@ -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 /* { dg-error "reimplementation of class .Test." } */ +- (int) test2 +{ + return [self test]; +} +@end +/* { dg-warning "incomplete implementation" "" { target *-*-* } 29 } */ +/* { dg-warning "not found" "" { target *-*-* } 29 } */ diff --git a/gcc/testsuite/obj-c++.dg/dwarf-2.mm b/gcc/testsuite/obj-c++.dg/dwarf-2.mm new file mode 100644 index 000000000..e938249d7 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/dwarf-2.mm @@ -0,0 +1,4 @@ +/* { dg-options "-gdwarf-2 -dA" } */ +/* { dg-skip-if "" { { hppa*-*-hpux* } && { ! hppa*64*-*-* } } { "*" } { "" } } */ +/* { dg-final { scan-assembler "0x11\[^0-9a-f\].*DW_AT_language" } } */ +int x; diff --git a/gcc/testsuite/obj-c++.dg/empty-private-1.mm b/gcc/testsuite/obj-c++.dg/empty-private-1.mm new file mode 100644 index 000000000..b8b90b07e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/empty-private-1.mm @@ -0,0 +1,9 @@ +/* Test for no entry after @private token. */ + +/* { do-do compile } */ + +@interface foo +{ +@private +} +@end diff --git a/gcc/testsuite/obj-c++.dg/encode-1-next.mm b/gcc/testsuite/obj-c++.dg/encode-1-next.mm new file mode 100644 index 000000000..47673f20c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/encode-1-next.mm @@ -0,0 +1,26 @@ +/* This file tests that things are encoded using the gcc-3.3 ABI which is only + used by the NeXT runtime. */ +/* 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/obj-c++.dg/encode-1.mm b/gcc/testsuite/obj-c++.dg/encode-1.mm new file mode 100644 index 000000000..5f5ba2013 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/encode-1.mm @@ -0,0 +1,24 @@ +/* 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/obj-c++.dg/encode-10.mm b/gcc/testsuite/obj-c++.dg/encode-10.mm new file mode 100644 index 000000000..2b3af88dc --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/encode-10.mm @@ -0,0 +1,46 @@ +/* Test for @encode in templates. */ +/* { dg-options "-lobjc" } */ +/* { dg-do run } */ +#include <string.h> +#include <stdlib.h> + +template<typename T> +const char *my_encode(int variant) +{ + const char *result; + + switch (variant) + { + case 0: + result = @encode(T); + break; + case 1: + result = @encode(T*); + break; + case 2: + result = @encode(const T*); + break; + default: + result = @encode(int); + break; + } + + return result; +} + +int main() +{ + if (strcmp (@encode(char), my_encode<char>(0))) + abort (); + + if (strcmp (@encode(char *), my_encode<char>(1))) + abort (); + + if (strcmp (@encode(const char *), my_encode<char>(2))) + abort (); + + if (strcmp (@encode(int), my_encode<char>(3))) + abort (); + + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/encode-2.mm b/gcc/testsuite/obj-c++.dg/encode-2.mm new file mode 100644 index 000000000..157bb5267 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/encode-2.mm @@ -0,0 +1,28 @@ +/* { dg-do assemble } */ +/* { dg-options "-save-temps" } */ + +template <class T> +struct Vec { + T x, y; + int z; +}; + +typedef struct { + Vec<double> dvec; + Vec<float> fvec; + float fscalar; + double dscalar; + Vec<signed char> chVec; + int iscalar; +} anonymous; + +Vec<double> dd; + +const char *enc = @encode(Vec<float>); +const char *enc2 = @encode(Vec<double>); +const char *enc3 = @encode(anonymous); + +/* { dg-final { scan-assembler "{Vec<float>=ffi}" } } */ +/* { dg-final { scan-assembler "{Vec<double>=ddi}" } } */ +/* { dg-final { scan-file "encode-2.o" "{?={Vec<double>=ddi}{Vec<float>=ffi}fd{Vec<signed char>=cci}i}" } } +/* { dg-final cleanup-saved-temps } */ diff --git a/gcc/testsuite/obj-c++.dg/encode-3.mm b/gcc/testsuite/obj-c++.dg/encode-3.mm new file mode 100644 index 000000000..1486a652a --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/encode-3.mm @@ -0,0 +1,60 @@ +/* { dg-do run } */ + +extern "C" { +extern void abort (void); +extern int strcmp (const char *, const char *); +} + +template <class T> +struct Vec { + T x, y; + long z; + long long zz; +}; + +typedef struct { + float fscalar; + double dv[10]; + int iscalar; + long z; + long long zz; + Vec<const signed char> cv; +} anonymous; + +//Vec<double> dd; +const char *enc = @encode(Vec<float>); +const char *enc2 = @encode(Vec<double>); +const char *enc3 = @encode(anonymous); + +#ifdef __LP64__ +#define L "q" +#else +#define L "l" +#endif + +/* Darwin (at least, as of XCode 3.2.3/Darwin10) does not encode the read-only + attribute on the type. Arguably, this is a bug, but we are compatible + with this when -fnext-runtime is selected. */ +#ifdef __NEXT_RUNTIME__ +#define E3 "{?=f[10d]i" L "q{Vec<const signed char>=cc" L "q}}" +#else +#define E3 "{?=f[10d]i" L "q{Vec<const signed char>=rcrc" L "q}}" +#endif + +int main(void) { + const char *encode = @encode(long); + + if (strcmp (encode, L)) + abort (); + + if (strcmp (enc, (const char *)"{Vec<float>=ff" L "q}")) + abort (); + + if (strcmp (enc2, (const char *)"{Vec<double>=dd" L "q}")) + abort (); + + if (strcmp (enc3, (const char *) E3)) + abort (); + + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/encode-4.mm b/gcc/testsuite/obj-c++.dg/encode-4.mm new file mode 100644 index 000000000..b973abe2d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/encode-4.mm @@ -0,0 +1,101 @@ +/* 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 + +#include <stdio.h> +#include <stdlib.h> + +#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/obj-c++.dg/encode-5.mm b/gcc/testsuite/obj-c++.dg/encode-5.mm new file mode 100644 index 000000000..18db3f3dd --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/encode-5.mm @@ -0,0 +1,95 @@ +/* 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 "../objc-obj-c++-shared/Object1.h" +#include "../objc-obj-c++-shared/next-mapping.h" +#include "../objc-obj-c++-shared/Protocol1.h" +#ifdef __cplusplus +#define ProtoBool bool +#else +#define ProtoBool _Bool +#endif + +#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 + +#include <stdio.h> +#include <stdlib.h> + +#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 = @protocol(Proto); +struct objc_method_description *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(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; + + meth = [proto descriptionForInstanceMethod: @selector(char:float:double:unsigned:short:long:)]; + 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)); + meth = [proto descriptionForInstanceMethod: @selector(setRect:withBool:withInt:)]; + 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)); + meth = [proto descriptionForClassMethod: @selector(getEnum:enum:bool:)]; + /* 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' */ + meth = [proto descriptionForClassMethod: @selector(getBool:)]; + scan_initial("^^B%u@%u:%u^*%u"); + CHECK_IF(totsize == offs2 + sizeof(ObjCBool **)); + return 0; +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/encode-6.mm b/gcc/testsuite/obj-c++.dg/encode-6.mm new file mode 100644 index 000000000..987d4a8ae --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/encode-6.mm @@ -0,0 +1,89 @@ +/* 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" +#ifndef __NEXT_RUNTIME__ +#include <objc/objc-api.h> +#endif + +#include <stdlib.h> +#include <string.h> + +#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/obj-c++.dg/encode-7.mm b/gcc/testsuite/obj-c++.dg/encode-7.mm new file mode 100644 index 000000000..523c7ce02 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/encode-7.mm @@ -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/obj-c++.dg/encode-8.mm b/gcc/testsuite/obj-c++.dg/encode-8.mm new file mode 100644 index 000000000..9321ceaa3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/encode-8.mm @@ -0,0 +1,23 @@ +/* Test if the Objective-C @encode machinery distinguishes between + 'BOOL *' (which should be encoded as '^c') and 'char *' (which + should be encoded as '*'). */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ + +#include <string.h> +#include <stdlib.h> +#include <objc/objc.h> + +int main(void) { + const char *BOOL_ptr = @encode(BOOL *); + const char *char_ptr = @encode(char *); + + if(strcmp(BOOL_ptr, "^c")) + abort(); + + if(strcmp(char_ptr, "*")) + abort(); + + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/encode-9.mm b/gcc/testsuite/obj-c++.dg/encode-9.mm new file mode 100644 index 000000000..6b064dfdc --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/encode-9.mm @@ -0,0 +1,26 @@ +/* Test than @encode is properly instantiated. */ +/* { dg-options "-lobjc" } */ +/* { dg-do run } */ + +#include <string.h> +#include <stdlib.h> +#include <objc/objc.h> + +template<typename T> +class typeOf { +public: + operator const char*() { return @encode(T); } +}; + +int main() { + typeOf<int> t; + if (strcmp ((const char *)t, @encode(int))) + abort(); + + typeOf<const char*> c; + if (strcmp ((const char *)c, @encode(const char*))) + abort(); + + return 0; +} + diff --git a/gcc/testsuite/obj-c++.dg/enhanced-proto-1.mm b/gcc/testsuite/obj-c++.dg/enhanced-proto-1.mm new file mode 100644 index 000000000..97e14206b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/enhanced-proto-1.mm @@ -0,0 +1,18 @@ +/* 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/obj-c++.dg/enhanced-proto-2.mm b/gcc/testsuite/obj-c++.dg/enhanced-proto-2.mm new file mode 100644 index 000000000..31c2e509b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/enhanced-proto-2.mm @@ -0,0 +1,23 @@ +/* { 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/obj-c++.dg/except-1.mm b/gcc/testsuite/obj-c++.dg/except-1.mm new file mode 100644 index 000000000..b835dc73e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/except-1.mm @@ -0,0 +1,67 @@ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* This tests that exceptions work. It used to fail because + objc_msgSend was marked with DECL_NOTHROW. + If you include objc/Object.h, the problem goes away, because + that file includes objc/objc-runtime.h which explicitly prototypes + objc_msgSend without 'nothrow'. */ + +#include <stdio.h> +#include <stdlib.h> +#include "../objc-obj-c++-shared/Object1.h" + +// ObjectiveC class header +@interface ObjCclass : Object { +} +-(void)method1; +-(void)method2; +@end + +// C++ class header +class CPPclass { +public: + void function1(); +}; + + +// Main +int main(int argc, char *argv[]) +{ + ObjCclass * foo = [[ObjCclass alloc] init]; + [foo method1]; + exit (0); +} + + +// ObjectiveC implementation +@implementation ObjCclass + +-(void) method1 +{ + try { + [self method2]; + } + catch(...) { + return; + } +} + +-(void) method2 +{ + CPPclass foo; + foo.function1(); +} + +@end + + +// C++ implementation +void CPPclass::function1() +{ + throw (1); + /* Shouldn't be here because we threw. */ + abort (); +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/exceptions-1.mm b/gcc/testsuite/obj-c++.dg/exceptions-1.mm new file mode 100644 index 000000000..0f3b7e8ae --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/exceptions-1.mm @@ -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/obj-c++.dg/exceptions-2.mm b/gcc/testsuite/obj-c++.dg/exceptions-2.mm new file mode 100644 index 000000000..989831f84 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/exceptions-2.mm @@ -0,0 +1,54 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ + +/* FIXME: This does not test running the code, because Objective-C exceptions at the moment + do not execute correctly in Objective-C++. See PR objc++/23616. Once that is fixed, + this test should be changed to use 'dg-do run' instead of just 'dg-do compile'. */ +/* { dg-do compile } */ +/* { dg-options "-fobjc-exceptions" } */ + +/* 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/obj-c++.dg/exceptions-3.mm b/gcc/testsuite/obj-c++.dg/exceptions-3.mm new file mode 100644 index 000000000..bf0be018e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/exceptions-3.mm @@ -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 "no matching function" "" { target *-*-* } 72 } */ + dummy++; /* { dg-message "MyObject" "" { target *-*-* } 13 } */ + } /* { dg-message "candidate" "" { target *-*-* } 13 } */ + /* { dg-message "candidates" "" { target *-*-* } 72 } */ + @try { @throw object; } + @catch (static MyObject *x) /* { dg-error "storage class" } */ + { + 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/obj-c++.dg/exceptions-4.mm b/gcc/testsuite/obj-c++.dg/exceptions-4.mm new file mode 100644 index 000000000..85debe444 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/exceptions-4.mm @@ -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" } */ + dummy++; /* { dg-error "@catch parameter is not a known Objective-C class type" "" { target *-*-* } 35 } */ + } + @catch () /* { dg-error "expected identifier before" } */ + { /* { dg-error "@catch parameter is not a known Objective-C class type" "" { target *-*-* } 38 } */ + dummy++; + } + @catch (i) /* { dg-error ".i. has not been declared" } */ + { /* { dg-error "@catch parameter is not a known Objective-C class type" "" { target *-*-* } 42 } */ + 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; /* { dg-error "expected ... before .return." } */ +} diff --git a/gcc/testsuite/obj-c++.dg/exceptions-5.mm b/gcc/testsuite/obj-c++.dg/exceptions-5.mm new file mode 100644 index 000000000..1ea9a6f46 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/exceptions-5.mm @@ -0,0 +1,115 @@ +/* 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.mm, 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 "no matching function" "" { target *-*-* } 72 } */ + dummy++; /* { dg-message "MyObject" "" { target *-*-* } 13 } */ + } /* { dg-message "candidate" "" { target *-*-* } 13 } */ + /* { dg-message "candidate" "" { target *-*-* } 72 } */ + + @try { @throw object; } + @catch (static MyObject *) /* { dg-error "storage class" } */ + { + 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/obj-c++.dg/exceptions-6.mm b/gcc/testsuite/obj-c++.dg/exceptions-6.mm new file mode 100644 index 000000000..58882fed8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/exceptions-6.mm @@ -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/obj-c++.dg/exceptions-7.mm b/gcc/testsuite/obj-c++.dg/exceptions-7.mm new file mode 100644 index 000000000..1f5adfc89 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/exceptions-7.mm @@ -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/obj-c++.dg/extern-c-1.mm b/gcc/testsuite/obj-c++.dg/extern-c-1.mm new file mode 100644 index 000000000..c5fec6fbe --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/extern-c-1.mm @@ -0,0 +1,18 @@ +/* Test extern c support inside @implementation */ +/* Devang Patel <dpatel@apple.com>. */ + +#include <objc/objc.h> + +@interface Extern +@end + +@implementation Extern + +extern "C" void NSRegisterElement(id element); + +- init { + NSRegisterElement(self); + return self; +} + +@end diff --git a/gcc/testsuite/obj-c++.dg/extra-semi.mm b/gcc/testsuite/obj-c++.dg/extra-semi.mm new file mode 100644 index 000000000..ad555962d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/extra-semi.mm @@ -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/obj-c++.dg/fix-and-continue-2.mm b/gcc/testsuite/obj-c++.dg/fix-and-continue-2.mm new file mode 100644 index 000000000..fdfbcbd0c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/fix-and-continue-2.mm @@ -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/obj-c++.dg/fobjc-exceptions-1.mm b/gcc/testsuite/obj-c++.dg/fobjc-exceptions-1.mm new file mode 100644 index 000000000..8cee4d849 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/fobjc-exceptions-1.mm @@ -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/obj-c++.dg/fobjc-exceptions-2.mm b/gcc/testsuite/obj-c++.dg/fobjc-exceptions-2.mm new file mode 100644 index 000000000..32b3506ec --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/fobjc-exceptions-2.mm @@ -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/obj-c++.dg/fobjc-exceptions-3.mm b/gcc/testsuite/obj-c++.dg/fobjc-exceptions-3.mm new file mode 100644 index 000000000..d3d6453df --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/fobjc-exceptions-3.mm @@ -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/obj-c++.dg/fobjc-std-1.mm b/gcc/testsuite/obj-c++.dg/fobjc-std-1.mm new file mode 100644 index 000000000..59db95091 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/fobjc-std-1.mm @@ -0,0 +1,82 @@ +/* Test warnings when using -fobjc-std=objc1. */ +/* { dg-do compile } */ +/* { dg-options "-fobjc-std=objc1" } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; /* { dg-error ".@package. is not available in Objective.C 1.0" } */ +@package + 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" } */ +/* There is a problem with the testsuite on the following line; the compiler seems Ok, but the testsuite still barfs. */ +/*@synthesize a;*/ /* dg-error "not available in Objective.C 1.0" */ +/* The following lines replace the synthesize to prevent warnings. */ +- (int) a { return a; } +- (void) setA: (int)value { a = value; } +@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 /* { dg-error "protocol attributes are not available in Objective.C 1.0" } */ +- (id) test; +@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 +#if 0 /* fast enumeration is not implemented even in Objective-C 2.0 */ +@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; +} +#endif + +id test (void) +{ + return MyRootClass.name; /* { dg-error "not available in Objective.C 1.0" } */ +} + +@interface MyRootClass3 +{ + Class isa; +} +@end + +/* There is a problem with the testsuite on the following line; the compiler seems Ok, but the testsuite still barfs. */ +/* @interface MyRootClass3 () */ /* dg-error "not available in Objective.C 1.0" */ +/* @end */ diff --git a/gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm b/gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm new file mode 100644 index 000000000..caeaa0300 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm @@ -0,0 +1,51 @@ +/* Check NSString format extensions. */ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-options "-Wall" } */ + +#ifndef __CONSTANT_CFSTRINGS__ +#error requires CFString +#endif + +#ifdef __cplusplus +extern "C" { +#endif +extern int printf (const char *fmt, ...); +typedef const struct __CFString * CFStringRef; + +#ifdef __cplusplus +} +#endif + +@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 (@"this 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 *-*-* } 48 } */ + printf(s9 (1, (char *)"and so is this %d %d %s" , 3, 4, "hm"), 5, 6, 12); /* { dg-warning "format '%s' expects argument of type 'char.', but argument 4 has type 'int'" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/fsf-package-0.m b/gcc/testsuite/obj-c++.dg/fsf-package-0.m new file mode 100644 index 000000000..d6b4db217 --- /dev/null +++ b/gcc/testsuite/obj-c++.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/obj-c++.dg/gnu-api-2-class.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm new file mode 100644 index 000000000..1e79e9b95 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm @@ -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 <iostream> +#include <cstring> + +@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 () +{ + /* Functions are tested in alphabetical order. */ + + std::cout << "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 (std::strcmp (ivar_getName (variable2), "variable2_ivar") != 0) + abort (); + + if (std::strcmp (ivar_getName (variable3), "variable3_ivar") != 0) + abort (); + + if (std::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 (); + } + } + } + + std::cout << "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 (); + } + + std::cout << "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 (); + } + + std::cout << "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 (); + } + + std::cout << "Testing class_copyIvarList ()...\n"; + { + unsigned int count; + Ivar * list = class_copyIvarList (objc_getClass ("MySubClass"), &count); + + if (count != 1) + abort (); + + if (std::strcmp (ivar_getName (list[0]), "variable_ivar") != 0) + abort (); + + if (list[1] != NULL) + abort (); + } + + std::cout << "Testing class_copyMethodList ()...\n"; + { + unsigned int count; + Method * list = class_copyMethodList (objc_getClass ("MySubClass"), &count); + + if (count != 2) + abort (); + + if (! ((std::strcmp (sel_getName (method_getName (list[0])), "variable") == 0 + && std::strcmp (sel_getName (method_getName (list[1])), "setVariable:") == 0) + || (std::strcmp (sel_getName (method_getName (list[0])), "setVariable:") == 0 + && std::strcmp (sel_getName (method_getName (list[1])), "variable") == 0))) + abort (); + + if (list[2] != NULL) + abort (); + } + + /* TODO: Test new ABI (when available). */ + std::cout << "Testing class_copyPropertyList ()...\n"; + { + unsigned int count; + objc_property_t * list = class_copyPropertyList (objc_getClass ("MySubClass"), &count); + + if (count != 0 || list != NULL) + abort (); + } + + std::cout << "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 (! ((std::strcmp (protocol_getName (list[0]), "MyProtocol") == 0 + && std::strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0) + || (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0 + && std::strcmp (protocol_getName (list[1]), "MyProtocol") == 0))) + abort (); + + if (list[2] != NULL) + abort (); + } + + std::cout << "Testing class_createInstance ()...\n"; + { + MySubClass *object = [[MySubClass alloc] init]; + + [object setVariable: object]; + if ([object variable] != object) + abort (); + } + + std::cout << "Testing class_getClassMethod ()...\n"; + { + Method method = class_getClassMethod (objc_getClass ("MySubClass"), + @selector(alloc)); + + if (method == NULL) + abort (); + + if (std::strcmp (sel_getName (method_getName (method)), "alloc") != 0) + abort (); + + if (class_getClassMethod (objc_getClass ("MySubClass"), + @selector(variable))) + abort (); + } + + std::cout << "Testing class_getClassVariable ()...\n"; + { + if (class_getClassVariable (objc_getClass ("MySubClass"), "variable_ivar")) + abort (); + } + + std::cout << "Testing class_getInstanceMethod ()...\n"; + { + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector(variable)); + + if (method == NULL) + abort (); + + if (std::strcmp (sel_getName (method_getName (method)), "variable") != 0) + abort (); + + if (class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector(alloc))) + abort (); + } + + std::cout << "Testing class_getInstanceSize ()...\n"; + { + if (class_getInstanceSize (objc_getClass ("MyRootClass")) != sizeof (struct objc_object)) + abort (); + } + + std::cout << "Testing class_getInstanceVariable ()...\n"; + { + Ivar variable = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar"); + + if (variable == NULL) + abort (); + + if (std::strcmp (ivar_getName (variable), "variable_ivar") != 0) + abort (); + + if (class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar_no")) + abort (); + } + + std::cout << "Testing class_getIvarLayout ()...\n"; + { + if (class_getIvarLayout (objc_getClass ("MyRootClass")) != NULL) + abort (); + } + + std::cout << "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. */ + /* std::cout << "Testing class_getMethodImplementation_stret ()...\n"; */ + + std::cout << "Testing class_getName ()...\n"; + { + if (std::strcmp (class_getName (objc_getClass ("MyRootClass")), + "MyRootClass") != 0) + abort (); + } + + /* TODO: Test new ABI (when available). */ + std::cout << "Testing class_getProperty ()...\n"; + { + if (class_getProperty (objc_getClass ("MyRootClass"), "property") != NULL) + abort (); + } + + std::cout << "Testing class_getSuperclass ()...\n"; + { + MySubClass *object = [[MySubClass alloc] init]; + if (class_getSuperclass (object_getClass (object)) != objc_getClass ("MyRootClass")) + abort (); + } + + std::cout << "Testing class_getVersion ()...\n"; + { + if (class_getVersion (objc_getClass ("MySubClass")) != 0) + abort (); + } + + std::cout << "Testing class_getWeakIvarLayout ()...\n"; + { + if (class_getWeakIvarLayout (objc_getClass ("MyRootClass")) != NULL) + abort (); + } + + std::cout << "Testing class_isMetaClass ()...\n"; + { + MySubClass *object = [[MySubClass alloc] init]; + if (class_isMetaClass (object_getClass (object)) + || ! class_isMetaClass (object_getClass (object_getClass (object)))) + abort (); + } + + std::cout << "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 (); + } + } + + std::cout << "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. */ + /* std::cout << "Testing class_setIvarLayout ()...\n"; */ + + std::cout << "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. */ + /* std::cout << "Testing class_setWeakIvarLayout ()...\n"; */ + + return (0); +} diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm new file mode 100644 index 000000000..1c85d238d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm @@ -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 <iostream> +#include <cstring> + +@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 () +{ + /* Functions are tested in alphabetical order. */ + + std::cout << "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 (); + } + + std::cout << "Testing ivar_getOffset () ...\n"; + { + Ivar ivar = class_getInstanceVariable (objc_getClass ("MyRootClass"), + "isa"); + if (ivar_getOffset (ivar) != 0) + abort (); + } + + std::cout << "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/obj-c++.dg/gnu-api-2-method.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm new file mode 100644 index 000000000..4029ce73c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm @@ -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 <iostream> +#include <cstring> + +@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 () +{ + /* Functions are tested in alphabetical order. */ + + std::cout <<"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 (); + } + + std::cout << "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 (); + } + + std::cout << "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 (); + } + + std::cout << "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 (); + } + + std::cout << "Testing method_getDescription () ...\n"; + { + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (variable)); + struct objc_method_description *description = method_getDescription (method); + + if (std::strcmp (sel_getName (description->name), "variable") != 0) + abort (); + + if (method_getDescription (NULL) != NULL) + abort (); + } + + std::cout << "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 (); + } + + std::cout << "Testing method_getName () ...\n"; + { + Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), + @selector (setVariable:)); + if (std::strcmp (sel_getName (method_getName (method)), "setVariable:") != 0) + abort (); + } + + std::cout << "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 (); + } + + std::cout << "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 (); + } + + std::cout << "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 (); + } + + std::cout << "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/obj-c++.dg/gnu-api-2-objc.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm new file mode 100644 index 000000000..90da96ae5 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm @@ -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 <iostream> +#include <cstring> + +@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 () +{ + /* Functions are tested in alphabetical order. */ + + std::cout << "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 (std::strcmp (class_getName (new_class), "MyNewSubClass") != 0) + abort (); + + if (class_getSuperclass (new_class) != objc_getClass ("MyRootClass")) + abort (); + + if (std::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 (); + } + } + + std::cout << "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 (! ((std::strcmp (protocol_getName (list[0]), "MyProtocol") == 0 + && std::strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0) + || (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0 + && std::strcmp (protocol_getName (list[1]), "MyProtocol") == 0))) + abort (); + + if (list[2] != NULL) + abort (); + } + + std::cout << "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. */ + /* std::cout << "Testing objc_duplicateClass ()...\n"; */ + + /* TODO - Test it when implemented in the GNU Runtime */ + /* std::cout << "Testing objc_getAssociatedObject ()...\n"; */ + + std::cout << "Testing objc_getClass ()...\n"; + { + if (std::strcmp (class_getName (objc_getClass ("MySubClass")), + "MySubClass") != 0) + abort (); + } + + std::cout << "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 = (Class *)(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 (std::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 (std::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 (std::strcmp (class_getName (list[i]), "Protocol") == 0) + break; + } + if (i == count) + abort (); + } + + /* This function does not exist with the GNU runtime. */ + /* std::cout << "Testing objc_getFutureClass ()...\n"; */ + + std::cout << "Testing objc_getMetaClass ()...\n"; + { + if (! class_isMetaClass (objc_getMetaClass ("MyRootClass"))) + abort (); + } + + std::cout << "Testing objc_getProtocol ()...\n"; + { + if (! protocol_isEqual (objc_getProtocol ("MyProtocol"), @protocol (MyProtocol))) + abort (); + } + + std::cout << "Testing objc_getRequiredClass ()...\n"; + { + if (std::strcmp (class_getName (objc_getRequiredClass ("MyRootClass")), + "MyRootClass") != 0) + abort (); + } + + std::cout << "Testing objc_lookUpClass ()...\n"; + { + if (std::strcmp (class_getName (objc_lookUpClass ("MyRootClass")), + "MyRootClass") != 0) + abort (); + } + + /* This function does not exist with the GNU runtime. */ + /* std::cout << "Testing objc_setFutureClass ()...\n"; */ + + std::cout << "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 (std::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 */ + /* std::cout << "Testing objc_removeAssociatedObjects ()...\n"; */ + + /* TODO - Test it when implemented in the GNU Runtime */ + /* std::cout << "Testing objc_setAssociatedObject ()...\n"; */ + + return (0); +} diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-objc_msg_lookup.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-objc_msg_lookup.mm new file mode 100644 index 000000000..dcbf6d21f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-objc_msg_lookup.mm @@ -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 <iostream> +#include <cstring> + +@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 () +{ + /* Functions are tested in alphabetical order. */ + + std::cout << "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 (); + } + + std::cout << "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/obj-c++.dg/gnu-api-2-object.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm new file mode 100644 index 000000000..a2702d647 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm @@ -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 <iostream> +#include <cstring> + +@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 () +{ + /* Functions are tested in alphabetical order. */ + + std::cout << "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 (); + } + + std::cout << "Testing object_dispose () ...\n"; + { + MySubClass *object = [[MySubClass alloc] init]; + + object_dispose (object); + } + + std::cout << "Testing object_getClass () ...\n"; + { + MyRootClass *o = [[MySubClass alloc] init]; + + if (object_getClass (o) != objc_getClass ("MySubClass")) + abort (); + } + + std::cout << "Testing object_getClassName () ...\n"; + { + MyRootClass *o = [[MyRootClass alloc] init]; + + if (std::strcmp (object_getClassName (o), "MyRootClass") != 0) + abort (); + } + + std::cout << "Testing object_getIndexedIvars () ...\n"; + { + if (object_getIndexedIvars ([[MyRootClass alloc] init]) == NULL) + abort (); + } + + std::cout << "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 (); + } + + std::cout << "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 (); + } + + std::cout << "Testing object_setClass () ...\n"; + { + MySubClass *o = [[MySubClass alloc] init]; + + object_setClass (o, objc_getClass ("MySubSubClass")); + + if ([(MySubSubClass *)o test] != o) + abort (); + } + + std::cout << "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 (); + } + + std::cout << "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/obj-c++.dg/gnu-api-2-property.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm new file mode 100644 index 000000000..953e9bb15 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm @@ -0,0 +1,101 @@ +/* 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 <iostream> +#include <cstring> + +@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 () +{ + /* Functions are tested in alphabetical order. */ + + std::cout << "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 (std::strcmp (property_getAttributes (property), + "T@,GgetP,SsetP:,VpropertyA") != 0) + abort (); + + property = class_getProperty (objc_getClass ("MySubClass"), "propertyB"); + if (std::strcmp (property_getAttributes (property), + "T@,N,VpropertyB") != 0) + abort (); + } +#endif + } + + std::cout << "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 (std::strcmp (property_getName (property), "propertyA") != 0) + abort (); + + property = class_getProperty (objc_getClass ("MySubClass"), "propertyB"); + if (std::strcmp (property_getName (property), "propertyB") != 0) + abort (); + } +#endif + } + + return (0); +} diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm new file mode 100644 index 000000000..9a2ceca13 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm @@ -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 <iostream> +#include <cstring> + +@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 () +{ + /* Functions are tested in alphabetical order. */ + + std::cout << "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 (); + } + + std::cout << "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 (std::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). */ + std::cout << "Testing protocol_copyPropertyList ()...\n"; + { + unsigned int count; + objc_property_t *list; + + list = protocol_copyPropertyList (@protocol (MyProtocol), &count); + + if (count != 0 || list != NULL) + abort (); + } + + std::cout << "Testing protocol_copyProtocolList ()...\n"; + { + unsigned int count; + Protocol **list; + + list = protocol_copyProtocolList (@protocol (MyThirdProtocol), &count); + + if (count != 1) + abort (); + + if (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") != 0) + abort (); + + if (list[1] != NULL) + abort (); + } + + std::cout << "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 (std::strcmp (sel_getName (description.name), "setVariable:") != 0) + abort (); + } + + std::cout << "Testing protocol_getName ()...\n"; + { + if (std::strcmp (protocol_getName (@protocol (MyProtocol)), "MyProtocol") != 0) + abort (); + } + + /* TODO: Test new ABI (when available). */ + std::cout << "Testing protocol_getProperty ()...\n"; + { + objc_property_t property; + + property = protocol_getProperty (objc_getProtocol ("MyProtocol"), "someProperty", + YES, YES); + + if (property != NULL) + abort (); + } + + std::cout << "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/obj-c++.dg/gnu-api-2-resolve-method.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-resolve-method.mm new file mode 100644 index 000000000..f8a54d392 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-resolve-method.mm @@ -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 <iostream> +#include <cstring> + +@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 () +{ + /* Functions are tested in alphabetical order. */ + + /* Install our test forwarding hook. */ + __objc_msg_forward2 = forward_everything_to_non_existing_method; + + std::cout << "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; + + std::cout << "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/obj-c++.dg/gnu-api-2-sel.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm new file mode 100644 index 000000000..ff5005856 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm @@ -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 <iostream> +#include <cstring> + +@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 () +{ + /* Functions are tested in alphabetical order. */ + +#ifdef __GNU_LIBOBJC__ + std::cout << "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 (std::strcmp (sel_getName (list[0]), sel_getName (@selector (method))) != 0) + abort (); + + if (std::strcmp (sel_getName (list[1]), sel_getName (@selector (method))) != 0) + abort (); + + if (list[2] != NULL) + abort (); + } +#endif + + std::cout << "Testing sel_getName () ...\n"; + { + if (std::strcmp (sel_getName (@selector (variable)), "variable") != 0) + abort (); + + if (std::strcmp (sel_getName (NULL), "<null selector>") != 0) + abort (); + } + +#ifdef __GNU_LIBOBJC__ + std::cout << "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 (std::strcmp (sel_getTypeEncoding (method_getName (method)), + method_getTypeEncoding (method)) != 0) + abort (); + + if (sel_getTypeEncoding (NULL) != NULL) + abort (); + } +#endif + +#ifdef __GNU_LIBOBJC__ + std::cout << "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 + + std::cout << "Testing sel_getUid () ...\n"; + { + if (std::strcmp (sel_getName (sel_getUid ("myMethod")), "myMethod") != 0) + abort (); + + if (sel_getUid (NULL) != NULL) + abort (); + } + + std::cout << "Testing sel_isEqual () ...\n"; + { + if (! sel_isEqual (@selector (setVariable:), @selector (setVariable:))) + abort (); + } + + std::cout << "Testing sel_registerName () ...\n"; + { + if (std::strcmp (sel_getName (sel_registerName ("myMethod")), "myMethod") != 0) + abort (); + + if (sel_registerName (NULL) != NULL) + abort (); + } + +#ifdef __GNU_LIBOBJC__ + std::cout << "Testing set_registerTypedName () ...\n"; + { + const char *types = method_getTypeEncoding (class_getInstanceMethod + (objc_getClass ("MySubClass"), + @selector (variable))); + SEL selector = sel_registerTypedName ("aMethod", types); + + if (std::strcmp (sel_getName (selector), "aMethod") != 0) + abort (); + + if (std::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/obj-c++.dg/gnu-runtime-1.mm b/gcc/testsuite/obj-c++.dg/gnu-runtime-1.mm new file mode 100644 index 000000000..c7e3bcc3a --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-runtime-1.mm @@ -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/obj-c++.dg/gnu-runtime-2.mm b/gcc/testsuite/obj-c++.dg/gnu-runtime-2.mm new file mode 100644 index 000000000..dd5333889 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-runtime-2.mm @@ -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, const char **args) +{ + if (strcmp ([@"this is a string" cString], "this is a string")) + abort (); + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/gnu-runtime-3.mm b/gcc/testsuite/obj-c++.dg/gnu-runtime-3.mm new file mode 100644 index 000000000..429fce3e8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/gnu-runtime-3.mm @@ -0,0 +1,30 @@ +/* Test that compiling for the GNU runtime works (regardless of + the system runtime used). */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do run } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ + +#include <objc/Object.h> +#include <stdlib.h> + +@interface FooBar: Object +- (void)boo; +@end + +int called = 0; + +@implementation FooBar +- (void)boo +{ + called ++; +} +@end + +int main () +{ + id fooBarInst = [[FooBar alloc] init]; + [fooBarInst boo]; + if (called != 1) + abort (); + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/invalid-method-2.mm b/gcc/testsuite/obj-c++.dg/invalid-method-2.mm new file mode 100644 index 000000000..48f03599c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/invalid-method-2.mm @@ -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 "expected" } */ +{ + return 0; +} +- (id) method2: (x)argument /* { dg-error "expected" } */ +{ + return 0; +} +@end diff --git a/gcc/testsuite/obj-c++.dg/invalid-type-1.mm b/gcc/testsuite/obj-c++.dg/invalid-type-1.mm new file mode 100644 index 000000000..ace144f0b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/invalid-type-1.mm @@ -0,0 +1,25 @@ +/* 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 ".Integer {aka int}. is not a template" } */ +/* { dg-error ".MyProtocol. was not declared in this scope" "" { target *-*-* } 21 } */ + +Integer <NonExistingProtocol> *object3; /* { dg-error ".Integer {aka int}. is not a template" } */ +/* { dg-error ".NonExistingProtocol. was not declared in this scope" "" { target *-*-* } 24 } */ diff --git a/gcc/testsuite/obj-c++.dg/isa-field-1.mm b/gcc/testsuite/obj-c++.dg/isa-field-1.mm new file mode 100644 index 000000000..4b93df8c4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/isa-field-1.mm @@ -0,0 +1,47 @@ +/* Ensure there are no bizarre difficulties with accessing the 'isa' field of + objects. This field is named differently between GNU and NeXT runtimes so + accessed via the CLASSPTRFIELD() macro defined in next-mapping.h */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include "../objc-obj-c++-shared/next-mapping.h" + +@interface Object (Test) +- (Class) test1: (id)object; +@end + +@interface Derived: Object +- (Class) test2: (id)object; +@end + +@implementation Object (Test) + +Class test1(id object) { + Class cls = CLASSPTRFIELD(object); + return cls; +} +- (Class) test1: (id)object { + Class cls = CLASSPTRFIELD(object); + return cls; +} + +@end + +@implementation Derived + +Class test2(id object) { + Class cls = CLASSPTRFIELD(object); + return cls; +} +- (Class) test2: (id)object { + Class cls = CLASSPTRFIELD(object); + return cls; +} + +@end + +Class test3(id object) { + Class cls = CLASSPTRFIELD(object); + return cls; +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm b/gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm new file mode 100644 index 000000000..4c1480a6b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm @@ -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 "invalid type" } */ + static int c; /* { dg-error "invalid type" } */ + inline int d; /* { dg-error "declared as an .inline." } */ + typedef int e; /* { dg-error "invalid type" } */ + __thread int f; /* { dg-error "invalid type" } */ +} +@end diff --git a/gcc/testsuite/obj-c++.dg/ivar-list-semi.mm b/gcc/testsuite/obj-c++.dg/ivar-list-semi.mm new file mode 100644 index 000000000..322de2fd4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/ivar-list-semi.mm @@ -0,0 +1,12 @@ +/* Allow for an optional semicolon following the ivar block. */ +/* Contributed by: Ziemowit Laski <zlaski@apple.com>. */ + +#include "../objc-obj-c++-shared/Object1.h" + +@interface Tink : Object { +@private + unsigned long mCode[4]; +}; +- (id)initWithProc:(void *)inProc; +- (void *)getUniqueProc; +@end diff --git a/gcc/testsuite/obj-c++.dg/ivar-problem-1.mm b/gcc/testsuite/obj-c++.dg/ivar-problem-1.mm new file mode 100644 index 000000000..4ed5afaf4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/ivar-problem-1.mm @@ -0,0 +1,66 @@ +/* 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. This only happened for ObjC, but it's good to + test ObjC++ as well. */ + +#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/obj-c++.dg/keywords-1.mm b/gcc/testsuite/obj-c++.dg/keywords-1.mm new file mode 100644 index 000000000..abb4537ae --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/keywords-1.mm @@ -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/obj-c++.dg/keywords-2.mm b/gcc/testsuite/obj-c++.dg/keywords-2.mm new file mode 100644 index 000000000..c81cb4d0c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/keywords-2.mm @@ -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/obj-c++.dg/layout-1.mm b/gcc/testsuite/obj-c++.dg/layout-1.mm new file mode 100644 index 000000000..3cd4d1567 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/layout-1.mm @@ -0,0 +1,17 @@ +/* Ensure that we do not get bizarre warnings referring to + __attribute__((packed)) or some such. */ +/* { dg-do compile } */ +/* { dg-options "-Wpadded -Wpacked -Wabi" } */ + +#include "../objc-obj-c++-shared/Object1.h" + +@interface Derived1: Object +{ } +@end + +@interface Derived2: Object +- (id) foo; +@end + +/* { dg-prune-output "In output included from" } Ignore this message. */ +/* { dg-bogus "padding struct to align" "PR23610" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/obj-c++.dg/local-decl-1.mm b/gcc/testsuite/obj-c++.dg/local-decl-1.mm new file mode 100644 index 000000000..684857287 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/local-decl-1.mm @@ -0,0 +1,44 @@ +/* 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/obj-c++.dg/lookup-1.mm b/gcc/testsuite/obj-c++.dg/lookup-1.mm new file mode 100644 index 000000000..e149e5c61 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/lookup-1.mm @@ -0,0 +1,8 @@ +/* Simple test to check Objectivec-C++ qualified type lookup. */ +/* Devang Patel <dpatel@apple.com>. */ + +@interface A +{ + A *ap; +} +@end diff --git a/gcc/testsuite/obj-c++.dg/lookup-2.mm b/gcc/testsuite/obj-c++.dg/lookup-2.mm new file mode 100644 index 000000000..5eaf38996 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/lookup-2.mm @@ -0,0 +1,58 @@ +/* { 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> + +class MyWidget { + public: + int a; + MyWidget(void) { a = 17; } +}; + +MyWidget gWidget; + +@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 = 0; + 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; +} + +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/lto/lto.exp b/gcc/testsuite/obj-c++.dg/lto/lto.exp new file mode 100644 index 000000000..4ae08c172 --- /dev/null +++ b/gcc/testsuite/obj-c++.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 obj-c++-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} \ +] + +obj-c++_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 "obj_cpp_lto" +set tests [lsort [glob -nocomplain $srcdir/$subdir/*_0.mm]] + +# 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/obj-c++.dg/lto/trivial-1_0.mm b/gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm new file mode 100644 index 000000000..45b6e7024 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm @@ -0,0 +1,43 @@ +/* { dg-lto-do run } */ +/* { dg-skip-if "Needs OBJC2 ABI" { "*-*-darwin*" && lp64 } { "*" } { "" } } */ +extern "C" { +extern int printf (char *,...) ; +extern void abort (void) ; +} + +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) +{ + Class cl = [myRootObject class]; + if (cl != (Class)0) { + printf((char *)"trivial OK\n"); + return 0; + } + abort () ; +} diff --git a/gcc/testsuite/obj-c++.dg/method-1.mm b/gcc/testsuite/obj-c++.dg/method-1.mm new file mode 100644 index 000000000..fdab6b7a9 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-1.mm @@ -0,0 +1,30 @@ +/* Test whether casting 'id' to a specific class removes method lookup + ambiguity. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do compile } */ + +#include <objc/objc.h> + +@class Int1, Int2; + +@interface Int1 ++ (Int1 *)classMethod1; ++ (id)classMethod2; +- (Int1 *)instanceMethod:(Int2 *)arg; /* { dg-bogus "using" } */ +@end + +@interface Int2: Int1 ++ (Int1 *)classMethod1; ++ (id)classMethod2; +- (id)int2Method; +- (int)instanceMethod:(int)arg; /* { dg-bogus "also found" } */ +@end + +int main(void) { + id i = [(Int2 *)[Int1 classMethod1] int2Method]; /* { dg-bogus "may not respond to" } */ + int j = [(Int2 *)[Int2 classMethod2] instanceMethod: 45]; /* { dg-bogus "multiple methods" } */ + /* { dg-bogus "invalid conversion" "" { target *-*-* } 25 } */ + /* { dg-bogus "invalid conversion" "" { target *-*-* } 25 } */ + return j; +} diff --git a/gcc/testsuite/obj-c++.dg/method-10.mm b/gcc/testsuite/obj-c++.dg/method-10.mm new file mode 100644 index 000000000..cac5d9791 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-10.mm @@ -0,0 +1,46 @@ +/* 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" +#include <stdlib.h> + +#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/obj-c++.dg/method-11.mm b/gcc/testsuite/obj-c++.dg/method-11.mm new file mode 100644 index 000000000..74192e80f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-11.mm @@ -0,0 +1,29 @@ +/* Check if class references (generated for the NeXT runtime) are appropriately + folded. This test is safe to run on all targets. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-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" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler "_OBJC_ClassRef_Object" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler-not "_OBJC_ClassRefs_1" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler-not "_OBJC_ClassRef_ObjectTypedef" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler-not "_OBJC_ClassRef_ObjectAlias" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/obj-c++.dg/method-12.mm b/gcc/testsuite/obj-c++.dg/method-12.mm new file mode 100644 index 000000000..7c6916b32 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-12.mm @@ -0,0 +1,31 @@ +/* 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-options "-Wstrict-selector-match" } */ +/* { dg-do compile } */ + +#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 *-*-* } 9 } */ + /* { dg-message "also found .\\+\\(Protocol \\*\\)port." "" { target *-*-* } 14 } */ + + [receiver starboard]; /* { dg-warning "no .\\+starboard. method found" } */ + /* { 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 } */ + + [Class port]; /* { dg-error ".Class. is not an Objective\\-C class name or alias" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/method-13.mm b/gcc/testsuite/obj-c++.dg/method-13.mm new file mode 100644 index 000000000..6938f7d34 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-13.mm @@ -0,0 +1,27 @@ +/* Check if finding multiple signatures for a method is handled gracefully. Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-options "-Wstrict-selector-match" } */ +/* { dg-do compile } */ + +#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 *-*-* } 18 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 18 } */ + /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 18 } */ + [obj2 setWindow:nil]; /* { dg-warning "multiple methods named .\\-setWindow:. found" } */ + /* { dg-message "using .\\-\\(void\\)setWindow:\\(Object \\*\\)wdw." "" { target *-*-* } 8 } */ + /* { dg-message "also found .\\-\\(void\\)setWindow:\\(Class1 \\*\\)window." "" { target *-*-* } 12 } */ + + return obj; +} diff --git a/gcc/testsuite/obj-c++.dg/method-14.mm b/gcc/testsuite/obj-c++.dg/method-14.mm new file mode 100644 index 000000000..4a13b7d6c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-14.mm @@ -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/obj-c++.dg/method-15.mm b/gcc/testsuite/obj-c++.dg/method-15.mm new file mode 100644 index 000000000..860aad63e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-15.mm @@ -0,0 +1,43 @@ +/* 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-options "-Wstrict-selector-match" } */ +/* { dg-do compile } */ + +#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 *-*-* } 33 } */ + /* { dg-message "using .\\-\\(id\\)initWithData:\\(Object \\*\\)data." "" { target *-*-* } 9 } */ + /* { dg-message "also found .\\-\\(id\\)initWithData:\\(id <MyObject, MyCoding>\\)data." "" { target *-*-* } 17 } */ + /* { dg-message "also found .\\-\\(id\\)initWithData:\\(int\\)data." "" { target *-*-* } 13 } */ + + /* 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 *-*-* } 33 } */ + return result; +} +@end diff --git a/gcc/testsuite/obj-c++.dg/method-16.mm b/gcc/testsuite/obj-c++.dg/method-16.mm new file mode 100644 index 000000000..aceefcdc7 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-16.mm @@ -0,0 +1,34 @@ + +/* 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 *-*-* } 26 } */ + /* { dg-message "using .\\-\\(void\\)initWithData:\\(Object1 \\*\\)data." "" { target *-*-* } 13 } */ + /* { dg-message "also found .\\-\\(id\\)initWithData:\\(Object1 \\*\\)data." "" { target *-*-* } 17 } */ + /* { dg-message "also found .\\-\\(id\\)initWithData:\\(Object2 \\*\\)data." "" { target *-*-* } 21 } */ + + /* The following error is a consequence of picking the "wrong" method signature. */ + /* { dg-error "void value not ignored as it ought to be" "" { target *-*-* } 26 } */ +} diff --git a/gcc/testsuite/obj-c++.dg/method-17.mm b/gcc/testsuite/obj-c++.dg/method-17.mm new file mode 100644 index 000000000..cb60473b3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-17.mm @@ -0,0 +1,33 @@ +/* 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" +#include <stdlib.h> + +#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: (int)d floatingPoint: d]; + return 0; +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/method-18.mm b/gcc/testsuite/obj-c++.dg/method-18.mm new file mode 100644 index 000000000..411caac11 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-18.mm @@ -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/obj-c++.dg/method-19.mm b/gcc/testsuite/obj-c++.dg/method-19.mm new file mode 100644 index 000000000..5dca80494 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-19.mm @@ -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-obj-c++-shared/next-mapping.h" +#include <objc/objc.h> + +#ifndef __NEXT_RUNTIME__ +#include <objc/objc-api.h> +#endif + +#include <stdlib.h> +#include <string.h> + +#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_get_class("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; +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/method-2.mm b/gcc/testsuite/obj-c++.dg/method-2.mm new file mode 100644 index 000000000..117d420e1 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-2.mm @@ -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/obj-c++.dg/method-20.mm b/gcc/testsuite/obj-c++.dg/method-20.mm new file mode 100644 index 000000000..96982254a --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-20.mm @@ -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/obj-c++.dg/method-21.mm b/gcc/testsuite/obj-c++.dg/method-21.mm new file mode 100644 index 000000000..898768d6d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-21.mm @@ -0,0 +1,25 @@ +/* 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-error "return.statement with no value" } */ +} +- (void) meth2 { + if (!bar) + return; + bar = 0; +} +@end diff --git a/gcc/testsuite/obj-c++.dg/method-22.mm b/gcc/testsuite/obj-c++.dg/method-22.mm new file mode 100644 index 000000000..610c178e9 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-22.mm @@ -0,0 +1,44 @@ +/* Ensure that overload resolution does not produce warnings as + side-effects. */ +/* { dg-do run } */ +/* { dg-additional-sources "../objc-obj-c++-shared/Object1.mm" } */ +/* { 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(E) if(!(E)) abort () + +@interface MyCursor: Object ++ (MyCursor *)crosshairCursor; +@end + +@class MyImage; + +class A { +public: + A(); + + int foo(MyImage *); + int foo(MyCursor *); +}; + +A::A() {} +int A::foo(MyCursor * c) { return 17; } +int A::foo(MyImage * i) { return 29; } + +@implementation MyCursor ++ (MyCursor *)crosshairCursor { + return self; +} +@end + +int main(void) { + A a; + + int r = a.foo([MyCursor crosshairCursor]); + + CHECK_IF (r == 17); + return 0; +} + diff --git a/gcc/testsuite/obj-c++.dg/method-23.mm b/gcc/testsuite/obj-c++.dg/method-23.mm new file mode 100644 index 000000000..2b59cb8fc --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-23.mm @@ -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.mm" } */ +/* { 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/obj-c++.dg/method-3.mm b/gcc/testsuite/obj-c++.dg/method-3.mm new file mode 100644 index 000000000..9dab8c5b3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-3.mm @@ -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/obj-c++.dg/method-4.mm b/gcc/testsuite/obj-c++.dg/method-4.mm new file mode 100644 index 000000000..e94f8f1b7 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-4.mm @@ -0,0 +1,24 @@ +/* Warn about "slightly" mismatched method signatures if + -Wstrict-selector-match is on. */ + +/* { dg-do compile } */ +/* { dg-options "-Wstrict-selector-match" } */ + +#include <objc/objc.h> + +@interface Base +- (id) meth1: (Base *)arg1; /* { dg-message "using .\\-\\(id\\)meth1:\\(Base \\*\\)arg1." } */ +- (id) window; /* { dg-message "using .\\-\\(id\\)window" } */ +@end + +@interface Derived: Base +- (id) meth1: (Derived *)arg1; /* { dg-message "also found .\\-\\(id\\)meth1:\\(Derived \\*\\)arg1." } */ +- (Base *) window; /* { dg-message "also found .\\-\\(Base \\*\\)window." } */ +@end + +void foo(void) { + id r; + + [r meth1:r]; /* { dg-warning "multiple methods named .\\-meth1:. found" } */ + [r window]; /* { dg-warning "multiple methods named .\\-window. found" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/method-5.mm b/gcc/testsuite/obj-c++.dg/method-5.mm new file mode 100644 index 000000000..17c841a46 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-5.mm @@ -0,0 +1,30 @@ +/* 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/obj-c++.dg/method-6.mm b/gcc/testsuite/obj-c++.dg/method-6.mm new file mode 100644 index 000000000..6c21e7995 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-6.mm @@ -0,0 +1,19 @@ +/* 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/obj-c++.dg/method-7.mm b/gcc/testsuite/obj-c++.dg/method-7.mm new file mode 100644 index 000000000..e9e2d3a43 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-7.mm @@ -0,0 +1,21 @@ +/* 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 *-*-* } 12 } */ + [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/obj-c++.dg/method-8.mm b/gcc/testsuite/obj-c++.dg/method-8.mm new file mode 100644 index 000000000..9857c63ff --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-8.mm @@ -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-error "previously defined here" } */ +- (int) meth1 { return 0; } /* { dg-error "redefinition of" } */ +@end + +@interface class4 ++ (void) meth1; +@end + +@implementation class4 ++ (void) meth1 {} /* { dg-error "previously defined here" } */ ++ (void) meth1 {} /* { dg-error "redefinition of" } */ +@end diff --git a/gcc/testsuite/obj-c++.dg/method-9.mm b/gcc/testsuite/obj-c++.dg/method-9.mm new file mode 100644 index 000000000..4509c4aa4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-9.mm @@ -0,0 +1,33 @@ +/* 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." } */ + [MyDerived instanceMethod]; /* { dg-warning ".MyDerived. may not respond to .\\+instanceMethod." } */ +} +@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/obj-c++.dg/method-conflict-1.mm b/gcc/testsuite/obj-c++.dg/method-conflict-1.mm new file mode 100644 index 000000000..2cc96e4fd --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-conflict-1.mm @@ -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/obj-c++.dg/method-conflict-2.mm b/gcc/testsuite/obj-c++.dg/method-conflict-2.mm new file mode 100644 index 000000000..0b0612d77 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-conflict-2.mm @@ -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/obj-c++.dg/method-conflict-3.mm b/gcc/testsuite/obj-c++.dg/method-conflict-3.mm new file mode 100644 index 000000000..73e80c948 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-conflict-3.mm @@ -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/obj-c++.dg/method-conflict-4.mm b/gcc/testsuite/obj-c++.dg/method-conflict-4.mm new file mode 100644 index 000000000..e2aca6cc5 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-conflict-4.mm @@ -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/obj-c++.dg/method-namespace-1.mm b/gcc/testsuite/obj-c++.dg/method-namespace-1.mm new file mode 100644 index 000000000..6095f572c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-namespace-1.mm @@ -0,0 +1,29 @@ +/* Test for usage of namespace inside @implementation. */ +/* { dg-do compile } */ +@interface MyDocument +@end + +@implementation MyDocument + +// This deprecated usage works +static void foo1() { } + +// This preferred usage does _not_ work +namespace + { + void foo2() { } + } + +namespace STD + { + void foo3 () {} + } + +using namespace STD; + +- (void) GARF { + foo2(); + foo3(); +} + +@end diff --git a/gcc/testsuite/obj-c++.dg/method-namespace-2.mm b/gcc/testsuite/obj-c++.dg/method-namespace-2.mm new file mode 100644 index 000000000..3e1c9d123 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-namespace-2.mm @@ -0,0 +1,25 @@ +/* Test that qualified type is resolved to its proper type. */ +/* { dg-do compile } */ + +@interface Object +{ + int I[100]; +} +@end + +namespace HC +{ + +struct Object +{ + void test(); +}; + +} // namespace HC + +int main() +{ + HC::Object* object; + object->test(); // Must compile with no error + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/msg-in-protocol.mm b/gcc/testsuite/obj-c++.dg/msg-in-protocol.mm new file mode 100644 index 000000000..86b7c85a3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/msg-in-protocol.mm @@ -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/obj-c++.dg/naming-1.mm b/gcc/testsuite/obj-c++.dg/naming-1.mm new file mode 100644 index 000000000..aed2fd517 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/naming-1.mm @@ -0,0 +1,26 @@ +/* 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" } */ +} +@end + +@interface C : A +@end + +@interface D : C +{ + NSDictionary * _userInfo; /* { dg-error "duplicate member" } */ +} +@end + diff --git a/gcc/testsuite/obj-c++.dg/naming-2.mm b/gcc/testsuite/obj-c++.dg/naming-2.mm new file mode 100644 index 000000000..4b7860e10 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/naming-2.mm @@ -0,0 +1,40 @@ +/* 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; +} +@end + +@interface C : A +@end + +@interface D : C +{ + NSDictionary * _userInfo; /* { dg-error "duplicate member" } */ +} +@end + diff --git a/gcc/testsuite/obj-c++.dg/no-extra-load.mm b/gcc/testsuite/obj-c++.dg/no-extra-load.mm new file mode 100644 index 000000000..1663ebc21 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/no-extra-load.mm @@ -0,0 +1,24 @@ +// Radar 3926484 + +// { dg-do compile } + +#include "../objc-obj-c++-shared/Object1.h" +#include <iostream> + +@interface Greeter : Object +- (void) greet: (const char *)msg; +@end + +@implementation Greeter +- (void) greet: (const char *)msg { std::cout << msg; } +@end + +int +main () +{ + std::cout << "Hello from C++\n"; + Greeter *obj = [Greeter new]; + [obj greet: "Hello from Objective-C\n"]; +} + +/* { dg-final { scan-assembler-not "L_objc_msgSend\\\$non_lazy_ptr" } } */ diff --git a/gcc/testsuite/obj-c++.dg/objc-gc-3.mm b/gcc/testsuite/obj-c++.dg/objc-gc-3.mm new file mode 100644 index 000000000..c0249e7a9 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/objc-gc-3.mm @@ -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 "cc1objplus: 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/obj-c++.dg/overload-1.mm b/gcc/testsuite/obj-c++.dg/overload-1.mm new file mode 100644 index 000000000..d4999897d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/overload-1.mm @@ -0,0 +1,11 @@ +// Make sure we can overload on ObjC classes +// Radar 3960754 + +// { dg-do compile } + +@class A, B; + +struct X { + void call(A*); + void call(B*); +}; diff --git a/gcc/testsuite/obj-c++.dg/pr23709.mm b/gcc/testsuite/obj-c++.dg/pr23709.mm new file mode 100644 index 000000000..018b53ac4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/pr23709.mm @@ -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/obj-c++.dg/pr24393.mm b/gcc/testsuite/obj-c++.dg/pr24393.mm new file mode 100644 index 000000000..269d84d9c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/pr24393.mm @@ -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/obj-c++.dg/pr28049.mm b/gcc/testsuite/obj-c++.dg/pr28049.mm new file mode 100644 index 000000000..d5ba4a10b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/pr28049.mm @@ -0,0 +1,2 @@ +/* { dg-do compile } */ ++ /* { dg-error "expected" } */ diff --git a/gcc/testsuite/obj-c++.dg/pr45735.mm b/gcc/testsuite/obj-c++.dg/pr45735.mm new file mode 100644 index 000000000..395698bdb --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/pr45735.mm @@ -0,0 +1,4 @@ +/* { dg-do compile } */ +@interface Fraction +-(void) setNumerator: (int) :(int) ; /* { dg-error "expected identifier" } */ +@end diff --git a/gcc/testsuite/obj-c++.dg/pragma-1.mm b/gcc/testsuite/obj-c++.dg/pragma-1.mm new file mode 100644 index 000000000..3d3539ed3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/pragma-1.mm @@ -0,0 +1,11 @@ +/* It is OK to use #pragma inside @interface body. This test checks that. */ +/* Devang Patel <dpatel@apple.com>. */ + +@interface A +{ + int p; +} ++(int) foo; +#pragma Mark foobar +-(int) bar; +@end diff --git a/gcc/testsuite/obj-c++.dg/pragma-2.mm b/gcc/testsuite/obj-c++.dg/pragma-2.mm new file mode 100644 index 000000000..14c4d7928 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/pragma-2.mm @@ -0,0 +1,23 @@ +/* It is OK to use #pragma inside @implementation body. This test checks that. */ +/* Ziemowit Laski <zlaski@apple.com>. */ + +@interface A +{ + int p; +} ++(int) foo; +-(int) bar; +@end + +@implementation A +#pragma mark - +#pragma mark init / dealloc ++ (int)foo { + return 1; +} +#pragma mark - +#pragma mark Private Functions +- (int)bar { + return 2; +} +@end diff --git a/gcc/testsuite/obj-c++.dg/private-1.mm b/gcc/testsuite/obj-c++.dg/private-1.mm new file mode 100644 index 000000000..0c25aea55 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/private-1.mm @@ -0,0 +1,58 @@ +/* Test errors for accessing @private and @protected variables. */ +/* Based on work by: 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 \\'_private\\' is declared private" } */ + + _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/obj-c++.dg/private-2.mm b/gcc/testsuite/obj-c++.dg/private-2.mm new file mode 100644 index 000000000..3e6ff118d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/private-2.mm @@ -0,0 +1,56 @@ +/* Test warnings for shadowing instance variables. */ +/* Based on work by: 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/obj-c++.dg/property/at-property-1.mm b/gcc/testsuite/obj-c++.dg/property/at-property-1.mm new file mode 100644 index 000000000..1b945bd44 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-1.mm @@ -0,0 +1,20 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +@property; /* { dg-error "expected identifier" } */ +@property int; /* { dg-error "expected identifier" } */ +@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 "expected identifier" } */ + /* { dg-error "expected ... " "" { target *-*-* } 18 } */ +@end diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-10.mm b/gcc/testsuite/obj-c++.dg/property/at-property-10.mm new file mode 100644 index 000000000..010c41bd3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-10.mm @@ -0,0 +1,97 @@ +/* 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; +} +@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/obj-c++.dg/property/at-property-11.mm b/gcc/testsuite/obj-c++.dg/property/at-property-11.mm new file mode 100644 index 000000000..51c402346 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-11.mm @@ -0,0 +1,44 @@ +/* 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; +} +@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/obj-c++.dg/property/at-property-12.mm b/gcc/testsuite/obj-c++.dg/property/at-property-12.mm new file mode 100644 index 000000000..89001e73b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-12.mm @@ -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/obj-c++.dg/property/at-property-13.mm b/gcc/testsuite/obj-c++.dg/property/at-property-13.mm new file mode 100644 index 000000000..6786c3aa8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-13.mm @@ -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/obj-c++.dg/property/at-property-14.mm b/gcc/testsuite/obj-c++.dg/property/at-property-14.mm new file mode 100644 index 000000000..a9068ba89 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-14.mm @@ -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/obj-c++.dg/property/at-property-15.mm b/gcc/testsuite/obj-c++.dg/property/at-property-15.mm new file mode 100644 index 000000000..ef5344246 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-15.mm @@ -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/obj-c++.dg/property/at-property-16.mm b/gcc/testsuite/obj-c++.dg/property/at-property-16.mm new file mode 100644 index 000000000..6a9856b90 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-16.mm @@ -0,0 +1,46 @@ +/* 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; /* { dg-message "originally specified here" } */ +@property (retain) id b; /* { dg-message "originally specified here" } */ +@property int c; /* { dg-message "originally specified here" } */ +@property (nonatomic) int d; /* { dg-message "originally specified here" } */ +@property int e; /* { dg-message "originally specified here" } */ +@property int f; /* { dg-message "originally specified here" } */ +@property int g; /* { dg-message "originally specified here" } */ +@property (readonly) int h; /* Ok */ +@property (readonly,getter=getMe) int i; /* { dg-message "originally specified here" } */ +@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" } */ +@property (assign) id b; /* { dg-warning "assign semantics attributes of property .b. conflict with previous declaration" } */ +@property (nonatomic) int c; /* { dg-warning ".nonatomic. attribute of property .c. conflicts with previous declaration" } */ +@property int d; /* { dg-warning ".nonatomic. attribute of property .d. conflicts with previous declaration" } */ +@property (setter=setX:) int e; /* { dg-warning ".setter. attribute of property .e. conflicts with previous declaration" } */ +@property (getter=x) int f; /* { dg-warning ".getter. attribute of property .f. conflicts with previous declaration" } */ +@property (readonly) int g; /* { dg-warning ".readonly. attribute of property .g. conflicts with previous declaration" } */ +@property (readwrite) int h; /* Ok */ +@property (readonly) int i; /* { dg-warning ".getter. attribute of property .i. conflicts with previous declaration" } */ +@end diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-17.mm b/gcc/testsuite/obj-c++.dg/property/at-property-17.mm new file mode 100644 index 000000000..efb62d6f7 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-17.mm @@ -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/obj-c++.dg/property/at-property-18.mm b/gcc/testsuite/obj-c++.dg/property/at-property-18.mm new file mode 100644 index 000000000..d31821098 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-18.mm @@ -0,0 +1,46 @@ +/* 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/obj-c++.dg/property/at-property-19.mm b/gcc/testsuite/obj-c++.dg/property/at-property-19.mm new file mode 100644 index 000000000..be898e218 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-19.mm @@ -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/obj-c++.dg/property/at-property-2.mm b/gcc/testsuite/obj-c++.dg/property/at-property-2.mm new file mode 100644 index 000000000..d8433dffc --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-2.mm @@ -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 "declaration of function .function. in invalid context" } */ +@property typedef int j; /* { dg-error "invalid type for property" } */ +@end diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-20.mm b/gcc/testsuite/obj-c++.dg/property/at-property-20.mm new file mode 100644 index 000000000..85f5aecd1 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-20.mm @@ -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/obj-c++.dg/property/at-property-21.mm b/gcc/testsuite/obj-c++.dg/property/at-property-21.mm new file mode 100644 index 000000000..d1f54b1cd --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-21.mm @@ -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/obj-c++.dg/property/at-property-22.mm b/gcc/testsuite/obj-c++.dg/property/at-property-22.mm new file mode 100644 index 000000000..03b3d0bb4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-22.mm @@ -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/obj-c++.dg/property/at-property-23.mm b/gcc/testsuite/obj-c++.dg/property/at-property-23.mm new file mode 100644 index 000000000..73138f64c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-23.mm @@ -0,0 +1,18 @@ +/* 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 "expected" } */ +@property int c[]; /* { dg-error "property can not be an array" } */ + /* { dg-error "ISO C.. forbids zero-size array" "" { target *-*-* } 16 } */ +@end diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-24.mm b/gcc/testsuite/obj-c++.dg/property/at-property-24.mm new file mode 100644 index 000000000..b4a7699f6 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-24.mm @@ -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/obj-c++.dg/property/at-property-25.mm b/gcc/testsuite/obj-c++.dg/property/at-property-25.mm new file mode 100644 index 000000000..422a29e55 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-25.mm @@ -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/obj-c++.dg/property/at-property-26.mm b/gcc/testsuite/obj-c++.dg/property/at-property-26.mm new file mode 100644 index 000000000..c45757e23 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-26.mm @@ -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/obj-c++.dg/property/at-property-27.mm b/gcc/testsuite/obj-c++.dg/property/at-property-27.mm new file mode 100644 index 000000000..727834684 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-27.mm @@ -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/obj-c++.dg/property/at-property-28.mm b/gcc/testsuite/obj-c++.dg/property/at-property-28.mm new file mode 100644 index 000000000..de5122443 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-28.mm @@ -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/obj-c++.dg/property/at-property-29.mm b/gcc/testsuite/obj-c++.dg/property/at-property-29.mm new file mode 100644 index 000000000..0f31617f8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-29.mm @@ -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/obj-c++.dg/property/at-property-3.mm b/gcc/testsuite/obj-c++.dg/property/at-property-3.mm new file mode 100644 index 000000000..adf4dd036 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-3.mm @@ -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 "invalid type" } */ +@property static int c; /* { dg-error "invalid type" } */ +@property inline int d; /* { dg-error "declared as an .inline." } */ +@property typedef int e; /* { dg-error "invalid type" } */ +@property __thread int f; /* { dg-error "invalid type" } */ +@end diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-4.mm b/gcc/testsuite/obj-c++.dg/property/at-property-4.mm new file mode 100644 index 000000000..941aab8e3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-4.mm @@ -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/obj-c++.dg/property/at-property-5.mm b/gcc/testsuite/obj-c++.dg/property/at-property-5.mm new file mode 100644 index 000000000..fc618f2bc --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-5.mm @@ -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 "misplaced .@property. Objective-C.. construct" } */ diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-6.mm b/gcc/testsuite/obj-c++.dg/property/at-property-6.mm new file mode 100644 index 000000000..f2e2044cc --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-6.mm @@ -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/obj-c++.dg/property/at-property-7.mm b/gcc/testsuite/obj-c++.dg/property/at-property-7.mm new file mode 100644 index 000000000..dc8e90fc3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-7.mm @@ -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/obj-c++.dg/property/at-property-8.mm b/gcc/testsuite/obj-c++.dg/property/at-property-8.mm new file mode 100644 index 000000000..f40416567 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-8.mm @@ -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/obj-c++.dg/property/at-property-9.mm b/gcc/testsuite/obj-c++.dg/property/at-property-9.mm new file mode 100644 index 000000000..4b2b64d3f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-9.mm @@ -0,0 +1,50 @@ +/* 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; +} +@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/obj-c++.dg/property/at-property-deprecated-1.mm b/gcc/testsuite/obj-c++.dg/property/at-property-deprecated-1.mm new file mode 100644 index 000000000..2cf4dee5e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-deprecated-1.mm @@ -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/obj-c++.dg/property/at-property-deprecated-2.mm b/gcc/testsuite/obj-c++.dg/property/at-property-deprecated-2.mm new file mode 100644 index 000000000..d2901a55b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-deprecated-2.mm @@ -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/obj-c++.dg/property/cxx-property-1.mm b/gcc/testsuite/obj-c++.dg/property/cxx-property-1.mm new file mode 100644 index 000000000..3c6f93e2a --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/cxx-property-1.mm @@ -0,0 +1,10 @@ +/* Testcase from PR obj-c++/48275. */ +/* { dg-do compile } */ + +@interface Test +{ + int ns; +} +@property (getter=namespace) int ns; + +@end diff --git a/gcc/testsuite/obj-c++.dg/property/cxx-property-2.mm b/gcc/testsuite/obj-c++.dg/property/cxx-property-2.mm new file mode 100644 index 000000000..4e085b398 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/cxx-property-2.mm @@ -0,0 +1,22 @@ +/* { dg-do compile } */ + +/* All these C++ keywords are acceptable in ObjC method names, hence + should be accepted for property getters and setters. */ + +@interface Test +{ + Class isa; +} +@property (getter=namespace) int p0; +@property (setter=namespace:) int p1; +@property (getter=and) int p2; +@property (setter=and:) int p3; +@property (getter=class) int p4; +@property (setter=class:) int p5; +@property (getter=new) int p6; +@property (setter=new:) int p7; +@property (getter=delete) int p8; +@property (setter=delete:) int p9; +@property (getter=delete) int p10; +@property (setter=delete:) int p11; +@end diff --git a/gcc/testsuite/obj-c++.dg/property/dotsyntax-1.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-1.mm new file mode 100644 index 000000000..8922f5f03 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-1.mm @@ -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/obj-c++.dg/property/dotsyntax-10.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-10.mm new file mode 100644 index 000000000..433595f3d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-10.mm @@ -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/obj-c++.dg/property/dotsyntax-11.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-11.mm new file mode 100644 index 000000000..6c9d924ca --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-11.mm @@ -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/obj-c++.dg/property/dotsyntax-12.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-12.mm new file mode 100644 index 000000000..20882f909 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-12.mm @@ -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/obj-c++.dg/property/dotsyntax-13.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-13.mm new file mode 100644 index 000000000..c5a4b3301 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-13.mm @@ -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/obj-c++.dg/property/dotsyntax-14.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-14.mm new file mode 100644 index 000000000..efa60ed99 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-14.mm @@ -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" } */ + + return object.countC; /* { dg-error "request for member .countC. in" } */ +} + +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" } */ + + return object.countC; /* { dg-error "request for member .countC. in" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/property/dotsyntax-15.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-15.mm new file mode 100644 index 000000000..7ddf5300c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-15.mm @@ -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" } */ + + return object.countC; /* { dg-error "request for member .countC. in" } */ +} + +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" } */ + + return object.countC; /* { dg-error "request for member .countC. in" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm new file mode 100644 index 000000000..893db69d9 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm @@ -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/obj-c++.dg/property/dotsyntax-17.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm new file mode 100644 index 000000000..c28e11f48 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm @@ -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/obj-c++.dg/property/dotsyntax-18.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-18.mm new file mode 100644 index 000000000..5697d311d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-18.mm @@ -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/obj-c++.dg/property/dotsyntax-19.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-19.mm new file mode 100644 index 000000000..df4867b0a --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-19.mm @@ -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/obj-c++.dg/property/dotsyntax-2.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-2.mm new file mode 100644 index 000000000..03e49aebc --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-2.mm @@ -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/obj-c++.dg/property/dotsyntax-20.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-20.mm new file mode 100644 index 000000000..2bddb7c6b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-20.mm @@ -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; /* This warning does not seem to be produced in C++. 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/obj-c++.dg/property/dotsyntax-21.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-21.mm new file mode 100644 index 000000000..4b8945ed6 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-21.mm @@ -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/obj-c++.dg/property/dotsyntax-22.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-22.mm new file mode 100644 index 000000000..cc5834822 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-22.mm @@ -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/obj-c++.dg/property/dotsyntax-3.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-3.mm new file mode 100644 index 000000000..d34780628 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-3.mm @@ -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/obj-c++.dg/property/dotsyntax-4.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-4.mm new file mode 100644 index 000000000..2e918d282 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-4.mm @@ -0,0 +1,44 @@ +/* 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" } */ + /* { dg-error "expected" "" { target *-*-* } 37 } */ + if (MyRootClass.int) /* { dg-error "expected identifier" } */ + /* { dg-error "expected" "" { target *-*-* } 39 } */ + abort (); + + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/property/dotsyntax-5.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-5.mm new file mode 100644 index 000000000..06e113032 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-5.mm @@ -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/obj-c++.dg/property/dotsyntax-6.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-6.mm new file mode 100644 index 000000000..7ecd34e3d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-6.mm @@ -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/obj-c++.dg/property/dotsyntax-7.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-7.mm new file mode 100644 index 000000000..15c1725d8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-7.mm @@ -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/obj-c++.dg/property/dotsyntax-8.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-8.mm new file mode 100644 index 000000000..35dfda40c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-8.mm @@ -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/obj-c++.dg/property/dotsyntax-9.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-9.mm new file mode 100644 index 000000000..61a5c0eb8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-9.mm @@ -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/obj-c++.dg/property/dotsyntax-deprecated-1.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-deprecated-1.mm new file mode 100644 index 000000000..ad627a8c1 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-deprecated-1.mm @@ -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/obj-c++.dg/property/dynamic-1.mm b/gcc/testsuite/obj-c++.dg/property/dynamic-1.mm new file mode 100644 index 000000000..4e84843c3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dynamic-1.mm @@ -0,0 +1,34 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +@end + +@implementation MyRootClass +@end + +@dynamic isa; /* { dg-error "misplaced .@dynamic. Objective-C.. construct" } */ + +@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/obj-c++.dg/property/dynamic-2.mm b/gcc/testsuite/obj-c++.dg/property/dynamic-2.mm new file mode 100644 index 000000000..49004eff4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dynamic-2.mm @@ -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 "misplaced .@dynamic. Objective-C.. construct" } */ + +@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/obj-c++.dg/property/dynamic-3.mm b/gcc/testsuite/obj-c++.dg/property/dynamic-3.mm new file mode 100644 index 000000000..e8a6693b0 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dynamic-3.mm @@ -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/obj-c++.dg/property/dynamic-4.mm b/gcc/testsuite/obj-c++.dg/property/dynamic-4.mm new file mode 100644 index 000000000..84998d6b4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dynamic-4.mm @@ -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/obj-c++.dg/property/dynamic-5.mm b/gcc/testsuite/obj-c++.dg/property/dynamic-5.mm new file mode 100644 index 000000000..77e81411a --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dynamic-5.mm @@ -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/obj-c++.dg/property/dynamic-6.mm b/gcc/testsuite/obj-c++.dg/property/dynamic-6.mm new file mode 100644 index 000000000..23a7a8905 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dynamic-6.mm @@ -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/obj-c++.dg/property/fsf-property-basic.mm b/gcc/testsuite/obj-c++.dg/property/fsf-property-basic.mm new file mode 100644 index 000000000..2c3774a93 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/fsf-property-basic.mm @@ -0,0 +1,70 @@ +/* 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" } { "" } } */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int printf (const char *fmt,...); +extern void abort (void); + +#include <objc/objc.h> +#include <objc/runtime.h> + +#ifdef __cplusplus +} +#endif + +@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/obj-c++.dg/property/fsf-property-method-access.mm b/gcc/testsuite/obj-c++.dg/property/fsf-property-method-access.mm new file mode 100644 index 000000000..11efb4af0 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/fsf-property-method-access.mm @@ -0,0 +1,75 @@ +/* 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" } { "" } } */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int printf (const char *fmt,...); +extern void abort (void); + +#include <objc/objc.h> +#include <objc/runtime.h> + +#ifdef __cplusplus +} +#endif + +@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/obj-c++.dg/property/fsf-property-named-ivar.mm b/gcc/testsuite/obj-c++.dg/property/fsf-property-named-ivar.mm new file mode 100644 index 000000000..d29f43106 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/fsf-property-named-ivar.mm @@ -0,0 +1,69 @@ +/* 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" } { "" } } */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int printf (const char *fmt,...); +extern void abort (void); + +#include <objc/objc.h> +#include <objc/runtime.h> + +#ifdef __cplusplus +} +#endif + +@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/obj-c++.dg/property/property-1.mm b/gcc/testsuite/obj-c++.dg/property/property-1.mm new file mode 100644 index 000000000..4447946d1 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/property-1.mm @@ -0,0 +1,31 @@ +/* This program tests use of property provided setter/getter functions. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../../objc-obj-c++-shared/Object1.mm" } */ + +#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/obj-c++.dg/property/property-encoding-1.mm b/gcc/testsuite/obj-c++.dg/property/property-encoding-1.mm new file mode 100644 index 000000000..dc12c3137 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/property-encoding-1.mm @@ -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/obj-c++.dg/property/property-neg-1.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-1.mm new file mode 100644 index 000000000..cae1a5615 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/property-neg-1.mm @@ -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/obj-c++.dg/property/property-neg-2.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-2.mm new file mode 100644 index 000000000..f730fe846 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/property-neg-2.mm @@ -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/obj-c++.dg/property/property-neg-3.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-3.mm new file mode 100644 index 000000000..0b30931a8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/property-neg-3.mm @@ -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/obj-c++.dg/property/property-neg-4.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-4.mm new file mode 100644 index 000000000..cc25d84af --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/property-neg-4.mm @@ -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/obj-c++.dg/property/property-neg-5.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-5.mm new file mode 100644 index 000000000..464470cba --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/property-neg-5.mm @@ -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/obj-c++.dg/property/property-neg-6.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-6.mm new file mode 100644 index 000000000..86bb66485 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/property-neg-6.mm @@ -0,0 +1,9 @@ +/* Check for proper declaration of @property. */ +/* { dg-do compile } */ + +@interface Bar +{ + int iVar; +} +@property int FooBar /* { dg-error "expected ';' at end of input" } */ + /* { dg-error "expected '@end' at end of input" "" { target *-*-* } 8 } */ diff --git a/gcc/testsuite/obj-c++.dg/property/property-neg-7.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-7.mm new file mode 100644 index 000000000..4c3d5d7d3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/property-neg-7.mm @@ -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/obj-c++.dg/property/property.exp b/gcc/testsuite/obj-c++.dg/property/property.exp new file mode 100644 index 000000000..468e34b37 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/property.exp @@ -0,0 +1,43 @@ +# GCC Objective-C++ testsuite that uses the `dg.exp' driver. +# Copyright (C) 2004, 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 obj-c++-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_OBJCXXFLAGS +if ![info exists DEFAULT_OBJCXXFLAGS] then { + set DEFAULT_OBJCXXFLAGS " -ansi -pedantic-errors -Wno-long-long" +} + +# Initialize `dg'. +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]] + +# Main loop. +dg-runtest $tests "-fgnu-runtime" $DEFAULT_OBJCXXFLAGS + +# 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_OBJCXXFLAGS +} + +# All done. +dg-finish diff --git a/gcc/testsuite/obj-c++.dg/property/synthesize-1.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-1.mm new file mode 100644 index 000000000..3513c016e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/synthesize-1.mm @@ -0,0 +1,53 @@ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyRootClass +{ + Class isa; +} +@end + +@implementation MyRootClass +@end + +@synthesize isa; /* { dg-error "misplaced .@synthesize. Objective-C.. construct" } */ + +@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/obj-c++.dg/property/synthesize-10.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-10.mm new file mode 100644 index 000000000..fc4683187 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/synthesize-10.mm @@ -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/obj-c++.dg/property/synthesize-11.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-11.mm new file mode 100644 index 000000000..25158da76 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/synthesize-11.mm @@ -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-message "method definition for ..setCountA.. not found" "" { target *-*-* } 29 } */ +/* { dg-message "method definition for ..countA. not found" "" { target *-*-* } 29 } */ diff --git a/gcc/testsuite/obj-c++.dg/property/synthesize-2.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-2.mm new file mode 100644 index 000000000..b14fe264a --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/synthesize-2.mm @@ -0,0 +1,52 @@ +/* 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 () +{ + 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/obj-c++.dg/property/synthesize-3.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-3.mm new file mode 100644 index 000000000..866990531 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/synthesize-3.mm @@ -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/obj-c++.dg/property/synthesize-4.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-4.mm new file mode 100644 index 000000000..602dc68b4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/synthesize-4.mm @@ -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/obj-c++.dg/property/synthesize-5.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-5.mm new file mode 100644 index 000000000..0871b63ee --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/synthesize-5.mm @@ -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/obj-c++.dg/property/synthesize-6.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-6.mm new file mode 100644 index 000000000..2a078c9b8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/synthesize-6.mm @@ -0,0 +1,30 @@ +/* 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 *-*-* } 27 } */ +/* { dg-message "method definition for .-setW1:. not found" "" { target *-*-* } 27 } */ +/* { dg-message "method definition for .-w1. not found" "" { target *-*-* } 27 } */ diff --git a/gcc/testsuite/obj-c++.dg/property/synthesize-7.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-7.mm new file mode 100644 index 000000000..929e3803b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/synthesize-7.mm @@ -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/obj-c++.dg/property/synthesize-8.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-8.mm new file mode 100644 index 000000000..4af3ecc74 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/synthesize-8.mm @@ -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/obj-c++.dg/property/synthesize-9.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-9.mm new file mode 100644 index 000000000..7eae31d3f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/synthesize-9.mm @@ -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/obj-c++.dg/proto-error-1.mm b/gcc/testsuite/obj-c++.dg/proto-error-1.mm new file mode 100644 index 000000000..888db4792 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/proto-error-1.mm @@ -0,0 +1,4 @@ +// PR obj-c++/28434 +// { dg-do compile } + +Class<> c; // { dg-error "identifier" } diff --git a/gcc/testsuite/obj-c++.dg/proto-init-mimatch-1.mm b/gcc/testsuite/obj-c++.dg/proto-init-mimatch-1.mm new file mode 100644 index 000000000..64e52e812 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/proto-init-mimatch-1.mm @@ -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/obj-c++.dg/proto-lossage-1.mm b/gcc/testsuite/obj-c++.dg/proto-lossage-1.mm new file mode 100644 index 000000000..2f7eb9861 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/proto-lossage-1.mm @@ -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/obj-c++.dg/proto-lossage-2.mm b/gcc/testsuite/obj-c++.dg/proto-lossage-2.mm new file mode 100644 index 000000000..361bb9087 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/proto-lossage-2.mm @@ -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/obj-c++.dg/proto-lossage-3.mm b/gcc/testsuite/obj-c++.dg/proto-lossage-3.mm new file mode 100644 index 000000000..ac66ace57 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/proto-lossage-3.mm @@ -0,0 +1,34 @@ +/* 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" } { "" } } */ +/* { dg-additional-sources "../objc-obj-c++-shared/Object1.mm" } */ + +#include "../objc-obj-c++-shared/next-mapping.h" +#include "../objc-obj-c++-shared/Protocol1.h" + +@protocol NoInstanceMethods ++ testMethod; +@end + +@protocol NoClassMethods +- testMethod; +@end + +int +main() +{ +#ifdef __OBJC2__ +protocol_getMethodDescription(@protocol(NoInstanceMethods), @selector(name), NO, YES); +protocol_getMethodDescription(@protocol(NoInstanceMethods), @selector(name), NO, NO); +protocol_getMethodDescription(@protocol(NoClassMethods), @selector(name), NO, YES); +protocol_getMethodDescription(@protocol(NoClassMethods), @selector(name), NO, NO); +#else +[@protocol(NoInstanceMethods) descriptionForInstanceMethod: @selector(name)]; +[@protocol(NoInstanceMethods) descriptionForClassMethod: @selector(name)]; +[@protocol(NoClassMethods) descriptionForInstanceMethod: @selector(name)]; +[@protocol(NoClassMethods) descriptionForClassMethod: @selector(name)]; +#endif +return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/proto-lossage-4.mm b/gcc/testsuite/obj-c++.dg/proto-lossage-4.mm new file mode 100644 index 000000000..9f94754ca --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/proto-lossage-4.mm @@ -0,0 +1,52 @@ +/* Test for situations in which protocol conformance information + may be lost while casting. */ +/* 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 Proto +- (long)someValue; +@end + +@interface Obj +- (long)anotherValue; +@end + +long foo(void) { + long 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 .long int." } */ + receiver += [receiver anotherValue]; /* { dg-warning "invalid receiver type .long int." } */ + + receiver += [(Obj *)receiver someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */ +/* { dg-error "invalid conversion" "" { target *-*-* } 28 } */ + + 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-error "invalid conversion" "" { target *-*-* } 34 } */ + + 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-error "invalid conversion" "" { target *-*-* } 42 } */ + + 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/obj-c++.dg/proto-lossage-5.mm b/gcc/testsuite/obj-c++.dg/proto-lossage-5.mm new file mode 100644 index 000000000..35c0956ed --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/proto-lossage-5.mm @@ -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/obj-c++.dg/proto-lossage-6.mm b/gcc/testsuite/obj-c++.dg/proto-lossage-6.mm new file mode 100644 index 000000000..6a4552eb0 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/proto-lossage-6.mm @@ -0,0 +1,17 @@ +@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/obj-c++.dg/proto-lossage-7.mm b/gcc/testsuite/obj-c++.dg/proto-lossage-7.mm new file mode 100644 index 000000000..b7746d7a1 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/proto-lossage-7.mm @@ -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/obj-c++.dg/proto-qual-1.mm b/gcc/testsuite/obj-c++.dg/proto-qual-1.mm new file mode 100644 index 000000000..959181b86 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/proto-qual-1.mm @@ -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 <stdio.h> +#include <stdlib.h> +#ifndef __NEXT_RUNTIME__ +#include <objc/objc-api.h> +#endif +#include "../objc-obj-c++-shared/next-mapping.h" +#include <objc/Protocol.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 *)) + +#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/obj-c++.dg/protocol-forward-1.mm b/gcc/testsuite/obj-c++.dg/protocol-forward-1.mm new file mode 100644 index 000000000..03c7ae065 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/protocol-forward-1.mm @@ -0,0 +1,27 @@ +/* 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/obj-c++.dg/protocol-forward-2.mm b/gcc/testsuite/obj-c++.dg/protocol-forward-2.mm new file mode 100644 index 000000000..9217ca8d5 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/protocol-forward-2.mm @@ -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/obj-c++.dg/protocol-inheritance-1.mm b/gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm new file mode 100644 index 000000000..6c23a4663 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm @@ -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/obj-c++.dg/protocol-inheritance-2.mm b/gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm new file mode 100644 index 000000000..d76994945 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm @@ -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/obj-c++.dg/protocol-optional-1.mm b/gcc/testsuite/obj-c++.dg/protocol-optional-1.mm new file mode 100644 index 000000000..bc4a3d07e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/protocol-optional-1.mm @@ -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/obj-c++.dg/protocol-qualifier-1.mm b/gcc/testsuite/obj-c++.dg/protocol-qualifier-1.mm new file mode 100644 index 000000000..c84bfbfa2 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/protocol-qualifier-1.mm @@ -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/obj-c++.dg/protocol-qualifier-2.mm b/gcc/testsuite/obj-c++.dg/protocol-qualifier-2.mm new file mode 100644 index 000000000..fd25d8ff6 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/protocol-qualifier-2.mm @@ -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/obj-c++.dg/qual-types-1.mm b/gcc/testsuite/obj-c++.dg/qual-types-1.mm new file mode 100644 index 000000000..2b0a7be59 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/qual-types-1.mm @@ -0,0 +1,69 @@ +/* Test if ObjC++ can distinguish protocol qualifiers from + template arguments. */ +/* Author: 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() + +@protocol Zone ++ allocFromZone:(void *)zone; +- copyFromZone:(void *)zone; +@end + +@protocol Init <Zone> ++ initialize; +- init; +@end + +@interface Foo: Object +{ @public int val; } +- init; +@end + +template <class T, class U> struct X { + T x; U y; +}; + +X<int, float> xx; + +template <typename T> struct Holder +{ + T *obj; + static int counter; + Holder(void) { obj = [[T alloc] init]; } + ~Holder(void) { [obj free]; --counter; } + id <Init, Zone> getObjId(void) { return obj; } + Object <Zone, Init> *getObj(void) { return obj; } +}; + +typedef Holder <Foo <Init, Zone> > FooHolder; + +@implementation Foo +-(id) init { + [super init]; + val = ++FooHolder::counter; + return self; +} +@end + +template <typename T> +int Holder<T>::counter = 0; + +int main (void) { + CHECK_IF(FooHolder::counter == 0); + { + FooHolder holder; + CHECK_IF(holder.obj->val == 1); + CHECK_IF(FooHolder::counter == 1); + FooHolder holder2; + CHECK_IF(holder2.obj->val == 2); + CHECK_IF(FooHolder::counter == 2); + } + CHECK_IF(FooHolder::counter == 0); + return 0; +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/selector-1.mm b/gcc/testsuite/obj-c++.dg/selector-1.mm new file mode 100644 index 000000000..d34f8c89c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/selector-1.mm @@ -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/obj-c++.dg/selector-2.mm b/gcc/testsuite/obj-c++.dg/selector-2.mm new file mode 100644 index 000000000..b3a3579e9 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/selector-2.mm @@ -0,0 +1,17 @@ +/* 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/obj-c++.dg/selector-3.mm b/gcc/testsuite/obj-c++.dg/selector-3.mm new file mode 100644 index 000000000..a1321a7b7 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/selector-3.mm @@ -0,0 +1,29 @@ +/* Test warning for non-existent selectors. */ +/* This is the "-fgnu-runtime" variant of objc.dg/selector-1.m. */ +/* { dg-options "-Wselector -fgnu-runtime" } */ +/* { dg-do compile } */ + +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/obj-c++.dg/selector-4.mm b/gcc/testsuite/obj-c++.dg/selector-4.mm new file mode 100644 index 000000000..690cc44b6 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/selector-4.mm @@ -0,0 +1,26 @@ +/* Test warning for non existing selectors. */ +/* Contributed by Devang Patel <dpatel@apple.com>. */ + +/* { dg-options "-Wselector -fnext-runtime" } */ +/* { dg-do compile } */ + +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/obj-c++.dg/selector-5.mm b/gcc/testsuite/obj-c++.dg/selector-5.mm new file mode 100644 index 000000000..5a3a4b614 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/selector-5.mm @@ -0,0 +1,13 @@ +/* { dg-options "" } */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +int main() +{ + SEL foo = @selector(foo::); + return 0; +} + +/* { dg-final { scan-assembler "foo::" } } */ + diff --git a/gcc/testsuite/obj-c++.dg/selector-6.mm b/gcc/testsuite/obj-c++.dg/selector-6.mm new file mode 100644 index 000000000..4ba8e2b36 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/selector-6.mm @@ -0,0 +1,13 @@ +/* { dg-options "" } */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" + +int main() +{ + SEL foo = @selector(foo: a::); + return 0; +} + +/* { dg-final { scan-assembler "foo:a::" } } */ + diff --git a/gcc/testsuite/obj-c++.dg/selector-warn-1.mm b/gcc/testsuite/obj-c++.dg/selector-warn-1.mm new file mode 100644 index 000000000..b4b308d7b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/selector-warn-1.mm @@ -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/obj-c++.dg/set-not-used-1.mm b/gcc/testsuite/obj-c++.dg/set-not-used-1.mm new file mode 100644 index 000000000..6380ec9df --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/set-not-used-1.mm @@ -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/obj-c++.dg/strings/const-cfstring-2.mm b/gcc/testsuite/obj-c++.dg/strings/const-cfstring-2.mm new file mode 100644 index 000000000..14ae68c6c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/strings/const-cfstring-2.mm @@ -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/obj-c++.dg/strings/const-cfstring-5.mm b/gcc/testsuite/obj-c++.dg/strings/const-cfstring-5.mm new file mode 100644 index 000000000..13cb78957 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/strings/const-cfstring-5.mm @@ -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/obj-c++.dg/strings/const-str-1.mm b/gcc/testsuite/obj-c++.dg/strings/const-str-1.mm new file mode 100644 index 000000000..754c99bf1 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/strings/const-str-1.mm @@ -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/obj-c++.dg/strings/const-str-12.mm b/gcc/testsuite/obj-c++.dg/strings/const-str-12.mm new file mode 100644 index 000000000..921d05565 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/strings/const-str-12.mm @@ -0,0 +1,31 @@ +/* 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-obj-c++-shared/Object1.h" + +@interface Foo: Object { + char *cString; + unsigned int len; +} ++ (id)description; +@end + +@interface Bar: Object ++ (Foo *) getString: (int) which; +@end + +#ifdef NEXT_OBJC_USE_NEW_INTERFACE +Class _FooClassReference; +#else +struct objc_class _FooClassReference; +#endif + +@implementation Bar ++ (Foo *) getString: (int) which { + return which? [Foo description]: @"Hello"; +} +@end diff --git a/gcc/testsuite/obj-c++.dg/strings/const-str-2.mm b/gcc/testsuite/obj-c++.dg/strings/const-str-2.mm new file mode 100644 index 000000000..e9e2fc93d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/strings/const-str-2.mm @@ -0,0 +1,8 @@ +/* Test the -fconstant-string-class flag error. */ +/* { dg-do compile } */ +/* { dg-options "-fconstant-string-class=" } */ +/* { 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/obj-c++.dg/strings/const-str-5.mm b/gcc/testsuite/obj-c++.dg/strings/const-str-5.mm new file mode 100644 index 000000000..8c12a0c11 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/strings/const-str-5.mm @@ -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 equiv_u { + 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/obj-c++.dg/strings/const-str-6.mm b/gcc/testsuite/obj-c++.dg/strings/const-str-6.mm new file mode 100644 index 000000000..69954d9f4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/strings/const-str-6.mm @@ -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 equiv_u { + 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/obj-c++.dg/strings/strings-1.mm b/gcc/testsuite/obj-c++.dg/strings/strings-1.mm new file mode 100644 index 000000000..fc3f21185 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/strings/strings-1.mm @@ -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/obj-c++.dg/strings/strings-2.mm b/gcc/testsuite/obj-c++.dg/strings/strings-2.mm new file mode 100644 index 000000000..403cf7d3b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/strings/strings-2.mm @@ -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" } { "" } } */ +/* { 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__ +#include <string.h> +/* The MyTestString metaclass will need to be initialized before we can + send messages to strings. */ + +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/obj-c++.dg/strings/strings.exp b/gcc/testsuite/obj-c++.dg/strings/strings.exp new file mode 100644 index 000000000..82cd925bb --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/strings/strings.exp @@ -0,0 +1,45 @@ +# 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 obj-c++-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_OBJCXXFLAGS +if ![info exists DEFAULT_OBJCXXFLAGS] then { + set DEFAULT_OBJCXXFLAGS " -ansi -pedantic-errors -Wno-long-long" +} + +# Initialize `dg'. +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]] + +# Main loop. +dg-runtest $tests "-fgnu-runtime" $DEFAULT_OBJCXXFLAGS + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { + dg-runtest $tests "-fnext-runtime" $DEFAULT_OBJCXXFLAGS +} + +# All done. +dg-finish diff --git a/gcc/testsuite/obj-c++.dg/stubify-1.mm b/gcc/testsuite/obj-c++.dg/stubify-1.mm new file mode 100644 index 000000000..687739cec --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/stubify-1.mm @@ -0,0 +1,39 @@ +/* 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 -fno-exceptions -mmacosx-version-min=10.4" } */ + +typedef struct objc_object { } *id ; +int x = 41 ; + +extern "C" { + 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/obj-c++.dg/stubify-2.mm b/gcc/testsuite/obj-c++.dg/stubify-2.mm new file mode 100644 index 000000000..9968672ed --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/stubify-2.mm @@ -0,0 +1,33 @@ +/* All calls must be properly stubified. */ +/* Testcase extracted from TextEdit:Document.m. */ + +/* { dg-do compile { target *-*-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/obj-c++.dg/super-class-1.mm b/gcc/testsuite/obj-c++.dg/super-class-1.mm new file mode 100644 index 000000000..788703697 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/super-class-1.mm @@ -0,0 +1,30 @@ +/* Test calling super from within a category method. */ + +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface NSObject +@end +@interface NSMenuItem: NSObject +@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 "invalid use of undefined type" } */ +} /* { dg-bogus "forward declaration of" "" { target *-*-* } 28 } */ +@end diff --git a/gcc/testsuite/obj-c++.dg/super-class-2.mm b/gcc/testsuite/obj-c++.dg/super-class-2.mm new file mode 100644 index 000000000..4ec0c3f47 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/super-class-2.mm @@ -0,0 +1,35 @@ +/* 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/obj-c++.dg/super-dealloc-1.mm b/gcc/testsuite/obj-c++.dg/super-dealloc-1.mm new file mode 100644 index 000000000..0ab177bb7 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/super-dealloc-1.mm @@ -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/obj-c++.dg/super-dealloc-2.mm b/gcc/testsuite/obj-c++.dg/super-dealloc-2.mm new file mode 100644 index 000000000..80dcf4950 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/super-dealloc-2.mm @@ -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/obj-c++.dg/sync-2.mm b/gcc/testsuite/obj-c++.dg/sync-2.mm new file mode 100644 index 000000000..c2143a4e9 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/sync-2.mm @@ -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/obj-c++.dg/sync-3.mm b/gcc/testsuite/obj-c++.dg/sync-3.mm new file mode 100644 index 000000000..95def43d0 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/sync-3.mm @@ -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" } */ + { dummy++; } + + @synchronized (int) /* { dg-error "expected" } */ + { dummy++; } + + return dummy; +} diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-1.mm b/gcc/testsuite/obj-c++.dg/syntax-error-1.mm new file mode 100644 index 000000000..13f3c275c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/syntax-error-1.mm @@ -0,0 +1,26 @@ +/* Graceful handling of a syntax error. */ +/* { dg-do compile } */ + +#include <objc/Object.h> + +class foo { + public: + foo(); + virtual ~foo(); +}; + + +extern void NXLog(const char *, ...); + +@interface Test2 : Object { +} +- (void) foo2; +@end + +@implementation Test2 +- (void) foo2 + NXLog("Hello, world!"); /* { dg-error "expected .\{. before .NXLog." } */ +} /* { dg-error "stray .\}. between Objective\\-C\\+\\+ methods" } */ +@end + +/* { dg-error "expected constructor, destructor, or type conversion before" "" { target *-*-* } 22 } */ diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-10.mm b/gcc/testsuite/obj-c++.dg/syntax-error-10.mm new file mode 100644 index 000000000..e45abccfc --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/syntax-error-10.mm @@ -0,0 +1 @@ +@interface /* { dg-error "expected identifier" } */ diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-2.mm b/gcc/testsuite/obj-c++.dg/syntax-error-2.mm new file mode 100644 index 000000000..ba8804a89 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/syntax-error-2.mm @@ -0,0 +1,16 @@ +/* Recover gracefully from a syntax error. */ + +@implementation Whatever /* { dg-warning "cannot find interface declaration for .Whatever." } */ + +- (void) function +{ + if( 1 ) + { + else /* { dg-error "expected .\}. before .else." } */ + { + } +} + +- (void) another {} + +@end diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-3.mm b/gcc/testsuite/obj-c++.dg/syntax-error-3.mm new file mode 100644 index 000000000..34f914bad --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/syntax-error-3.mm @@ -0,0 +1,10 @@ +/* Yet another stray infinite loop... */ +/* { dg-do compile } */ + +@interface Foo +{ + int x; + int y; +} +- (int) foo ; { /* { dg-error "stray .\{. between Objective\\-C\\+\\+ methods" } */ +@end diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-4.mm b/gcc/testsuite/obj-c++.dg/syntax-error-4.mm new file mode 100644 index 000000000..0df061839 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/syntax-error-4.mm @@ -0,0 +1,15 @@ +/* Yet another stray infinite loop... */ +/* { dg-do compile } */ + +@interface t +{ +} +- (void)go; +@end +@implementation t +- (void)go +{ + } +} /* { dg-error "stray .\}. between Objective\\-C\\+\\+ methods" } */ +@end + diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-5.mm b/gcc/testsuite/obj-c++.dg/syntax-error-5.mm new file mode 100644 index 000000000..f0d060520 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/syntax-error-5.mm @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +typedef struct S { int i; } NSDictionary; + +@interface A +{ +} +@end + +@interface B : A +{ + NSDictionary * _userInfo; +@end /* { dg-error "expected .\}. before .end." } */ diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-6.mm b/gcc/testsuite/obj-c++.dg/syntax-error-6.mm new file mode 100644 index 000000000..21423ec7e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/syntax-error-6.mm @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +@interface NSButton +- (int) state; +@end + +void FOO() +{ + NSButton * mCopyAcrobatCB; + + [ [ mCopyAcrobatCB state ] == 0 ] != 1; /* { dg-error "objective\\-c\\+\\+" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-7.mm b/gcc/testsuite/obj-c++.dg/syntax-error-7.mm new file mode 100644 index 000000000..e38c0958c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/syntax-error-7.mm @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +@interface Foo +-(void) someMethod; +@end + +@implementation Foo +-(void) +-(void) someMethod /* { dg-error "expected before .-." } */ +{ +} +@end /* { dg-warning "incomplete implementation of class" } */ +/* { dg-warning "method definition for ..someMethod. not found" "" { target *-*-* } 12 } */ diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-8.mm b/gcc/testsuite/obj-c++.dg/syntax-error-8.mm new file mode 100644 index 000000000..731ffda5f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/syntax-error-8.mm @@ -0,0 +1 @@ +@interface A /* { dg-error "expected ..end." } */
\ No newline at end of file diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-9.mm b/gcc/testsuite/obj-c++.dg/syntax-error-9.mm new file mode 100644 index 000000000..97706d5b1 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/syntax-error-9.mm @@ -0,0 +1,3 @@ +@implementation SaturnDoc /* { dg-warning "cannot find interface declaration" } */ +- read: (void*)aStream ggg /* { dg-error "expected .:. at end of input" } */ +/* { dg-error "expected ..end. at end of input" "" { target *-*-* } 2 } */
\ No newline at end of file diff --git a/gcc/testsuite/obj-c++.dg/template-1.mm b/gcc/testsuite/obj-c++.dg/template-1.mm new file mode 100644 index 000000000..fc8b08b5e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/template-1.mm @@ -0,0 +1,50 @@ +/* Test for using ObjC classes as C++ template parameters. */ +/* Author: 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 Base: Object +- (int) meth; +@end + +@interface Derived: Base +- (int) meth; +@end + +static int count = 0; + +template <class T> struct Templ +{ + T *m; + int i; + Templ(): i(55), m([[T alloc] init]) { count++; } + ~Templ() { [m free]; count--; } +}; + +@implementation Base +- (int) meth { return 333; } +@end + +@implementation Derived +- (int) meth { return 666; } +@end + +int main (void) { + CHECK_IF(count == 0); + { + Templ<Derived> derived; + CHECK_IF(derived.i == 55 && count == 1); + Templ<Base> base; + CHECK_IF(base.i == 55 && count == 2); + CHECK_IF([base.m meth] == 333); + CHECK_IF([derived.m meth] == 666); + } + CHECK_IF(count == 0); + return 0; +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/template-2.mm b/gcc/testsuite/obj-c++.dg/template-2.mm new file mode 100644 index 000000000..346dab6c2 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/template-2.mm @@ -0,0 +1,29 @@ +/* Test if ObjC classes (and pointers thereto) can participate + in C++ overloading. Correct handling of cv-qualifiers is + key here. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do compile } */ + +@interface foo { + int a, b; +} +@end + +struct bar { + int c, d; +}; + +template <class _Tp> +struct allocator { + typedef _Tp* pointer; + typedef const _Tp* const_pointer; + typedef _Tp& reference; + typedef const _Tp& const_reference; + + pointer address(reference __x) const { return &__x; } + const_pointer address(const_reference __x) const { return &__x; } +}; + +allocator<bar *> b; +allocator<foo *> d; diff --git a/gcc/testsuite/obj-c++.dg/template-3.mm b/gcc/testsuite/obj-c++.dg/template-3.mm new file mode 100644 index 000000000..a3b96b32d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/template-3.mm @@ -0,0 +1,81 @@ +/* Test for passing arguments to ObjC methods in the context of template + expansion. */ +/* 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 ObjCClass : Object +{ +@public + int info; +} +-(id) init; +-(id) initWithInformation: (int) whatInfo; +-(id) initWithInformation: (int) whatInfo andInfo: (int) info2; +@end + +void foo(int info) { + ObjCClass *mObj1 = [[ObjCClass alloc] init]; + ObjCClass *mObj2 = [[ObjCClass alloc] initWithInformation: info]; + ObjCClass *mObj3 = [[ObjCClass alloc] initWithInformation: info andInfo: 39]; + + CHECK_IF(mObj1->info == 666); + CHECK_IF(mObj2->info == info); + CHECK_IF(mObj3->info == info + 39); +} + +template <class WrappedObjCClass> +class ObjCObjectWrapper +{ + public: + ObjCObjectWrapper(int info); + WrappedObjCClass *mObj1, *mObj2, *mObj3; +}; + +template <class WrappedObjCClass> +ObjCObjectWrapper<WrappedObjCClass>::ObjCObjectWrapper(int info) +{ + mObj1 = [[WrappedObjCClass alloc] init]; + mObj2 = [[WrappedObjCClass alloc] initWithInformation: info]; + mObj3 = [[WrappedObjCClass alloc] initWithInformation: info andInfo: 67]; +} + +@implementation ObjCClass +-(id) init { + return [self initWithInformation:666]; +} +-(id) initWithInformation: (int) whatInfo { + [super init]; + info = whatInfo; + return self; +} +-(id) initWithInformation: (int) whatInfo andInfo: (int) info2 { + [super init]; + info = whatInfo + info2; + return self; +} +@end + +ObjCObjectWrapper<ObjCClass> staticInstance(42); + +int main(void) { + ObjCObjectWrapper<ObjCClass> stackInstance(47); + + foo(89); + + CHECK_IF(staticInstance.mObj1->info == 666); + CHECK_IF(staticInstance.mObj2->info == 42); + CHECK_IF(staticInstance.mObj3->info == 42 + 67); + + CHECK_IF(stackInstance.mObj1->info == 666); + CHECK_IF(stackInstance.mObj2->info == 47); + CHECK_IF(stackInstance.mObj3->info == 47 + 67); + + return 0; +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/template-4.mm b/gcc/testsuite/obj-c++.dg/template-4.mm new file mode 100644 index 000000000..af3145f05 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/template-4.mm @@ -0,0 +1,85 @@ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do run } */ +/* { 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.mm ../objc-obj-c++-shared/nsconstantstring-class-impl.mm" } */ + +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#ifndef __NEXT_RUNTIME__ +#include <objc/NXConstStr.h> +#else +#include "../objc-obj-c++-shared/nsconstantstring-class.h" +#endif + +#include "../objc-obj-c++-shared/Object1.h" +#include "../objc-obj-c++-shared/next-mapping.h" + +#define CHECK_IF(expr) if(!(expr)) abort() + +template <class ARR, class TYPE> class TestT +{ +public: + TYPE k; + int abc(ARR *array) { + return [array count] * k; + } + TestT(TYPE _k): k(_k) { } +}; + +template <class TYPE> +const char *getDesc(void) { + return [TYPE name]; +} + +@class Array; + +template <class TYPE> +int abc(TYPE *xyz, Array *array) { + return [xyz count] + [array count]; +} + +@interface Array: Object { + id *arr; + int count; +} ++ (id)arrayWithObjects:(id)first, ... ; +- (int)count; +@end + +@implementation Array ++ (id)arrayWithObjects:(id)first, ... { + Array *a = [Array new]; + a->count = 0; + a->arr = (id *) calloc(8, sizeof(id)); + + va_list args; + va_start (args, first); + + a->arr[a->count++] = first; + + for (id el; el = va_arg(args, id); a->count++) + a->arr[a->count] = el; + + return a; +} +- (int)count { + return count; +} +@end + +int main(void) { + CHECK_IF(!strcmp ([@"Object" cString], getDesc<Object>())); + CHECK_IF(!strcmp ([@"Array" cString], getDesc<Array>())); + + Array* a1 = [Array arrayWithObjects:@"One", @"Two", @"Three", nil]; + Array* a2 = [Array arrayWithObjects:@"Four", @"Five", nil]; + + TestT<Array, int> t(7); + CHECK_IF(t.abc(a1) + t.abc(a2) == 35); + CHECK_IF(abc(a1, a2) * t.k == 35); + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/template-5.mm b/gcc/testsuite/obj-c++.dg/template-5.mm new file mode 100644 index 000000000..79ed57d15 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/template-5.mm @@ -0,0 +1,17 @@ +// Test that extern template does not get emitted. +// Author: Matt Austern <austern@apple.com> + +// { dg-do compile } +// { dg-options "" } +// { dg-final { scan-assembler-not ".globl __ZN3FooIiE5identEi" } } + +template <typename X> +struct Foo { + X ident(X x) { return x; } +}; + +extern template struct Foo<int>; + +int abcde(Foo<int>& foo, int n) { + return foo.ident(n); +} diff --git a/gcc/testsuite/obj-c++.dg/template-6.mm b/gcc/testsuite/obj-c++.dg/template-6.mm new file mode 100644 index 000000000..c9b82c0c7 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/template-6.mm @@ -0,0 +1,16 @@ +// Test that extern template does not get emitted. +// Author: Matt Austern <austern@apple.com> + +// { dg-do compile } +// { dg-options "" } +// { dg-final { scan-assembler-not ".globl __ZN3FooIiE5identEi" } } + +template <typename X> + struct Foo { X ident(X x); }; + +template <typename X> + X Foo<X>::ident(X x) { return x; } + +extern template struct Foo<int>; + +int abcde(Foo<int>& foo, int n) { return foo.ident(n); } diff --git a/gcc/testsuite/obj-c++.dg/template-7.mm b/gcc/testsuite/obj-c++.dg/template-7.mm new file mode 100644 index 000000000..8621abeba --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/template-7.mm @@ -0,0 +1,21 @@ +// Test that objective-c++ does not confuse a template parameter named 'Object' +// with an interface of the same name. +// Author: Fariborz Jahanian <fjahanian@apple.com> +// { dg-do compile } +// { dg-options "" } +typedef struct objc_class *Class; + +@interface Object +{ + Class isa; +} +@end + +template <class Object> +struct pyobject_type +{ + static Object* checked_downcast(Object* x) + { + return x; + } +}; diff --git a/gcc/testsuite/obj-c++.dg/template-8.mm b/gcc/testsuite/obj-c++.dg/template-8.mm new file mode 100644 index 000000000..df215b852 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/template-8.mm @@ -0,0 +1,53 @@ +/* Test that all pending instantiations have taken place before meta-data + generation. */ +/* Author: Fariborz Jahanian <fjahanian@apple.com> */ +/* Adapted by Nicola Pero <nicola.pero@meta-innovation.com> */ +/* { 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" } { "" } } */ + +#include <objc/objc.h> +#include <objc/runtime.h> + +@interface MyRootClass +{ Class isa; } ++ (id) initialize; ++ alloc; +- init; +- doSomething; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ alloc { return class_createInstance (self, 0); } +- init { return self; } +- doSomething { return self; } +@end + +class Base +{ +public: + Base() { } + virtual ~Base() { } + + void destroy() { delete this; } +}; + +template<class T> +class Subclass : public T +{ +public: + Subclass() { } + + virtual ~Subclass() + { + [[[MyRootClass alloc] init] doSomething]; + } +}; + +int main(int argc, const char * argv[]) +{ + Subclass<Base>* theSubclass = new Subclass<Base>(); + theSubclass->destroy(); + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/threedotthree-abi-1.mm b/gcc/testsuite/obj-c++.dg/threedotthree-abi-1.mm new file mode 100644 index 000000000..672a31163 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/threedotthree-abi-1.mm @@ -0,0 +1,73 @@ +/* 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 <stdio.h> +#include <string.h> +#include "../objc-obj-c++-shared/Protocol1.h" +#ifndef __NEXT_RUNTIME__ +#include <objc/objc-api.h> +#endif + +extern "C" 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/obj-c++.dg/tls/diag-1.mm b/gcc/testsuite/obj-c++.dg/tls/diag-1.mm new file mode 100644 index 000000000..7c3245d9f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/tls/diag-1.mm @@ -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/obj-c++.dg/tls/diag-2.mm b/gcc/testsuite/obj-c++.dg/tls/diag-2.mm new file mode 100644 index 000000000..de88eb193 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/tls/diag-2.mm @@ -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 "multiple storage classes" } */ + +void foo() +{ + __thread int l1; /* { dg-error "implicitly auto and declared '__thread'" } */ + auto __thread int l2; /* { dg-error "multiple storage classes" } */ + __thread extern int l3; /* { dg-error "'__thread' before 'extern'" } */ + register __thread int l4; /* { dg-error "multiple storage classes" } */ +} + +__thread void f1 (); /* { dg-error "storage class '__thread' invalid for function 'f1'" } */ +extern __thread void f2 (); /* { dg-error "storage class '__thread' invalid for function 'f2'" } */ +static __thread void f3 (); /* { dg-error "storage class '__thread' invalid for function 'f3'" } */ +__thread void f4 () { } /* { dg-error "storage class '__thread' invalid for function 'f4'" } */ + +void bar(__thread int p1); /* { dg-error "(invalid in parameter)|(specified for parameter)" } */ + +struct A { + __thread int i; /* { dg-error "storage class specified for 'i'" } */ +}; diff --git a/gcc/testsuite/obj-c++.dg/tls/diag-3.mm b/gcc/testsuite/obj-c++.dg/tls/diag-3.mm new file mode 100644 index 000000000..0a597b20f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/tls/diag-3.mm @@ -0,0 +1,11 @@ +/* Report invalid extern and __thread combinations. */ +/* { dg-require-effective-target tls } */ + +extern int j; /* { dg-error "previously declared here" } */ +__thread int j; /* { dg-error "follows non-thread-local" } */ + +extern __thread int i; /* { dg-error "previously declared here" } */ +int i; /* { dg-error "follows thread-local" } */ + +extern __thread int k; /* This is fine. */ +__thread int k; diff --git a/gcc/testsuite/obj-c++.dg/tls/diag-4.mm b/gcc/testsuite/obj-c++.dg/tls/diag-4.mm new file mode 100644 index 000000000..10ac2aada --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/tls/diag-4.mm @@ -0,0 +1,10 @@ +/* Invalid __thread specifiers. */ +/* { dg-require-effective-target tls } */ + +__thread typedef int g4; /* { dg-error "multiple storage classes in declaration of" } */ + +void foo() +{ + __thread auto int l2; /* { dg-error "multiple storage classes in declaration of" } */ + __thread register int l4; /* { dg-error "multiple storage classes in declaration of" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/tls/diag-5.mm b/gcc/testsuite/obj-c++.dg/tls/diag-5.mm new file mode 100644 index 000000000..413d107f2 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/tls/diag-5.mm @@ -0,0 +1,4 @@ +/* __thread specifiers on empty declarations. */ +/* { dg-require-effective-target tls } */ + +__thread struct foo; /* { dg-error "qualifiers can only be specified for objects and functions" } */ diff --git a/gcc/testsuite/obj-c++.dg/tls/init-1.mm b/gcc/testsuite/obj-c++.dg/tls/init-1.mm new file mode 100644 index 000000000..943088713 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/tls/init-1.mm @@ -0,0 +1,14 @@ +/* Invalid initializations. */ +/* { dg-require-effective-target tls } */ + +__thread int i = 42; + +static int j; +__thread int *p = &j; + +/* Note that this is valid in C++ (unlike C) as a run-time initialization. */ +int *q = &i; + +/* Valid because "const int k" is an integral constant expression in C++. */ +__thread const int k = 42; +__thread const int l = k;
\ No newline at end of file diff --git a/gcc/testsuite/obj-c++.dg/tls/init-2.mm b/gcc/testsuite/obj-c++.dg/tls/init-2.mm new file mode 100644 index 000000000..dc886ba01 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/tls/init-2.mm @@ -0,0 +1,14 @@ +/* Invalid initializations. */ +/* { dg-require-effective-target tls } */ + +extern __thread int i; +__thread int *p = &i; /* { dg-error "dynamically initialized" } */ + +extern int f(); +__thread int j = f(); /* { dg-error "dynamically initialized" } */ + +struct S +{ + S(); +}; +__thread S s; /* { dg-error "" } two errors here */ diff --git a/gcc/testsuite/obj-c++.dg/tls/static-1.mm b/gcc/testsuite/obj-c++.dg/tls/static-1.mm new file mode 100644 index 000000000..6d58010eb --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/tls/static-1.mm @@ -0,0 +1,31 @@ +// { dg-do run } +// { dg-require-effective-target tls } +// { dg-add-options tls } +// { dg-additional-sources "static-1a.mm" } + +extern "C" { +extern void abort (); +} +extern int test (); + +struct A +{ + static __thread int i; +}; + +__thread int A::i = 8; + +int +main () +{ + if (A::i != 8) + abort (); + + if (test ()) + abort (); + + if (A::i != 17) + abort (); + + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/tls/static-1a.mm b/gcc/testsuite/obj-c++.dg/tls/static-1a.mm new file mode 100644 index 000000000..40974205f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/tls/static-1a.mm @@ -0,0 +1,17 @@ +// { dg-skip-if "Additional Source File" *-*-* "*" "" } +// This is the additional source file for test static-1.mm + +struct A +{ + static __thread int i; +}; + +int +test () +{ + if (A::i != 8) + return 1; + + A::i = 17; + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/tls/tls.exp b/gcc/testsuite/obj-c++.dg/tls/tls.exp new file mode 100644 index 000000000..a4ba6393f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/tls/tls.exp @@ -0,0 +1,25 @@ +# Load support procs. +load_lib obj-c++-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_OBJCXXFLAGS +if ![info exists DEFAULT_OBJCXXFLAGS] then { + set DEFAULT_OBJCXXFLAGS " -ansi -pedantic-errors -Wno-long-long" +} + +# Initialize `dg'. +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]] + +# Main loop. +dg-runtest $tests "-fgnu-runtime" $DEFAULT_OBJCXXFLAGS + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { +dg-runtest $tests "-fnext-runtime" $DEFAULT_OBJCXXFLAGS +} + +# All done. +dg-finish diff --git a/gcc/testsuite/obj-c++.dg/tls/trivial.m b/gcc/testsuite/obj-c++.dg/tls/trivial.m new file mode 100644 index 000000000..e2b8f45b8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/tls/trivial.m @@ -0,0 +1,3 @@ +// { dg-require-effective-target tls } + +__thread int i; diff --git a/gcc/testsuite/obj-c++.dg/too-many-args.mm b/gcc/testsuite/obj-c++.dg/too-many-args.mm new file mode 100644 index 000000000..6fee1b31b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/too-many-args.mm @@ -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/obj-c++.dg/torture/dg-torture.exp b/gcc/testsuite/obj-c++.dg/torture/dg-torture.exp new file mode 100644 index 000000000..9ef34e995 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/dg-torture.exp @@ -0,0 +1,17 @@ +# This harness is for tests that should be run at all optimisation levels. + +load_lib obj-c++-dg.exp + +dg-init + +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]] + +obj-c++-dg-runtest $tests "-fgnu-runtime" + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { + obj-c++-dg-runtest $tests "-fnext-runtime" +} + +dg-finish diff --git a/gcc/testsuite/obj-c++.dg/torture/strings/const-cfstring-1.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-cfstring-1.mm new file mode 100644 index 000000000..2983c43c4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-cfstring-1.mm @@ -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/obj-c++.dg/torture/strings/const-cfstring-3.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-cfstring-3.mm new file mode 100644 index 000000000..4a6142988 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-cfstring-3.mm @@ -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/obj-c++.dg/torture/strings/const-cfstring-4.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-cfstring-4.mm new file mode 100644 index 000000000..1155db5f8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-cfstring-4.mm @@ -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/obj-c++.dg/torture/strings/const-str-10.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-10.mm new file mode 100644 index 000000000..3cb3acfae --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-10.mm @@ -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 } */ +/* { 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 + +#ifdef NEXT_OBJC_USE_NEW_INTERFACE +Class _NSConstantStringClassReference; +#else +extern struct objc_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/obj-c++.dg/torture/strings/const-str-11.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-11.mm new file mode 100644 index 000000000..8674646d8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-11.mm @@ -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 } */ +/* { 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 + +#ifdef NEXT_OBJC_USE_NEW_INTERFACE +extern Class _XStrClassReference; +#else +extern struct objc_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/obj-c++.dg/torture/strings/const-str-3.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-3.mm new file mode 100644 index 000000000..461d97b19 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-3.mm @@ -0,0 +1,57 @@ +/* Test the -fconstant-string-class=Foo option under the NeXT + runtime. */ +/* Developed by Markus Hitter <mah@jump-ing.de>. */ + +/* { dg-do run { target *-*-darwin* } } */ +/* { 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/obj-c++.dg/torture/strings/const-str-4.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-4.mm new file mode 100644 index 000000000..c2cadd3df --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-4.mm @@ -0,0 +1,33 @@ +/* Ensure that the preprocessor handles ObjC string constants gracefully. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-options "-fconstant-string-class=MyString" } */ +/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=MyString" { target *-*-darwin* } } */ + +#include <stdlib.h> + +@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/obj-c++.dg/torture/strings/const-str-7.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-7.mm new file mode 100644 index 000000000..d58cb91a7 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-7.mm @@ -0,0 +1,46 @@ +/* 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.mm" } */ + +#include "../../../objc-obj-c++-shared/Object1.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <objc/objc.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/obj-c++.dg/torture/strings/const-str-8.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-8.mm new file mode 100644 index 000000000..17997b628 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-8.mm @@ -0,0 +1,44 @@ +/* Test for assigning compile-time constant-string objects to static variables. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do run { target *-*-darwin* } } */ +/* { 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.mm" } */ + +#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/obj-c++.dg/torture/strings/const-str-9.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-9.mm new file mode 100644 index 000000000..e05c62b88 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-9.mm @@ -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 + +#ifdef NEXT_OBJC_USE_NEW_INTERFACE +Class _NSConstantStringClassReference; +#else +extern struct objc_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/obj-c++.dg/torture/strings/string1.mm b/gcc/testsuite/obj-c++.dg/torture/strings/string1.mm new file mode 100644 index 000000000..deacf43b3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/strings/string1.mm @@ -0,0 +1,25 @@ +/* Based on a test case contributed by Nicola Pero. */ + +/* { dg-do run } */ +/* { dg-options "-mno-constant-cfstrings" { target *-*-darwin* } } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../../../objc-obj-c++-shared/Object1.mm ../../../objc-obj-c++-shared/nsconstantstring-class-impl.mm" } */ + +#include "../../../objc-obj-c++-shared/Object1.h" +#include "../../../objc-obj-c++-shared/next-mapping.h" + +#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, char **args) +{ + if (strcmp ([@"this is a string" cString], "this is a string")) + abort (); + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/torture/strings/strings.exp b/gcc/testsuite/obj-c++.dg/torture/strings/strings.exp new file mode 100644 index 000000000..180401c3b --- /dev/null +++ b/gcc/testsuite/obj-c++.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 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_lib obj-c++-dg.exp + +dg-init +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]] + +obj-c++-dg-runtest $tests "-fgnu-runtime" + +# Darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { + obj-c++-dg-runtest $tests "-fnext-runtime" +} + +dg-finish diff --git a/gcc/testsuite/obj-c++.dg/torture/tls/diag-1.mm b/gcc/testsuite/obj-c++.dg/torture/tls/diag-1.mm new file mode 100644 index 000000000..7c3245d9f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/tls/diag-1.mm @@ -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/obj-c++.dg/torture/tls/thr-init-1.mm b/gcc/testsuite/obj-c++.dg/torture/tls/thr-init-1.mm new file mode 100644 index 000000000..62e322ed1 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/tls/thr-init-1.mm @@ -0,0 +1,25 @@ +// { dg-do run } +// { dg-require-effective-target tls } +// { dg-add-options tls } + +extern "C" { +extern void abort (); +} + +static __thread int fstat = 1; + +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 ) + abort (); + + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/torture/tls/thr-init-2.mm b/gcc/testsuite/obj-c++.dg/torture/tls/thr-init-2.mm new file mode 100644 index 000000000..4e3f8e6e3 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/tls/thr-init-2.mm @@ -0,0 +1,45 @@ +// { dg-do run } +// { dg-require-effective-target tls } +// { dg-add-options tls } + +extern "C" { +extern void abort (); +} + +__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 ) + abort () ; + + a = fa(glb); + if ( a != 6 ) + abort () ; + + a = fb(a); + if ( a != 10 || glb != 10 ) + abort () ; + + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/torture/tls/thr-init-3.mm b/gcc/testsuite/obj-c++.dg/torture/tls/thr-init-3.mm new file mode 100644 index 000000000..29768886a --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/tls/thr-init-3.mm @@ -0,0 +1,41 @@ +/* { dg-do run } */ +/* { dg-require-effective-target tls } */ +/* { dg-add-options tls } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../../../objc-obj-c++-shared/Object1.mm" } */ + +#include "../../../objc-obj-c++-shared/Object1.h" +extern "C" { +extern void abort (); +} + +@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 ) + abort () ; + + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/torture/tls/tls.exp b/gcc/testsuite/obj-c++.dg/torture/tls/tls.exp new file mode 100644 index 000000000..6d0668045 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/tls/tls.exp @@ -0,0 +1,16 @@ +# This harness is for tests that should be run at all optimisation levels. + +load_lib obj-c++-dg.exp + +dg-init +# Gather a list of all tests. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]] + +obj-c++-dg-runtest $tests "-fgnu-runtime" + +# darwin targets can also run code with the NeXT runtime. +if [istarget "*-*-darwin*" ] { + obj-c++-dg-runtest $tests "-fnext-runtime" +} + +dg-finish diff --git a/gcc/testsuite/obj-c++.dg/torture/tls/trivial.mm b/gcc/testsuite/obj-c++.dg/torture/tls/trivial.mm new file mode 100644 index 000000000..e2b8f45b8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/tls/trivial.mm @@ -0,0 +1,3 @@ +// { dg-require-effective-target tls } + +__thread int i; diff --git a/gcc/testsuite/obj-c++.dg/torture/trivial.mm b/gcc/testsuite/obj-c++.dg/torture/trivial.mm new file mode 100644 index 000000000..e627343a8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/torture/trivial.mm @@ -0,0 +1,12 @@ +// { dg-do run } + +// { dg-xfail-run-if "OBJC2 runtime" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "-fgnu-runtime" } } +// { dg-additional-sources "../../objc-obj-c++-shared/Object1.mm" } + +#import "../../objc-obj-c++-shared/Object1.h" + +int main(void) +{ + [Object class]; + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/try-catch-1.mm b/gcc/testsuite/obj-c++.dg/try-catch-1.mm new file mode 100644 index 000000000..a32bfeed6 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-1.mm @@ -0,0 +1,42 @@ +/* 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/obj-c++.dg/try-catch-10.mm b/gcc/testsuite/obj-c++.dg/try-catch-10.mm new file mode 100644 index 000000000..5f6daa42b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-10.mm @@ -0,0 +1,25 @@ +/* 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/obj-c++.dg/try-catch-11.mm b/gcc/testsuite/obj-c++.dg/try-catch-11.mm new file mode 100644 index 000000000..49e2c0cef --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-11.mm @@ -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/obj-c++.dg/try-catch-12.mm b/gcc/testsuite/obj-c++.dg/try-catch-12.mm new file mode 100644 index 000000000..e08f321e8 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-12.mm @@ -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/obj-c++.dg/try-catch-13.mm b/gcc/testsuite/obj-c++.dg/try-catch-13.mm new file mode 100644 index 000000000..905702fde --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-13.mm @@ -0,0 +1,67 @@ +/* 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-error "invalid conversion" "" { target *-*-* } 23 } */ +/* { dg-error "initializing argument" "" { 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-error "invalid conversion" "" { target *-*-* } 38 } */ +/* 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-error "initializing argument" "" { target *-*-* } 12 */ + } + @catch (id exc) { + @throw; + } + } while(0); + + do { + @try { + typeof(q) k = 88; + typeof(i) j = 8; + some_func (&j); +/* { dg-error "invalid conversion" "" { target *-*-* } 53 } */ +/* 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-error "initializing argument" "" { target *-*-* } 12 */ + some_func (&k); + } + @catch (id exc) { + @throw; + } + } while(0); + +} +@end + diff --git a/gcc/testsuite/obj-c++.dg/try-catch-14.mm b/gcc/testsuite/obj-c++.dg/try-catch-14.mm new file mode 100644 index 000000000..1d922b509 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-14.mm @@ -0,0 +1,24 @@ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +typedef unsigned char uint8_t; +typedef uint8_t foo[24]; + +void thingy(foo a) +{ +} + +int main() +{ + foo bar; + + @try { + } + @finally { + } + + thingy(bar); + + return 0; +} + diff --git a/gcc/testsuite/obj-c++.dg/try-catch-15.mm b/gcc/testsuite/obj-c++.dg/try-catch-15.mm new file mode 100644 index 000000000..01b3d5cbf --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-15.mm @@ -0,0 +1,34 @@ +/* Test if addition of 'volatile' to object causes bogus error in presence of try-catch. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +@interface Exception +@end + +class CppObj { +public: + void constMethod() const { + } +}; + +@interface MyObject : Exception +- (void)doSomething; +- (void)myMethod; +@end + +@implementation MyObject +- (void)doSomething { +} + +- (void)myMethod { + CppObj cppObj; + + @try { + [self doSomething]; + } + @catch (Exception *exception) { + } + + cppObj.constMethod(); +} +@end diff --git a/gcc/testsuite/obj-c++.dg/try-catch-16.mm b/gcc/testsuite/obj-c++.dg/try-catch-16.mm new file mode 100644 index 000000000..4aea2647a --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-16.mm @@ -0,0 +1,20 @@ +/* Test if addition of 'volatile' to object causes bogus error in presence of try-catch. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +extern void func( void * outData) ; +struct Point { + short v; + short h; +}; + + +void foo () +{ + Point eventLocation; + @try { + } @catch (id iiii) { + } + + func( &eventLocation ); +} diff --git a/gcc/testsuite/obj-c++.dg/try-catch-17.mm b/gcc/testsuite/obj-c++.dg/try-catch-17.mm new file mode 100644 index 000000000..7c642aca0 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-17.mm @@ -0,0 +1,18 @@ +/* Test if addition of 'volatile' to object causes bogus error in presence of try-catch. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile } */ + +struct Point { + short v; + short h; +}; + +void foo () +{ + Point eventLocation; + @try { + } @catch (id iiii) { + } + + Point p = eventLocation; +} diff --git a/gcc/testsuite/obj-c++.dg/try-catch-2.mm b/gcc/testsuite/obj-c++.dg/try-catch-2.mm new file mode 100644 index 000000000..05aba36a4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-2.mm @@ -0,0 +1,81 @@ +/* Test out '@catch(id foo) {...}', which should catch + all uncaught exceptions. */ +/* Developed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do run } */ +/* { dg-xfail-run-if "PR23616" { *-*-* } { "-fgnu-runtime" } { "-fnext-runtime" } } */ +/* { dg-xfail-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" "-fgnu-runtime" } { "" } } +/* { dg-options "-fobjc-exceptions" } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include <stdio.h> +#include <stdlib.h> + +/* The following is not required in actual user code; we include it + here to check that the compiler generates an internal definition of + _setjmp that is consistent with what <setjmp.h> provides. */ +#include <setjmp.h> + +#define CHECK_IF(expr) if(!(expr)) abort() + +@interface Frob: Object +@end + +@implementation Frob: Object +@end + +static Frob* _connection = nil; + +//-------------------------------------------------------------------- + + +void test (Object* sendPort) +{ + int cleanupPorts = 1; + Frob* receivePort = nil; + + @try { + printf ("receivePort = %p\n", receivePort); + printf ("sendPort = %p\n", sendPort); + printf ("cleanupPorts = %d\n", cleanupPorts); + printf ("---\n"); + + receivePort = (Frob *) -1; + _connection = (Frob *) -1; + printf ("receivePort = %p\n", receivePort); + printf ("sendPort = %p\n", sendPort); + printf ("cleanupPorts = %d\n", cleanupPorts); + printf ("---\n"); + + receivePort = nil; + sendPort = nil; + cleanupPorts = 0; + + printf ("receivePort = %p\n", receivePort); + printf ("sendPort = %p\n", sendPort); + printf ("cleanupPorts = %d\n", cleanupPorts); + printf ("---\n"); + + @throw [Object new]; + } + @catch(Frob *obj) { + printf ("Exception caught by incorrect handler!\n"); + CHECK_IF(0); + } + @catch(id exc) { + printf ("Exception caught by correct handler.\n"); + printf ("receivePort = %p (expected 0x0)\n", receivePort); + printf ("sendPort = %p (expected 0x0)\n", sendPort); + printf ("cleanupPorts = %d (expected 0)\n", cleanupPorts); + printf ("---"); + CHECK_IF(!receivePort); + CHECK_IF(!sendPort); + CHECK_IF(!cleanupPorts); + } +} + +int main (void) { + test((Object *)-1); + return 0; +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/try-catch-3.mm b/gcc/testsuite/obj-c++.dg/try-catch-3.mm new file mode 100644 index 000000000..7577c5bfa --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-3.mm @@ -0,0 +1,18 @@ +/* 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/obj-c++.dg/try-catch-4.mm b/gcc/testsuite/obj-c++.dg/try-catch-4.mm new file mode 100644 index 000000000..8dc033120 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-4.mm @@ -0,0 +1,25 @@ +/* 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/obj-c++.dg/try-catch-5.mm b/gcc/testsuite/obj-c++.dg/try-catch-5.mm new file mode 100644 index 000000000..f12d7e2cc --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-5.mm @@ -0,0 +1,26 @@ +/* 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 -fnext-runtime -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/obj-c++.dg/try-catch-6.mm b/gcc/testsuite/obj-c++.dg/try-catch-6.mm new file mode 100644 index 000000000..e0022b299 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-6.mm @@ -0,0 +1,14 @@ +/* A very simple @try-@catch example. */ + +/* { dg-do compile } */ +/* { dg-options "-fobjc-exceptions" } */ + +int foo(void) { + @try { + return 2; + } + @catch (id foo) { + return 1; + } + return 0; +} diff --git a/gcc/testsuite/obj-c++.dg/try-catch-7.mm b/gcc/testsuite/obj-c++.dg/try-catch-7.mm new file mode 100644 index 000000000..b69c980b2 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-7.mm @@ -0,0 +1,24 @@ +/* { 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/obj-c++.dg/try-catch-8.mm b/gcc/testsuite/obj-c++.dg/try-catch-8.mm new file mode 100644 index 000000000..b66662370 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-8.mm @@ -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/obj-c++.dg/try-catch-9.mm b/gcc/testsuite/obj-c++.dg/try-catch-9.mm new file mode 100644 index 000000000..a4331fc35 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/try-catch-9.mm @@ -0,0 +1,69 @@ +/* Check that local variables that get modified inside the @try + block survive until the @catch block is reached. */ +/* Developed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-do run } */ +/* { dg-xfail-run-if "PR23616" { *-*-* } { "-fgnu-runtime" } { "-fnext-runtime" } } */ +/* { dg-xfail-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" "-fgnu-runtime" } { "" } } +/* { dg-prune-output ".*internal compiler error.*" } */ +/* { dg-options "-fobjc-exceptions -O2" } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include <stdlib.h> +#include <stdio.h> + +int gi1 = 9, gi2 = 19; +float gf1 = 9.0, gf2 = 19.0; +id obj2 = nil; + +void foo (int arg1, float *arg2) +{ + int *pi = &gi1; + float *pf = &gf1; + id obj1 = nil; + int local1 = 45, local2 = 47; + float local3 = 3.0, local4 = 4.0; + register int local5 = 15; + static float local6 = 16.0; + + @try { + local1 = 123; + local2 = 345; + local3 = 5.0; + local4 = 6.0; + local5 = 17; + local6 = 18.0; + pi = &gi2; + pf = &gf2; + obj2 = obj1 = [Object new]; + arg1 = 17; + arg2 = &gf2; + + @throw [Object new]; + } + @catch (Object *obj) { + if (local1 != 123 || local2 != 345 || local3 != 5.0 + || local4 != 6.0 || local5 != 17 || local6 != 18.0) { + printf("Abort 1\n"); + abort(); + } + if (pi != &gi2 || pf != &gf2) { + printf("Abort 2\n"); + abort(); + } + if (!obj1 || obj1 != obj2) { + printf("Abort 3\n"); + abort(); + } + if (arg1 != 17 || arg2 != &gf2) { + printf("Abort 4\n"); + abort(); + } + } +} + +int main(void) { + foo(15, &gf1); + return 0; +} +#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/typedef-alias-1.mm b/gcc/testsuite/obj-c++.dg/typedef-alias-1.mm new file mode 100644 index 000000000..79db8765e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/typedef-alias-1.mm @@ -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/obj-c++.dg/va-meth-1.mm b/gcc/testsuite/obj-c++.dg/va-meth-1.mm new file mode 100644 index 000000000..c6aea14bc --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/va-meth-1.mm @@ -0,0 +1,75 @@ +/* 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 + +extern "C" int some_func(id self, SEL _cmd, int firstN, int secondN, int thirdN, ...) { + return firstN + secondN + thirdN; +} + +@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/obj-c++.dg/warn5.mm b/gcc/testsuite/obj-c++.dg/warn5.mm new file mode 100644 index 000000000..5f9b7a7f7 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/warn5.mm @@ -0,0 +1,25 @@ +/* Check to make sure that a c++ program compiled in objective-c++ mode + has no trace of meta-data specific diagnosis coming out of compiling it. + This is replicate of warn5.C. +*/ +// { dg-do assemble } +// { dg-options "-Wpointer-arith" } + +double X(const double x) { return x; } +double Y() { return 1.0; } +double Z() { return 2.0; } + +struct A { + void bar() { } + void foo() { } +}; + +typedef void (A::*pmf)(); + +static int mememe = &A::foo - &A::bar; // { dg-error "" } +pmf b = &A::foo-1; // { dg-error "" } + +int main() { + double y; + y=X(Y-Z); // { dg-error "" } +} |