NordicSemiconductor / zcbor

Low footprint C/C++ CBOR library and Python tool providing code generation from CDDL descriptions.
Apache License 2.0
114 stars 34 forks source link

Unamed union member when map item is given a choice #350

Closed jnz86 closed 7 months ago

jnz86 commented 1 year ago

A couple derivative issues here.

I wanted to include a choice of value options for an item in a map. The generated code is a little off.

CDDL:

test_vars = (
    test_length : "l" : uint .le 4096,
    test_data   : "d" : bstr,
    test_hash   : "h" : uint / int,
)

pl_selftest = {
    test_vars
}

Generated header:

struct test_vars_r {
    uint32_t test_length;
    struct zcbor_string test_data;
    union {
        uint32_t uint;
        int32_t Int;
    };
    enum {
        test_vars_test_hash_uint_c,
        test_vars_test_hash_int_c,
    } test_hash_choice;
};

struct pl_selftest {
    struct test_vars_r test_vars_m;
};

Issues:

(Also, as an aside, I am still not sure what the _r means, any help there?)

Using commit d1b4e0512c2783c5a4713f2b4b26c0d8c211b155

oyvindronningstad commented 1 year ago

Hi, thanks for taking the time.

There are no concrete plans to do anything about these, but I will keep it open for a while in case I e.g. do some naming fixes.

jnz86 commented 1 year ago

No wait, I think you didn't see the issue. I'm not questioning that if there is a choice then an int / uint, that isn't named a way that I didn't find sensible. It's not named at all. Which is legal because it's an anonymous union - legal once, but not twice.

See this change to add a second one:

test_vars = (
    test_len   : "l" : uint 4..4096,
    test_data  : "d" : bstr,
    test_hash  : "h" : uint / int,
    test_hash2  : "h2" : uint / int,
)
truct test_vars_r {
    uint32_t test_len;

    struct zcbor_string test_data;

    union {
        uint32_t uint;
        int32_t Int;
    };

    enum {
        test_vars_test_hash_uint_c,
        test_vars_test_hash_int_c,
    } test_hash_choice;

    union {
        uint32_t uint;
        int32_t Int;
    };

    enum {
        test_vars_test_hash2_uint_c,
        test_vars_test_hash2_int_c,
    } test_hash2_choice;
};

The first one is allowed to be an anonymous union. Where it should have taken the union name of test_hash in my opinion but did not. The second one is an error in C, duplicate member uint/Int, but of course won't be if it was named test_hash2.

This seems unintentional, no?

oyvindronningstad commented 1 year ago

Ah ok. I assume you're using --short-names. Currently --short-names is not guaranteed to give unique names, so the workaround for that is changing the CDDL or not using --short-names.

jnz86 commented 1 year ago

I see.

I’ll look into not using short names for this module. More importantly, I seems clear to me what the fix is here, that hash probably needs a name either way.

But, since no one wants me mucking about in their Python code. Best I can do is to point it out.