kendall@wjh12.UUCP (Kendall) (08/26/83)
Once a name has been defined as a typedef type, it is very difficult to redeclare it in an inner block. The manual states (section 8.8), Within the scope of a declaration, each identifier appearing as part of any declarator therein become [sic] syntactically equivalent to the type keyword naming the type associated with the identifier .... This statement has a couple of exceptions. (1) struct/union/enum tags are in a seperate namespace and do not conflict with typedef names. It is common practice, and reasonable, to depend on this. struct/union member names seem to work the same way in the Ritchie and Portable compilers. (2) In both compilers, one can redeclare a typedef name in the normal namespace, and in an inner scope, (only) by redeclaring the name as either a formal parameter or an enum member. I guess one is allowed to redeclare a typedef name in those contexts because it is syntactically unambiguous to do so. The way I see it, exception (1) is a reasonable exception, and should be viewed as an omission in the manual. Exception (2), however, strikes me as a compiler bug, even in both compilers. It is a strange thing to depend on, particularly since lint will complain. If exception (2) wasn't there, one could rest secure in the knowledge that typedef names cannot be redeclared. Questions: does any program depend on exception (2)? Should it be stricken from the language, since the manual implicitly prohibits it and since the language would be cleaner without it? Does anyone care? Sam Kendall {allegra,ihnp4}!wjh12!kendall Delft Consulting Corporation decvax!genrad!wjh12!kendall
ldg@druny.UUCP (08/27/83)
In my opinion, the problem of typedef redefinition stems from two sources: 1) lack of specification, and, 2) compiler complexity. Section 11.1 of the C Reference Manual (Ritchie) describes a scenario in which a typedef identifier is redefined as a simple ordinary identifier: typedef float distance; ... { auto int distance; ... The point made is that "int" must be present, otherwise we would have a declaration with no declarator and type "distance. Clearly, the physical position of "distance" also plays a role here. Should we change the ordering of "int" and "distance" we would have an illegal declaration with no declarator. If we had auto int a,b,c,distance,e,f; should we expect a syntax error or a redeclaration to occur? It seems the manual is lacking in this area. There should be no problem with using "distance" as a structure or union tag, since these are kept in a logically separate list, as the manual says. However, enumeration tags and enumerators are like ordinary identifiers and would conflict with an identical typedef name declared in the same scope. Incidentally, I couldn't get the above example from the manual to compile on any compiler. I think it's fairly clear why the compiler can't correctly resolve a valid redeclaration of a typedef. The C parser is generated from a YACC grammar, and expects the lexical analyzer to distinguish between a simple identifier and a declared typedef name. If instead this were not done and typedef names were treated lexically like any other identifier, then the grammar must dramatically increase in size in order to handle parsing problems like "in a declaration, where does the type part end and the declarator begin?". Things could even get more ambiguous: x; /* declaration or statement? */ a = (f)(x); /* function call or cast expression? */ So, because a typedef name is lexically distinct from an identifier (which is the root of any declarator) it cannot syntactically assume the role of a declarator in a declaration. In order to implement typedef redeclaration in a way consistent with the current manual, I would think the compiler maintainers would have to modify the semantic actions performed in the production(s) allowing a declaration without a declarator so that a new definition is associated with the typedef identifier.