// REQUIRED_ARGS: -preview=dip1021

/* Should compile successfully
 */


struct Allocation {
    int* ptr;
    size_t length;
}

void canFind(scope Allocation);

int* malloc();
void free(int*);
void pitcher();
void borrow(scope int*);
void borrow2c(const scope int*, const scope int*);
void out1(out int*);


/*****************************/

@live int* foo1(int* p)
{
    return p;   // consumes owner
}

@live int* foo2()
{
    int* p = null;
    return p;      // consumes owner
}

@live int* foo3(int* p)
{
    scope int* q = p;  // borrows from p
    return p;          // use of p ends borrow in q
}

@live int* foo4(int* p)
{
    scope int* bq = p;          // borrow
    scope const int* cq = p;    // const borrow
    return p;                   // ends both borrows
}

/*******************************/

@live void foo5()
{
    auto p = malloc();
    scope(exit) free(p);
    pitcher();
}

/*******************************/

void deallocate(int* ptr, size_t length) @live
{
    canFind(Allocation(ptr, length)); // canFind() borrows ptr
    free(ptr);
}


/*******************************/


@live int* test1()
{
    auto p = malloc();
    scope b = p;
    return p;
}

@live int* test2()
{
    auto p = malloc();
    auto q = p;
    return q;
}

@live void test3()
{
    auto p = malloc();
    free(p);
}

@live void test4()
{
    auto p = malloc();
    borrow(p);
    free(p);
}

@live void test5()
{
    auto p = malloc();
    scope q = p;
    borrow2c(p, p);
    free(p);
}

@live void test6()
{
    int* p = void;
    out1(p);  // initialize
    free(p);  // consume
}


/*******************************/

void zoo1(int);

@live void zoo2() {
    int* p = malloc();
    zoo1(*p);  // does not consume p
    free(p);
}

@live void zoo3() {
    int** p = cast(int**)malloc();
    free(*p); // consumes p
}

@live void zoo4() {
    int[] a = malloc()[0 .. 1];
    zoo1(a[0]);  // does not consume a
    free(a.ptr); // consumes a
}

@live void zoo5() {
    int*[] a = (cast(int**)malloc())[0 .. 1];
    free(a[0]); // consumes a
}

struct S { int i; int* p; }

@live void zoo6() {
    S* s = cast(S*)malloc();
    zoo1(s.i);    // does not consume s
    free(cast(int*)s);
}

@live void zoo7() {
    S* s = cast(S*)malloc();
    free(s.p);    // consumes s
}
