View mode: basic / threaded / horizontal-split · Log in · Help
February 15, 2007
Suggestion: class/struct tuples preserve anonymous unions/structs
If you write something like this:

struct S
{
   int x;

   union U
   {
       int a;
       int b;
   }

   U u;
}

And print out its field types:

foreach(T; FieldTypeTuple!(S))
   writefln(typeid(T));

It will print out

int
test.S.U

But if you make the union anonymous:

struct S
{
   int x;

   union
   {
       int a;
       int b;
   }
}

The output becomes:

int
int
int

The anonymous union is getting "flattened out" by the type tuple mechanism.

This messes up some automation features.  For example I'm trying to write a 
simple "Serialize" function which can serialize entire structs.  But unions 
can't be automatically serialized, since the Serialize function has no idea 
which member of the union is currently "valid."  So I have error checking to 
disallow serializing unions, but since the .tupleof facility flattens out 
anonymous unions, it can't check for errors (and therefore I don't know that 
there's a problem until I write the struct out to a file and end up with a 
bunch of invalid members, since they came from the anonymous union).

I'm not sure how anonymous unions and structs are handled by the compiler. 
If they are created as "secret" types, would it then be possible for the 
above struct with the anonymous union to consist of:

int
test.S.__UNION0

or something like that?
February 15, 2007
Re: Suggestion: class/struct tuples preserve anonymous unions/structs
Jarrett Billingsley wrote:
> The anonymous union is getting "flattened out" by the type tuple mechanism.
> 
> This messes up some automation features.  For example I'm trying to write a 
> simple "Serialize" function which can serialize entire structs.  But unions 
> can't be automatically serialized, since the Serialize function has no idea 
> which member of the union is currently "valid."  So I have error checking to 
> disallow serializing unions, but since the .tupleof facility flattens out 
> anonymous unions, it can't check for errors (and therefore I don't know that 
> there's a problem until I write the struct out to a file and end up with a 
> bunch of invalid members, since they came from the anonymous union).
> 
> I'm not sure how anonymous unions and structs are handled by the compiler. 
> If they are created as "secret" types, would it then be possible for the 
> above struct with the anonymous union to consist of:
> 
> int
> test.S.__UNION0
> 
> or something like that? 

I don't think it's being "flattened out" by the type tuple mechanism, I 
think it happens *before* that. They're not created as secret types, 
they just seem to use different rules for offset calculation.
I'm not really sure whether or not this is a bug in the compiler, but it 
happens.

The following template can be used to check for unions (anonymous and 
named) and generate compile errors when it finds any:
-----
/** static asserts when T is a union or contains unions.
 *  Note: the 'Idx' parameter should be left at the default by
 *        code outside the template.
 */
template validate(T, size_t Idx = 0) {
    static assert(!is(T == union), T.stringof ~ " is a union itself!");
    static assert(!is(typeof(T.tupleof)[Idx] == union),
        "Member " ~ Idx.stringof ~ " of " ~ T.stringof ~ " is a union");

    static if (Idx + 1 < T.tupleof.length) {
        // check overlap caused by anonymous union members
        static assert(T.tupleof[Idx].offsetof + T.tupleof[Idx].sizeof 
<= T.tupleof[Idx + 1].offsetof,
            "Member " ~ Idx.stringof ~ " of " ~ T.stringof ~ " overlaps 
the next member");
        // and check the other members
        mixin validate!(T, Idx + 1);
    }

    static if (Idx < T.tupleof.length) {
        // Recurse into member structs
        static if (is(typeof(T.tupleof)[Idx] == struct))
            mixin validate!(typeof(T.tupleof)[Idx]);

        // uncomment these lines to recurse into member class 
references as well:
        //else static if (is(typeof(T.tupleof)[Idx] == class))
        //    mixin validate!(typeof(T.tupleof)[Idx]);
    }
}


//
// Some test code:
//

struct SAnonUnion
{
    int x;

    union
    {
        int a;
        int b;
    }
}
struct SUnion
{
    int x;

    union U
    {
        int a;
        int b;
    }
    U u;
}

struct SValid
{
    int x;

    int a;
    int b;
}

class Class { SUnion u; }

struct SNested
{
    Class u;
}

void main()
{
    //mixin validate!(SAnonUnion);    // error :)
    //mixin validate!(SUnion);        // error :)
    mixin validate!(SNested);       // error if class references are 
followed, or 'Class' is changed to a struct
    mixin validate!(SValid);
}
-----
(You may have to correct some line wrapping before it'll compile)
February 15, 2007
Re: Suggestion: class/struct tuples preserve anonymous unions/structs
"Frits van Bommel" <fvbommel@REMwOVExCAPSs.nl> wrote in message 
news:er1cc3$3sr$1@digitalmars.com...
>
> I don't think it's being "flattened out" by the type tuple mechanism, I 
> think it happens *before* that. They're not created as secret types, they 
> just seem to use different rules for offset calculation.
> I'm not really sure whether or not this is a bug in the compiler, but it 
> happens.

I was kind of worried about that.  Well we can hope..

> template validate(T, size_t Idx = 0) {
>     static assert(!is(T == union), T.stringof ~ " is a union itself!");
>     static assert(!is(typeof(T.tupleof)[Idx] == union),
>         "Member " ~ Idx.stringof ~ " of " ~ T.stringof ~ " is a union");
>
>     static if (Idx + 1 < T.tupleof.length) {
>         // check overlap caused by anonymous union members
>         static assert(T.tupleof[Idx].offsetof + T.tupleof[Idx].sizeof <= 
> T.tupleof[Idx + 1].offsetof,
>             "Member " ~ Idx.stringof ~ " of " ~ T.stringof ~ " overlaps 
> the next member");
>         // and check the other members
>         mixin validate!(T, Idx + 1);
>     }
>
>     static if (Idx < T.tupleof.length) {
>         // Recurse into member structs
>         static if (is(typeof(T.tupleof)[Idx] == struct))
>             mixin validate!(typeof(T.tupleof)[Idx]);
>
>         // uncomment these lines to recurse into member class references 
> as well:
>         //else static if (is(typeof(T.tupleof)[Idx] == class))
>         //    mixin validate!(typeof(T.tupleof)[Idx]);
>     }
> }

Thanks for this :)  I was thinking it might be possible to check the 
.offsetofs.
February 15, 2007
Re: Suggestion: class/struct tuples preserve anonymous unions/structs
Jarrett Billingsley wrote:
[snip code]
> 
> Thanks for this :)  I was thinking it might be possible to check the 
> .offsetofs. 

Something I just thought of: that code doesn't take typedefs into 
account. That loophole can be closed by using is(T Base == typedef) and 
inspecting Base recursively if it evaluates to true. Implementing this 
is left as an exercise to the reader ;).
February 15, 2007
Re: Suggestion: class/struct tuples preserve anonymous unions/structs
"Frits van Bommel" <fvbommel@REMwOVExCAPSs.nl> wrote in message 
news:er1ost$mae$1@digitalmars.com...
> Jarrett Billingsley wrote:
> [snip code]
>>
>> Thanks for this :)  I was thinking it might be possible to check the 
>> .offsetofs.
>
> Something I just thought of: that code doesn't take typedefs into account. 
> That loophole can be closed by using is(T Base == typedef) and inspecting 
> Base recursively if it evaluates to true. Implementing this is left as an 
> exercise to the reader ;).

