/+
REQUIRED_ARGS: -HC -c -o-
PERMUTE_ARGS:
TEST_OUTPUT:
---
// Automatically generated by Digital Mars D Compiler

#pragma once

#include <assert.h>
#include <math.h>
#include <stddef.h>
#include <stdint.h>

#ifdef CUSTOM_D_ARRAY_TYPE
#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
#else
/// Represents a D [] array
template<typename T>
struct _d_dynamicArray final
{
    size_t length;
    T *ptr;

    _d_dynamicArray() : length(0), ptr(NULL) { }

    _d_dynamicArray(size_t length_in, T *ptr_in)
        : length(length_in), ptr(ptr_in) { }

    T& operator[](const size_t idx) {
        assert(idx < length);
        return ptr[idx];
    }

    const T& operator[](const size_t idx) const {
        assert(idx < length);
        return ptr[idx];
    }
};
#endif

struct Outer final
{
    static Outer* outerPtr;
    static Middle::Inner* outerToInnerPtr;
    static Middle::InnerTmpl<int32_t >* outerToInnerTmplPtr;
    struct Middle final
    {
        static Outer* middleOuterPtr;
        static Middle* middlePtr;
        static Inner* middleInnerPtr;
        struct Inner final
        {
            static Outer* innerOuterPtr;
            static Middle* innerPtr;
            static Inner* innerInnerPtr;
            static InnerTmpl<int32_t >* innerInnerTmplPtr;
            Inner()
            {
            }
        };

        template <typename U>
        struct InnerTmpl final
        {
            static Outer* innerTmplOuterPtr;
            static Middle* innerTmplPtr;
            static Inner* innerTmplInnerPtr;
            static InnerTmpl* innerTmplInnerTmplPtr;
            InnerTmpl()
            {
            }
        };

        Middle()
        {
        }
    };

    template <typename T>
    struct MiddleTmpl final
    {
        static MiddleTmpl<T >* middleTmplPtr;
        static MiddleTmpl<T >* middleTmplInnerTmplPtr;
        struct Inner final
        {
            static Inner* ptr;
            static MiddleTmpl<T >* ptr2;
            Inner()
            {
            }
        };

        template <typename U>
        struct InnerTmpl final
        {
            static InnerTmpl* innerTmplPtr;
            static InnerTmpl<char >* innerTmplPtrDiff;
            static MiddleTmpl<T >* middleTmplInnerTmplPtr;
            static T a;
            static U bar();
            InnerTmpl()
            {
            }
        };

        MiddleTmpl()
        {
        }
    };

    Outer()
    {
    }
};

---
+/

extern(C++):

struct Outer
{
    __gshared Outer* outerPtr;
    __gshared Middle.Inner* outerToInnerPtr;
    __gshared Middle.InnerTmpl!int* outerToInnerTmplPtr;

    static struct Middle
    {
        __gshared Outer* middleOuterPtr;
        __gshared Middle* middlePtr;
        __gshared Inner* middleInnerPtr;

        static struct Inner
        {
            __gshared Outer* innerOuterPtr;
            __gshared Middle* innerPtr;
            __gshared Inner* innerInnerPtr;
            __gshared InnerTmpl!int* innerInnerTmplPtr;
        }

        static struct InnerTmpl(U)
        {
            __gshared Outer* innerTmplOuterPtr;
            __gshared Middle* innerTmplPtr;
            __gshared Inner* innerTmplInnerPtr;
            __gshared InnerTmpl* innerTmplInnerTmplPtr;
        }
    }

    static struct MiddleTmpl(T)
    {
        __gshared MiddleTmpl!T* middleTmplPtr;
        __gshared MiddleTmpl!T.Inner* middleTmplInnerTmplPtr;

        static struct Inner
        {
            __gshared Inner* ptr;
            __gshared MiddleTmpl!T.Inner* ptr2;
        }

        static struct InnerTmpl(U)
        {
            __gshared InnerTmpl* innerTmplPtr;
            __gshared InnerTmpl!char* innerTmplPtrDiff;
            __gshared MiddleTmpl!T.Inner* middleTmplInnerTmplPtr;

            __gshared T a;
            static U bar() { return U.init; }
        }
    }
}

/+
TEST_OUTPUT:
---
extern Outer::Middle::Inner inner;

extern Outer::Middle::InnerTmpl<int32_t > innerTmpl;

extern Outer::MiddleTmpl<int32_t >::Inner middleTmpl;

extern Outer::MiddleTmpl<int32_t >::InnerTmpl<double > bothTmpl;

---
+/

__gshared Outer.Middle.Inner inner;

__gshared Outer.Middle.InnerTmpl!int innerTmpl;

__gshared Outer.MiddleTmpl!int.Inner middleTmpl;

__gshared Outer.MiddleTmpl!int.InnerTmpl!double bothTmpl;

/+
TEST_OUTPUT:
---
typedef Outer::MiddleTmpl<int32_t >::InnerTmpl<double > FullTmplInst;

template <typename U>
using FullTmpl = Outer::MiddleTmpl<int32_t >::InnerTmpl<U>;
---
+/

alias FullTmplInst = Outer.MiddleTmpl!int.InnerTmpl!double;

alias FullTmpl = Outer.MiddleTmpl!int.InnerTmpl;

/+
TEST_OUTPUT:
---
extern void dotId(int32_t a = Outer::MiddleTmpl<int32_t >::InnerTmpl<double >::a);

---
+/

void dotId( int a = Outer.MiddleTmpl!int.InnerTmpl!double.a ) {}

/+
TEST_OUTPUT:
---
extern void castExp(double a = (double) Outer::MiddleTmpl<int32_t >::InnerTmpl<double >::a);

---
+/

void castExp( double a = Outer.MiddleTmpl!int.InnerTmpl!double.a ) {}

/+
TEST_OUTPUT:
---
extern void structLit(Outer::MiddleTmpl<int32_t >::InnerTmpl<double > a = Outer::MiddleTmpl<int32_t >::InnerTmpl<double >());

---
+/

void structLit( Outer.MiddleTmpl!int.InnerTmpl!double a = Outer.MiddleTmpl!int.InnerTmpl!double() ) {}

/+
TEST_OUTPUT:
---
extern void callExp(double a = Outer::MiddleTmpl<int32_t >::InnerTmpl<double >::bar());

---
+/

void callExp( double a = Outer.MiddleTmpl!int.InnerTmpl!double.bar() ) {}
