June 02, 2019
https://issues.dlang.org/show_bug.cgi?id=19935

          Issue ID: 19935
           Summary: hasUDA and getUDAs ignore UDA with a custom string
                    type
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Windows
            Status: NEW
          Severity: major
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: simon.vanbernem@yahoo.de

I observe very weird behaviour, when attaching a UDA to a variable. The type of the UDA contains a member of a custom string type, which seems to cause the issue. Both hasUDA and getUDA don't recognize the existence of said UDA. When using a UDA of a type that does not contain my custom string type, but just the builtin one, hasUDA and getUDA don't have a problem (see Attribute1 and Attribute2 structs).

When attaching the problematic UDA to a variable without initializing the member, hasUDA and getUDA find it. Below is the repro-program and the compiler output.

------------PROGRAM------------------------

struct My_String{
        long size;
        char* data;
}

My_String make_my_string(string s){
        My_String my_string;
        my_string.data = cast(char*) s.ptr;
        my_string.size = s.length;
        return my_string;
}

struct Attribute1{
        My_String s;
}

struct Attribute2{
        string s;
}

import std.traits;

void main(){
        @Attribute1(make_my_string("foo")) int a;

        pragma(msg, "\n", __traits(getAttributes, a));
        pragma(msg, hasUDA!(a, Attribute1));
        pragma(msg, getUDAs!(a, Attribute1), "\n");

        @Attribute2("foo") int b;

        pragma(msg, __traits(getAttributes, b));
        pragma(msg, hasUDA!(b, Attribute2));
        pragma(msg, getUDAs!(b, Attribute2), "\n");

        @Attribute1() int c;

        pragma(msg, __traits(getAttributes, c));
        pragma(msg, hasUDA!(c, Attribute1));
        pragma(msg, getUDAs!(c, Attribute1), "\n");
}

------------OUTPUT------------------------

tuple(Attribute1(My_String(3L, &"foo"[0])))
false
()

tuple(Attribute2("foo"))
true
tuple(Attribute2("foo"))

tuple(Attribute1(My_String(0L, null)))
true
tuple(Attribute1(My_String(0L, null)))

--