1/* { dg-do run } */
2/* See if -forward:: is able to work. */
3/* { dg-skip-if "Needs OBJC2 Implementation" { *-*-darwin8* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
4/* { dg-additional-options "-Wl,-framework,Foundation" { target *-*-darwin* } } */
5#include <stdio.h>
6#include <stdlib.h>
7
8/* Versions of the runtime after 10.13 no longer support the original
9   'forward:' mechanism, so we make a stripped down representation of
10   NSInvocation and need to link with -framework Foundation.  */
11#if __NEXT_RUNTIME__
12@class  NSInvocation, NSMethodSignature;
13# include "../../objc-obj-c++-shared/F-NSObject.h"
14@interface NSInvocation : NSObject
15+ (NSInvocation *)invocationWithMethodSignature:(NSMethodSignature *)sig;
16@property SEL selector;
17- (void)invoke;
18- (void)invokeWithTarget:(id)target;
19@end
20# define OBJECT NSObject
21#else
22#include "../../objc-obj-c++-shared/TestsuiteObject.m"
23#define OBJECT TestsuiteObject
24#endif
25
26#define VALUETOUSE 1234567890
27
28id forwarder, receiver;
29
30@interface Forwarder : OBJECT
31{
32    id receiver;
33}
34
35-initWithReceiver:theReceiver;
36#if __NEXT_RUNTIME__
37- (void)forwardInvocation:(NSInvocation *)anInvocation;
38- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
39#endif
40
41@end
42
43@interface Receiver : OBJECT
44{
45    int foo;
46}
47-display;
48-initWithFoo:(int)theFoo;
49@end
50
51@implementation Receiver
52
53-initWithFoo: (int)theFoo
54{
55    foo = theFoo;
56    return self;
57}
58
59-display
60{
61  printf ("Executing display\n");
62    /* Check to see if we are really the reciever. */
63    if (self != receiver)
64        abort ();
65    /* And the value of foo is set correctly. */
66    if (foo != VALUETOUSE)
67      abort ();
68    return self;
69}
70
71@end
72
73@implementation Forwarder
74-initWithReceiver: theReceiver
75{
76    [super init];
77    receiver = theReceiver;
78    return self;
79}
80
81#if __NEXT_RUNTIME__
82- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSel
83{
84 return [receiver methodSignatureForSelector:aSel];
85}
86- (void)forwardInvocation:(NSInvocation *)anInvocation
87{
88    if ([receiver respondsToSelector:[anInvocation selector]]) {
89        [anInvocation invokeWithTarget:receiver];
90    }
91    else {
92    }
93}
94#else
95-(void *) forward:(SEL)theSel : (void *)theArgFrame
96{
97  /* If we have a reciever try to perform on that object */
98    if (receiver)
99      {
100	/* Simple forward that works for methods with no
101	   arguments.  */
102	typedef id (*method_with_no_args) (id receiver, SEL _cmd);
103	Method method = class_getInstanceMethod (object_getClass (receiver),
104						 theSel);
105	method_with_no_args imp = (method_with_no_args)(method_getImplementation
106							(method));
107	return (*imp)(receiver, theSel);
108      }
109
110    /* Normally you'd emit an error here.  */
111    printf ("Unrecognized selector\n");
112    return NULL;
113}
114#endif
115
116@end
117int main()
118{
119    /* Init the reciever. */
120    receiver = [[Receiver alloc] initWithFoo: VALUETOUSE];
121    /* Init the fowarder. */
122    forwarder = [[Forwarder alloc] initWithReceiver: receiver];
123    /* Call display on the forwarder which in turns calls display on
124       the reciever. */
125    [forwarder display];
126    exit(0);
127}
128