WAITWaitwaitwait.  When the *hell* was .stringof added?

:D
February 15, 2007
Re: Suggestion: class/struct tuples preserve anonymous unions/structs
"Jarrett Billingsley" <kb3ctd2@yahoo.com> wrote in message 
news:er1s3r$qqa$1@digitalmars.com...

> WAITWaitwaitwait.  When the *hell* was .stringof added?
>
> :D

I guess I missed the mini-conversation in the DMD 1.005 thread.. man!  What 
a cool feature :)
February 15, 2007
Re: Suggestion: class/struct tuples preserve anonymous unions/structs
Jarrett Billingsley wrote:
> "Jarrett Billingsley" <kb3ctd2@yahoo.com> wrote in message 
> news:er1s3r$qqa$1@digitalmars.com...
> 
>> WAITWaitwaitwait.  When the *hell* was .stringof added?
>>
>> :D
> 
> I guess I missed the mini-conversation in the DMD 1.005 thread.. man!  What 
> a cool feature :) 

Yes it is :).
It's not really essential here though, I just used it to provide more 
readable error messages for assertion failures...
February 15, 2007
Re: Suggestion: class/struct tuples preserve anonymous unions/structs
Jarrett Billingsley wrote:
> I'm not sure how anonymous unions and structs are handled by the compiler. 

This has nothing to do with tuples. Anonymous structs and unions are 
used for layout only, the members are 'promoted' into the enclosing 
aggregate.
February 15, 2007
Re: Suggestion: class/struct tuples preserve anonymous unions/structs
Walter Bright wrote:
> Jarrett Billingsley wrote:
>> I'm not sure how anonymous unions and structs are handled by the 
>> compiler. 
> 
> This has nothing to do with tuples. Anonymous structs and unions are 
> used for layout only, the members are 'promoted' into the enclosing 
> aggregate.

It's fairly obvious this is what's happening. And normally this wouldn't 
matter as you wouldn't be able see the difference, but because of 
.tupleof this is now detectable.
I think the real question here is: while this may be what *is* 
happening, is this also what *should* happen? (i.e. "Is this a bug?")
I can't find anything specifying this behavior in the spec...
February 15, 2007
Re: Suggestion: class/struct tuples preserve anonymous unions/structs
Frits van Bommel wrote:
> Walter Bright wrote:
>> Jarrett Billingsley wrote:
>>> I'm not sure how anonymous unions and structs are handled by the 
>>> compiler. 
>>
>> This has nothing to do with tuples. Anonymous structs and unions are 
>> used for layout only, the members are 'promoted' into the enclosing 
>> aggregate.
> 
> It's fairly obvious this is what's happening. And normally this wouldn't 
> matter as you wouldn't be able see the difference, but because of 
> ..tupleof this is now detectable.
> I think the real question here is: while this may be what *is* 
> happening, is this also what *should* happen? (i.e. "Is this a bug?")
> I can't find anything specifying this behavior in the spec...

I think as long as .offsetof can be obtained for the values then 
everything should be fine.  You know members are part of a union when 
their .offsetof is the same.


Sean
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home