version (LDC)
{
    // no DMD-specific section-bracketing symbols
}
else version(CRuntime_Microsoft)
{
    extern(C)
    {
        extern __gshared uint _DP_beg;
        extern __gshared uint _DP_end;
        extern __gshared uint _TP_beg;
        extern __gshared uint _TP_end;
    }
    alias _DPbegin = _DP_beg;
    alias _DPend = _DP_end;
    alias _TPbegin = _TP_beg;
    alias _TPend = _TP_end;

    __gshared void[] dataSection;
    shared static this()
    {
        import core.internal.traits : externDFunc;
        alias findImageSection = externDFunc!("rt.sections_win64.findImageSection",
                                              void[] function(string name) nothrow @nogc);
        dataSection = findImageSection(".data");
    }

    void[] tlsRange;
    static this()
    {
        import core.internal.traits : externDFunc;
        alias initTLSRanges = externDFunc!("rt.sections_win64.initTLSRanges",
                                              void[] function() nothrow @nogc);
        tlsRange = initTLSRanges();
    }

    version = ptrref_supported;
}
else version(Win32)
{
    extern(C)
    {
        extern __gshared void* _DPbegin;
        extern __gshared void* _DPend;
        extern __gshared uint _TPbegin;
        extern __gshared uint _TPend;
        extern int _tlsstart;
        extern int _tlsend;
    }

    void[] tlsRange;
    static this()
    {
		tlsRange = (cast(void*)&_tlsstart)[0.. cast(void*)&_tlsend - cast(void*)&_tlsstart];
	}

    version = ptrref_supported;
}

struct Struct
{
    int x;
    Struct* next;
}

class Class
{
    void* ptr;
}

struct Struc(T)
{
	static T vtls;
	static __gshared T vgshared;
}

__gshared Struct* gsharedStrctPtr2 = new Struct(7, new Struct(8, null));

int tlsInt;
void* tlsVar;

shared int sharedInt;
shared void* sharedVar;
__gshared void* gsharedVar;
__gshared void* gsharedVar2;
immutable int[] arr = [1, 2, 3];
string tlsStr;

__gshared Struct gsharedStrct;
Struct[3] tlsStrcArr;
Class tlsClss;

// expression initializers
string[] strArr = [ "a", "b" ];
__gshared Class gsharedClss = new Class;
__gshared Struct* gsharedStrctPtr = new Struct(7, new Struct(8, null));

debug(PRINT) import core.stdc.stdio;

void main()
{
    version(ptrref_supported)
        testRefPtr();
}

version(ptrref_supported):

bool findTlsPtr(const(void)* ptr)
{
    debug(PRINT) printf("findTlsPtr %p\n", ptr);
    for (uint* p = &_TPbegin; p < &_TPend; p++)
    {
        void* addr = tlsRange.ptr + *p;
        debug(PRINT) printf("  try %p\n", addr);
        assert(*p < tlsRange.length);
        if (addr == ptr)
            return true;
    }
    return false;
}

bool findDataPtr(const(void)* ptr)
{
    debug(PRINT) printf("findDataPtr %p\n", ptr);
    for (auto p = &_DPbegin; p < &_DPend; p++)
    {
        debug(PRINT) printf("  try %p\n", cast(void*) cast(size_t) *p);
        version(CRuntime_Microsoft)
            void* addr = dataSection.ptr + *p;
        else
            void* addr = *p;

        if (addr == ptr)
            return true;
    }
    return false;
}

void testRefPtr()
{
    debug(PRINT) printf("&_DPbegin %p\n", &_DPbegin);
    debug(PRINT) printf("&_DPend   %p\n", &_DPend);

    debug(PRINT) printf("&_TPbegin %p\n", &_TPbegin);
    debug(PRINT) printf("&_TPend   %p\n", &_TPend);

    assert(!findDataPtr(cast(void*)&sharedInt));
    assert(!findTlsPtr(&tlsInt));

    assert(findDataPtr(cast(void*)&sharedVar));
    assert(findDataPtr(&gsharedVar));
    assert(findDataPtr(&gsharedStrct.next));
    assert(findDataPtr(&(gsharedClss)));
    assert(findDataPtr(&(gsharedClss.ptr)));

    assert(findTlsPtr(&tlsVar));
    assert(findTlsPtr(&tlsClss));
    assert(findTlsPtr(&tlsStrcArr[0].next));
    assert(findTlsPtr(&tlsStrcArr[1].next));
    assert(findTlsPtr(&tlsStrcArr[2].next));

    assert(!findTlsPtr(cast(size_t*)&tlsStr)); // length
    assert(findTlsPtr(cast(size_t*)&tlsStr + 1)); // ptr

    // monitor is manually managed
    assert(!findDataPtr(cast(size_t*)cast(void*)Class.classinfo + 1));
    assert(!findDataPtr(cast(size_t*)cast(void*)Class.classinfo + 1));

    assert(!findDataPtr(&arr));
    assert(!findTlsPtr(&arr));
    assert(!findDataPtr(cast(size_t*)&arr + 1));
    assert(!findTlsPtr(cast(size_t*)&arr + 1));

    assert(findDataPtr(cast(size_t*)&strArr[0] + 1)); // ptr in _DATA!
    assert(findDataPtr(cast(size_t*)&strArr[1] + 1)); // ptr in _DATA!
    strArr[1] = "c";

    assert(findDataPtr(&gsharedStrctPtr));
    assert(findDataPtr(&gsharedStrctPtr.next));
    assert(findDataPtr(&gsharedStrctPtr.next.next));

    assert(findDataPtr(&(Struc!(int*).vgshared)));
    assert(!findDataPtr(&(Struc!(int).vgshared)));
    assert(findTlsPtr(&(Struc!(int*).vtls)));
    assert(!findTlsPtr(&(Struc!(int).vtls)));
}
