[comp.std.c] Interaction between storage class and qualifiers

jack@cwi.nl (Jack Jansen) (01/07/91)

The SGI C compiler treats the following two pointers as unequal:
	register volatile struct foo *p1;
	volatile register struct foo *p2;
p1 is a pointer (in a register) to a volatile struct foo, while
p2 is a volatile pointer (in a register) to a struct foo.

Gcc treats the pointers as identical, and in my opinion this is
as it should be. However, I haven't been able to find anything in
the standard about the interaction of storage classes and type
qualifiers. Since the 'register' in the declaration of p2 already
refers to the variable p2 it is argueable that the volatile in front
of it can't refer to the structure anymore.

Could anyone who knows the standard better than I do please shed
some light on this?

(preferrably by mail, I don't read this group too often. I'll summarize)
-- 
--
Een volk dat voor tirannen zwicht	| Oral:     Jack Jansen
zal meer dan lijf en goed verliezen	| Internet: jack@cwi.nl
dan dooft het licht			| Uucp:     hp4nl!cwi.nl!jack

henry@zoo.toronto.edu (Henry Spencer) (01/08/91)

In article <2760@charon.cwi.nl> jack@cwi.nl (Jack Jansen) writes:
>The SGI C compiler treats the following two pointers as unequal:
>	register volatile struct foo *p1;
>	volatile register struct foo *p2;
>p1 is a pointer (in a register) to a volatile struct foo, while
>p2 is a volatile pointer (in a register) to a struct foo.

