/* APPLE LOCAL file radar 4426814 */
/* A run-time test for insertion of read barriers for __weak objects. */

/* { dg-do run { target powerpc*-*-darwin* i?86*-*-darwin* } } */
/* { dg-options "-fnext-runtime -fobjc-gc" } */

#include <objc/objc.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct __CFDictionary * CFDictionaryRef;

// callouts to these are generated with cc -fobjc-gc

int GlobalReads;

static
id objc_read_weak(id *value) {
  ++GlobalReads;
  return *value;
}

static
id objc_assign_weak(id value, id *dest) {
  /* APPLE LOCAL radar 5276085 */
  return (*dest = value);
}


// The test case elements;
@class NSObject;
@class NSString;

@interface Foo  {
@public
// read of  __weak fields should generate objc_read_weak
  __weak CFDictionaryRef dict;
  __weak CFDictionaryRef dictArray[3];
  __weak id ivar;
  __weak id array[10];
  __weak NSObject *nsobject;
  __weak NSString *stringArray[10];
}
@end

@implementation Foo
- (void)message {}
- (void)message1 : (id)arg {}
@end

#define READTEST(expr, count)	if (GlobalReads != count) { printf(# expr " is busted\n"); ++counter; } --GlobalReads;

id get_id()
{
  static id x;
  return (id)&x;
}

int testGlobals() {
  // Everything in this function generates objc_assign_weak intercepts
  int counter = 0;

  static __weak id staticGlobalId = 0;
  static __weak id staticGlobalArray[20] = {0};
  static __weak NSObject *staticGlobalObject;
  static __weak NSObject *staticGlobalObjectArray[20];
  static __weak CFDictionaryRef staticGdict;
  static __weak CFDictionaryRef staticGdictarray[10] = {0,0,0};


  if (!staticGlobalId)
    READTEST(staticGlobalId,1);

  if (!staticGlobalArray[0])
    READTEST(staticGlobalArray[0],1);

  staticGlobalObject = get_id();

  if (staticGlobalObject)
    READTEST(staticGlobalObject,1);

  staticGdict = (CFDictionaryRef)get_id();
  if (staticGlobalId || staticGdictarray[1] || staticGdict)
    {
	READTEST(staticGlobalId,3);
	READTEST(staticGlobalArray[1],2);
	READTEST(staticGdict,1);
    }

  return counter;
}


int testIvars() {
  int counter = 0;
  Foo *foo = (Foo *)calloc(sizeof(Foo), 1); // don't call in ObjC

  if (!foo->ivar)
    READTEST(foo->ivar, 1);
  if (!foo->dict)
    READTEST(foo->dict, 1);

  foo->ivar = get_id();
  if (foo->dict || foo->dictArray[0] || foo->stringArray[0] || foo->ivar)
    {
  	READTEST(foo->dict, 4);			
  	READTEST(foo->dictArray[0], 3);	
  	READTEST(foo->stringArray[0], 2);
  	READTEST(foo->ivar, 1);	
    }

  [foo->array[0] message];
  READTEST(foo->array, 1);
    
  [foo->array[0] message1 : foo->ivar];
  READTEST(foo->array, 2);

  return counter;
}

int main(int argc, char *argv[]) {
  int errors = 0;
  errors += testGlobals();
  errors += testIvars();
  return (errors);
}
