1

I found the following declaration in v0.9.2 of the ACE Radius library:

// Types of attribute data
typedef enum AttributeFormat_e
{
    E_ATTR_FORMAT_INTEGER,
    E_ATTR_FORMAT_IP_ADDRESS,
    E_ATTR_FORMAT_STRING,
    E_ATTR_FORMAT_VENDOR_SPECIFIC,
    E_ATTR_FORMAT_USER_PASSWORD,
    E_ATTR_FORMAT_CHAP_PASSWORD
};

That leading typedef is completely meaningless and should not be present.
Indeed, GCC emits the following diagnostic:

/usr/include/ace-radius/RadiusAttribute.h:597: warning: ‘typedef’ was ignored in this declaration

Now, this is ultimately harmless, despite being a bizarre sort of half-meaningful half-C declaration in a file that otherwise may only be parsed as C++ (the declaration is found as a private member in a class).

But purely out of curiosity I wanted to know whether this is strictly compliant, or strictly ill-formed, and couldn't quite tell from the standard.

Is this leading typedef legal? Or is GCC being permissive?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055

1 Answers1

9

It's legal, for the simple reason that there's no rule against it anywhere in the standard. The effect of typedef is only defined as what effect it has on names defined with the typedef specifier, so when there are no names defined with that specifier, the behaviour is well-defined: typedef simply has no effect.

The grammar in general does not require any declarators for a simple-declaration, and you probably already know this, since you would not have been surprised to see enum AttributeFormat_e { ... }; without the typedef. The productions are

simple-declaration:
    decl-specifier-seqopt init-declarator-listopt ;
    attribute-specifier-seq decl-specifier-seqopt init-declarator-list ;

As long as no attribute-specifier-seq is present in a simple-declaration, the init-declarator-list is optional.

typedef int; would be invalid, as would int; without the typedef, but that's a different rule: the rule there is that a declaration has to declare something. That rule doesn't apply to what's in your question, because that declaration does declare something. More precisely, C++11 [dcl.dcl]p3:

In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (Clause 9) or enumeration (7.2), that is, when the decl-specifier-seq contains either a class-specifier, an elaborated-type-specifier with a class-key (9.1), or an enum-specifier. [...]

The code in the question is declaring an enumeration, so this rule is not violated.

static enum E { x }; would be invalid, but that's another different rule: C++11 [dcl.stc]p1:

[...] If a storage-class-specifier appears in a decl-specifier-seq, there can be no typedef specifier in the same decl-specifier-seq and the init-declarator-list of the declaration shall not be empty (except for an anonymous union declared in a named namespace or in the global namespace, which shall be declared static (9.5)). [...]

const enum E { x }; would also be invalid, but that's a third different rule: C++11 [dcl.type.cv]p1:

[...] If a cv-qualifier appears in a decl-specifier-seq, the init-declarator-list of the declaration shall not be empty. [...]

There is simply no such rule anywhere for typedef.

  • This doesn't seem like a good argument. The standard is not "anything is legal as long as it's not made illegal", and you haven't pointed out the feature of `typedef` (or the fact of its grammar production) that allows the "target name" to be emitted. I'm looking for something a bit more concrete than "it's just legal, mmkay?" – Lightness Races in Orbit Jan 16 '15 at 11:44
  • 1
    @LightnessRacesinOrbit You already know very well that the grammar allows declarations without any declarators. That's how `enum AttributeFormat_e { ... };` without the `typedef` would be valid. But I will elaborate a bit. –  Jan 16 '15 at 11:45
  • Can you tell us which grammar productions cover this? Your answer is still "there's nothing to ban it" well great but _something_ defines it, even if passively. – Lightness Races in Orbit Jan 16 '15 at 12:26
  • 1
    @LightnessRacesinOrbit Sure, edited. Does that cover it? –  Jan 16 '15 at 12:30
  • 1
    Aha! Yes, I think that probably does. It's still not very satisfying but that's C++'s fault, not yours. Thanks for your time – Lightness Races in Orbit Jan 16 '15 at 12:43
  • I had to make a C++ parser to extract some `typedef struct tag {...} NAME, *PNAME;` declarations. I based my parser rules on those of the old lex/yacc C grammar. I was very baffled by the rule in regard with "typedef": `storage_class_spec : 'auto' | 'register' | 'static' | 'extern' | 'typedef'`. Yeah, you can have several typedef! mixed with the others! I wonder if that weird rule is still the same for c++ grammar? – hlide Jan 18 '15 at 16:23
  • 1
    @hlide Neither C nor C++ allows `typedef` to be mixed with (other) storage class specifiers. The grammar allows it, but the semantics don't. C says "At most, one storage-class specifier may be given in the declaration specifiers in a declaration." And in C++, `typedef` is not a storage class specifier, and the rule is written as "The typedef specifier shall not be combined in a decl-specifier-seq with any other kind of specifier except a type-specifier." Note: `typedef` *can* appear along with `extern` if the latter is part of a linkage-specification: `extern "C" typedef void f();` is valid. –  Jan 18 '15 at 16:36
  • @hvd Good to hear. The fact is you cannot trust a free-context C/C++ grammar parsing to validate source or detect ill-constructed declaration. – hlide Jan 18 '15 at 16:46