This is incorrect.  The standard attributes no significance to the order
of storage class specifiers, type specifiers, and type qualifiers in the
declaration-specifiers list beginning a declaration.  The type specifiers
(in this case `struct foo') and type qualifiers (`volatile') all go to
forming the "base type", so to speak, for the declaration.

The way to declare a volatile pointer (in a register) to a struct foo is

	register struct foo * volatile p3;

See the pointer-declarator rules in 3.5.4.1.

>... I haven't been able to find anything in
>the standard about the interaction of storage classes and type
>qualifiers.

That's because there is none.  The storage class is completely independent
of the type.
-- 
If the Space Shuttle was the answer,   | Henry Spencer at U of Toronto Zoology
what was the question?                 |  henry@zoo.toronto.edu   utzoo!henry

diamond@jit345.swstokyo.dec.com (Norman Diamond) (01/08/91)

In article <2760@charon.cwi.nl> jack@cwi.nl (Jack Jansen) writes:
>The SGI C compiler treats the following two pointers as unequal:
>	register volatile struct foo *p1;
>	volatile register struct foo *p2;
>p1 is a pointer (in a register) to a volatile struct foo, while
>p2 is a volatile pointer (in a register) to a struct foo.
>
>Gcc treats the pointers as identical, and in my opinion this is
>as it should be. However, I haven't been able to find anything in
>the standard about the interaction of storage classes and type
>qualifiers. Since the 'register' in the declaration of p2 already
>refers to the variable p2 it is argueable that the volatile in front
>of it can't refer to the structure anymore.

Interesting.  I thought this would be well defined in the standard
(i.e. that p2 has to be the same as p1) but it isn't.
Section 3.5 includes the following excerpts (except for line numbers):
   (1)  declaration:
   (2)    declaration-specifiers  init-declarator-list/opt
   (3)  declaration-specifiers:
   (4)    storage-class-specifier  declaration-specifiers/opt
   (5)    type-specifier  declaration-specifiers/opt
   (6)    type-qualifier  declaration-specifiers/opt
   (7)  init-declarator-list:
   (8)    init-declarator
   (9)    init-declarator-list  ,  init-declarator
  (10)  init-declarator:
  (11)    declarator
  (12)    declarator  =  initializer
    The declaration specifiers (line 3) consist of a sequence of specifiers
  that indicate the linkage (line 4), storage duration (line 4), and part
  of the type of the entities (lines 5, 6) that the declarators (line 11)
  denote.
Section 3.5.4 tells what kinds of entities declarators can denote:
  (13)  declarator:
  (14)    pointer/opt  direct-declarator
  (15)  direct-declarator:
  (16)    identifier
  (17)    (  declarator  )
  (18)    direct-declarator  [  constant-expression/opt  ]
  (19)    direct-declarator  (  parameter-type-list  )
  (20)    direct-declarator  (  identifier-list/opt  )
  (21)  pointer:
  (22)    *  type-qualifier-list/opt
  (23)    *  type-qualifier-list/opt  pointer
Section 3.5.3 "constrains" the qualifiers:
    The same type qualifier shall not appear more than once in the same
  specifier list (line 3?) or qualifier list (lines 22, 23?), either
  directly or via one or more typedefs.
(Section 3.5.3 does not contain a forward reference to section 3.5.4, but
both of these references are the best interpretations that I can guess.)

At least, it seems that "register const" and "const register" both refer
to the same entity.  Which entity it is, we will determine in a moment.
Nonetheless, either p1 and p2 are the same, or else *p1 and *p2 are the
same.  SGI seems to be broken.  Now, what about GCC?

OK, so what does section 3.5 say about:
  register const int *a;
register, const, and int all describe *a, because *a is the entity denoted
by line 11.  Hmm, section 3.5 seems to be in trouble.
No one, but no one, obeys section 3.5 with regard to "register".
Everyone, but everyone, obeys section 3.5 with regard to "int".
Everyone THOUGHT that it should be disobeyed with respect to "const".
But SGI accidentally obeys it sometimes, while disobeying it other times.
GCC never obeys it.

OK, let's pretend that section 3.5 says "identifier" (fixed up somehow)
instead of "declarator".  (Mr. Gwyn will doubtless assert that it already
says that.)
Now, what does it say about:
  register const int *a;
register, const, and int all describe a?
Everyone obeys this with regard to "register".
No one obeys this with regard to "int".
Everyone thought that this should be obeyed with regard to "const".
Again, SGI is inconsistent.
GCC always obeys it.

Section 3.5 needs to be fixed.  SGI needs to be fixed.  I predict that,
if section 3.5 is fixed, GCC's behavior will be correct.
--
Norman Diamond       diamond@tkov50.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.

davea@quasar.wpd.sgi.com (David B.Anderson) (01/09/91)

In article <1991Jan8.000756.24432@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
>In article <2760@charon.cwi.nl> jack@cwi.nl (Jack Jansen) writes:
>>The SGI C compiler treats the following two pointers as unequal:

Henry's corrections are appropriate. What started this is a compiler
bug that caused rejection of a legal assignment.

By e-mail, Jack Jensen sent me a complete example:
volatile struct foo { int y; } *ptr;
main() {
    register volatile struct foo *p1;
    volatile register struct foo *p2; /* compiler gets ``wrong struct'' */
    p1 = ptr;
    p2 = ptr; /* compiler rejects this: compiler bug */
}
ccom: Warning: tv2.c, line 11: illegal structure pointer combination
          p2 = ptr;
      ------------^

CHARACTERIZATION: Considering: 
	  X to be volatile, const, int, char, unsigned, struct foo (etc)
		or a combination
	and
	  Y to be register, auto, extern, static, typedef
	then
		X Y X
	would not always get the compiler-internal Node data correct. 
	the type would be right, but other data (like the structure index)
	would come from the first X only and ignore the second.

WORKAROUND: Using
		Y X
	instead is recommended practice and works around the bug. 

FIX:
	This previously unknown bug will be fixed (today) for the next 
	major release (4.0).

Thanks to Jack Jensen for letting us know about the problem.

Sorry for any inconvenience this may have caused....
[ David B. Anderson  Silicon Graphics  (415)335-1548  davea@sgi.com ]
[``What can go wrong?''                           --Calvin to Hobbes]

thorinn@diku.dk (Lars Henrik Mathiesen) (01/09/91)

diamond@jit345.swstokyo.dec.com (Norman Diamond) writes: (ND>)
In article <2760@charon.cwi.nl> jack@cwi.nl (Jack Jansen) writes: (JJ>)
JJ>The SGI C compiler treats the following two pointers as unequal:
JJ>	register volatile struct foo *p1;
JJ>	volatile register struct foo *p2;
JJ>p1 is a pointer (in a register) to a volatile struct foo, while
JJ>p2 is a volatile pointer (in a register) to a struct foo.
JJ>
JJ>Gcc treats the pointers as identical, and in my opinion this is
JJ>as it should be. However, I haven't been able to find anything in
JJ>the standard about the interaction of storage classes and type
JJ>qualifiers. Since the 'register' in the declaration of p2 already
JJ>refers to the variable p2 it is argueable that the volatile in front
JJ>of it can't refer to the structure anymore.

I read this to mean that GCC took both declarations as "register
pointer to volatile struct foo" (as it should). Below, you seem to
think that GCC made the pointer volatile.

ND>Interesting.  I thought this would be well defined in the standard
ND>(i.e. that p2 has to be the same as p1) but it isn't.
ND>Section 3.5 includes the following excerpts (except for line numbers):
ND> [grammar rules deleted, and references to them below]
ND>    The declaration specifiers consist of a sequence of specifiers
ND>  that indicate the linkage, storage duration, and part
ND>  of the type of the entities that the declarators
ND>  denote.

I think the problem is the wording "the entities that the declarators
denote". A priori, it might well mean what you seem to assume
(something like "operands of the same form as the declarators", see
the formulation in 3.5.4 Semantics). It might also mean "the
identifiers declared by the declarators"; as I'll argue below, and
knowing what was intended, that's probably the best interpretation.

Note that it says "part of the type" --- if the first meaning was
intended, the type-specifiers and type-qualifiers here would give the
precise type of the "entity", not just part.

ND>At least, it seems that "register const" and "const register" both refer
ND>to the same entity.  Which entity it is, we will determine in a moment.
ND>Nonetheless, either p1 and p2 are the same, or else *p1 and *p2 are the
ND>same.  SGI seems to be broken.  Now, what about GCC?

I'll just comment on the results you get when you make the same
assumption as I do.

ND>OK, let's pretend that section 3.5 says "identifier" (fixed up somehow)
ND>instead of "declarator".  (Mr. Gwyn will doubtless assert that it already
ND>says that.)
ND>Now, what does it say about:
ND>  register const int *a;
ND>register, const, and int all describe a?
ND>Everyone obeys this with regard to "register".

Yes.

ND>No one obeys this with regard to "int".

I think they do, because here's where the "part of the type" comes in.
If you read the explanation in 3.5.4 Semantics, and then read 3.5.4.1
(Pointer declarators), you'll see that the type of a in "int *a" is
determined like this:

  "int *a" has the form "T D1", where T == "int" and D1 == "* a"
  So D1 has the form "* D", where D == "a"
  In the declaration T D, that is "int a", the type specified for a is
integer.
  Therefore, the type specified for a in "int *a" is pointer to integer.

So integer really is part of the type of the identifier declared.

ND>Everyone thought that this should be obeyed with regard to "const".
ND>Again, SGI is inconsistent.
ND>GCC always obeys it.

I think you got this backwards, perhaps. "const int *a" declares a
pointer to a readonly integer, and that's what GCC takes it to do. In
your terms, that would be disobeying this interpretation of 3.5,
wouldn't it?

ND>Section 3.5 needs to be fixed.  SGI needs to be fixed.  I predict that,
ND>if section 3.5 is fixed, GCC's behavior will be correct.

Section 3.5 could certainly do with a better wording, but once you
know what's intended, it's not wrong. SGI is wrong.

--
Lars Mathiesen, DIKU, U of Copenhagen, Denmark      [uunet!]mcsun!diku!thorinn
Institute of Datalogy -- we're scientists, not engineers.      thorinn@diku.dk

gwyn@smoke.brl.mil (Doug Gwyn) (01/09/91)

In article <1991Jan8.011724.25209@jituha.enet.dec.com> diamond@tkov50.enet.dec.com (Norman Diamond) writes:
>OK, let's pretend that section 3.5 says "identifier" (fixed up somehow)
>instead of "declarator".

No, there is nothing wrong with the wording of 3.5 that I can see.
SGI apparently simply got the implementation wrong; there are numerous
problems in their ANSI C support as of Irix release 3.3.  We'll see if
it is fixed in their forthcoming new C implementation.