Sphinx: Error with unnamed structs: WARNING: Invalid definition: Expected identifier in nested name.

Created on 15 Jun 2016  路  5Comments  路  Source: sphinx-doc/sphinx

Hello

The Sphinx parser, using doxygent input, seems to get confused by unnamed structures, used specially in nested unions / structs:

[from the Zephyr kernel in zephyrproject.org include/linux/i2c.h]

   union dev_config {
           uint32_t raw;
       struct {
                   uint32_t        use_10_bit_addr : 1;
           uint32_t        speed : 3;
           uint32_t        is_master_device : 1;
           uint32_t        is_slave_read : 1;
           uint32_t        reserved : 26;
       } bits;
   };

This will likely generate an error such as::

  doc/api/io_interfaces.rst:28: WARNING: Invalid definition: Expected identifier in nested name. [error at 19]
  struct dev_config::@61  dev_config::bits
  -------------------^

The simple workaround is to name that unnamed struct, with an internal name (such as ___bits_):

   union dev_config {
           uint32_t raw;
       struct __bits {
                   uint32_t        use_10_bit_addr : 1;
           uint32_t        speed : 3;
           uint32_t        is_master_device : 1;
           uint32_t        is_slave_read : 1;
           uint32_t        reserved : 26;
       } bits;
   };

Is this a bug or there is a way to use undocumented unions / structs?

cpp enhancement

Most helpful comment

Thanks for the suggestion; I toyed with that solution while researching this and it definitely does work for some cases.

However, there are cases where you want fully anonymous and you actually cannot name it (due to syntactic reasons); consider:

struct device {
    union {
         uint_t port;
         void *address;
    };
    int some_field;
    char *device_name
};

This would be and oversimplified structure describing the common parts of a device descriptor in a kernel, where depending on the hardware, it might be accessed by port (an IO port) or if mapped in memory, via a pointer to memory.

For syntactical correctness, you want the right type to feed to the right access functions. For space consideration (as you might have multiple device drivers sharing this system-wide definition) you want them to share space as only one of them is going to be use at the same time. Lastly, for code cleanliness, you don't want to add another name to the union because it makes names longer (hence the unnamed anonymous union).

It is a legal construct, widely used. I agree it seems counter intuitive. However, in the example given, the fields inside the union are basically considered fields of 'struct device' and the union basically is considered not to exist. The fields port and address are part of the struct device namespace.

All 5 comments

Currently there is no way to document anonymous entities in Sphinx, and it seems that either Doxygen or Breathe invents invalid identifiers for them (to avoid collisions I guess). I would recommend the non-solution of always give entities you want to document a name.
Otherwise, how should the documentation for an anonymous entity be rendered? and what name should we give it in order to generate links (without any chance of collisions)?

Thanks for the suggestion; I toyed with that solution while researching this and it definitely does work for some cases.

However, there are cases where you want fully anonymous and you actually cannot name it (due to syntactic reasons); consider:

struct device {
    union {
         uint_t port;
         void *address;
    };
    int some_field;
    char *device_name
};

This would be and oversimplified structure describing the common parts of a device descriptor in a kernel, where depending on the hardware, it might be accessed by port (an IO port) or if mapped in memory, via a pointer to memory.

For syntactical correctness, you want the right type to feed to the right access functions. For space consideration (as you might have multiple device drivers sharing this system-wide definition) you want them to share space as only one of them is going to be use at the same time. Lastly, for code cleanliness, you don't want to add another name to the union because it makes names longer (hence the unnamed anonymous union).

It is a legal construct, widely used. I agree it seems counter intuitive. However, in the example given, the fields inside the union are basically considered fields of 'struct device' and the union basically is considered not to exist. The fields port and address are part of the struct device namespace.

Hello Sphinx Team,

I am struggling with this issue since several weeks, entered https://github.com/michaeljones/breathe/issues/346 and has been finally pointed here. Currently I am getting such warnings for two structures that contain unnamed union esp_a2d_mcc_t and esp_bt_uuid_t .

There is minimum documentation site set up to demonstrate / test this issue and I am looking for any help to resolve it :smile:

There are several contributors to our documentation and I would like to filter out issues with updates by failing documentation build on warnings. Obviously the fist step is to eliminate "in born" warnings.

@eric-wieser @michaeljones @jakobandersen Any hope of handling these unnamed nested struct/union members better? We've got developers using these constructs more often across other projects and the resulting doxygen and sphinx/breathe output around these constructs is not usable. Obi-wan(s), you're our only hope.

This should now be fixed in the master branch (to become version 1.8). Any identifier starting with @ denotes an anonymous entity, but is rendered as [anonymous].

Was this page helpful?
0 / 5 - 0 ratings