[comp.std.c] Interpretation of peculiar declarators?

mself@next.com (05/08/91)

I am trying to determine whether the following program is in error:

	typedef int t;

	void foo (void)
	{
	  t t, x;
	}

I believe this ought to declare t and x to be of type int, since I don't  
believe that the fact that t is re-declared as a variable instead of a typedef  
in the first declarator should affect the interpretation of the identifier t in  
the type-specifier for the second declarator (since the type-specifier is  
lexcically before the redefinition).  That is, I do not believe that

	t t, x;

is equivalent to

	t t;
	t x;

ANSI is quite specific that the scope of an identifier begins "just after the  
completion of its declarator" (3.1.2.1), and there is nothing to indicate that  
the identifiers in the type-specifier may be re-interpreted at each declarator.

An even more complicated case is this:

	t t = 1, x = t;

In this case I believe that this is exactly equivalent to

	int t = 1, x = t;

That is, it declares t and x to be of type int, and initializes x to the  
current value of t (which is 1).

If all of this speculation is true, then it puts some fairly strong constraints  
on the implementation of compilers.  A compiler must look up any type name in  
the type-specifier only once (before processing any of the declarators), and it  
must enter the newly declared identifiers into the symbol table before  
processing subsequent declarators.

Can anyone clear this up?

diamond@jit533.swstokyo.dec.com (Norman Diamond) (05/08/91)

In article <679@rosie.NeXT.COM> mself@next.com writes:

>	typedef int t;
>	void foo (void)	{ t t, x; }
>I believe this ought to declare t and x to be of type int,

I believe that the BNF constructions cause this result.

>An even more complicated case is this:
>	t t = 1, x = t;
>In this case I believe that this is exactly equivalent to
>	int t = 1, x = t;
>That is, it declares t and x to be of type int, and initializes x to the
>current value of t (which is 1).

This seems true too, for the reasons you gave (and I deleted).

>If all of this speculation is true, then it puts some fairly strong constraints
>on the implementation of compilers.  A compiler must look up any type name in
>the type-specifier only once (before processing any of the declarators), and it
>must enter the newly declared identifiers into the symbol table before
>processing subsequent declarators.

Sorry to be pedantic, but the compiler only has to behave "as if" it were
doing this.  Out of curiosity, what else would you want to do?  Would you
prefer for the result to be undefined?  Maybe this causes a bit of extra
work in implementing an incremental compiler, but surely there is no other
meaningful result.

>Can anyone clear this up?

I'd say you cleared this up yourself, mself.
--
Norman Diamond       diamond@tkov50.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.

david@lpi.liant.com (David Michaels) (05/09/91)

In article <679@rosie.NeXT.COM> mself@next.com writes:

> I am trying to determine whether the following program is in error:
>
>	typedef int t;
>	void foo (void) {
>	  t t, x;
>	}
>
> I believe this ought to declare t and x to be of type int, since I don't
> believe that the fact that t is re-declared as a variable instead of a
> typedef  in the first declarator should affect the interpretation of the
> identifier t in the type-specifier for the second declarator (since the
> type-specifier is lexcically before the redefinition).

You're right, "t t, x;" is equivalent to "int t, x;".

> ANSI is quite specific that the scope of an identifier begins "just after
> the completion of its declarator" (3.1.2.1), and there is nothing to
> indicate that the identifiers in the type-specifier may be re-interpreted
> at each declarator.

Yep.

> An even more complicated case is this:
>
>	t t = 1, x = t;
>
> In this case I believe that this is exactly equivalent to
>
>	int t = 1, x = t;

Right again, they are equivalent.  This also might be of interest:

	const x;        /* ok -- same as const int x; */
	typedef int t;
	f () {
	     const t;   /* error -- no declarator name (i.e. const int;) */
	}
	g () {
	     const *t;  /* error -- technically, but ... */
	}

ANSI-C (3.5.6) says that if a typedef name is redeclared in an inner scope
(or as a struct/union member in the same or inner scope), the type specifiers
shall not be omitted.  This constitutes what someone coined as the "maximum
munch" rule (in C++ this rule is achieved by saying that the longest sequence
of declaration specifiers that could possibly be a type name is taken as the
declaration specifiers of a declaration).  The second error case is interesting
in that according to ANSI-C it is illegal, even though it is clear what is
meant, and the compiler has to go out of its way to generate a diagnostic.
Here's another one:

	typedef int t;
	f () {
	     const t (t (t (t (t))));
	}

This mess turns out to be a legal declaration equivalent to:

	const int t (int (int (int)));

I.e. a function "t" returning a "const int" and taking one parameter of
type [pointer to] function returning "int" and taking one parameter of type
[pointer to] function returning "int" and taking one parameter of type "int".

> If all of this speculation is true, then it puts some fairly strong 
> constraints on the implementation of compilers.  A compiler must look
> up any type name in the type-specifier only once (before processing
> any of the declarators), and it must enter the newly declared identifiers
> into the symbol table before processing subsequent declarators.

Exactly.  It turns out that it's not all that
difficult to get it straight; just a little tricky.

> Can anyone clear this up?

Sounds like you've got it all cleared up yourself.

				-- David Michaels (david@lpi.liant.com)
				   Language Processors, Inc.
				   Framingham, Massachusetts