[comp.std.c] the "const" qualifier

andy@cit-vax.Caltech.Edu (Andy Fyfe) (10/15/89)

The GNU C compiler permits assignment (where assignment includes
things such as parameter passing) of a "char *" to a "const char *",
but not of a "char **" to a "const char **" without an explicit
cast.  Rms assures me that this is in strict accordance with the
ANSI standard.

This came up when I provided the following prototype for
execv:
	extern int execv(const char *path, const char **args);
Gcc gave a warning about incompatible pointer types when execv was
called with a "char **" as the second parameter.

While "execv" may be a bad example (as it's not expected to
return at all), my understanding of such a prototype is that the
function will not change the characters pointed to by "path", or
by "args[0], args[1], ...".  Passing pointers that permit such
changes I would expect to be allowed (and is, for "path").

I was wondering if someone could clarify this for me.

Andy Fyfe
            andy@csvax.caltech.edu
            wjafyfe@caltech.bitnet
            andy@cit-vax.UUCP	(...!ames!elroy!cit-vax!andy)

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/16/89)

In article <12239@cit-vax.Caltech.Edu> andy@csvax.caltech.edu (Andy Fyfe) writes:
>The GNU C compiler permits assignment (where assignment includes
>things such as parameter passing) of a "char *" to a "const char *",
>but not of a "char **" to a "const char **" without an explicit
>cast.  Rms assures me that this is in strict accordance with the
>ANSI standard.

Yes, the arguments must be "assignment compatible" with the corresponding
parameters declared in the prototype.  The rules for this are given in
Section 3.3.16.1 "Constraints".  Violation of a Constraint requires that
a diagnostic be issued.  The relevant constraint from 3.3.2.2 is that the
(zeroth-level) argument type must be assignable to the (zeroth-level)
parameter type after the parameter type has the 0th-level type qualifiers
stripped (the qualifier is second-level in this example), and the relevant
assignment-compatibility constraints are that the (first-level) types
pointed to, i.e. (const char *) and (char *), be compatible ignoring
FIRST-LEVEL qualifiers (there are none in this example), and the type
pointed to by the parameter type, i.e. (const char *), have all the
qualifiers of the type pointed to by the argument type, i.e. (char *),
which it does NOT -- thus the constraint violation.  Note that the
first-level ignoring of qualifiers on the pointed-to types allows a
(char *) argument to be passed without casting to a function declared as
taking a (const char *) parameter, but the qualifier-ignoring does not
occur at second or lower levels.

>	extern int execv(const char *path, const char **args);
>... my understanding of such a prototype is that the
>function will not change the characters pointed to by "path", or
>by "args[0], args[1], ...".  Passing pointers that permit such
>changes I would expect to be allowed (and is, for "path").

You understand the meaning okay.  The problem ultimately stems from a
slight overloading of semantics for "const".  You have to either use
compatible types, or use a cast when invoking the function.

Another interesting possibility is to declare the second argument as
(char * const *), which is true of execv() (it doesn't modify the
pointers in the args[] array either).  While not as helpful as what
you want, it works with the special rule for pointer first levels as
explained previously.  Of course the fully constrained spec is
	extern int execv( const char *path, const char *const *args );

Personally I would opt for
	extern int execv( const char *path, char *const *args );
as the most restrictive declaration that doesn't cause user hassles.

maart@cs.vu.nl (Maarten Litmaath) (10/16/89)

gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
\...  Note that the
\first-level ignoring of qualifiers on the pointed-to types allows a
\(char *) argument to be passed without casting to a function declared as
\taking a (const char *) parameter, but the qualifier-ignoring does not
\occur at second or lower levels.
          ^^^^^^^^^^^^^^^^^^^^^^
Why?  (See below.)

\>	extern int execv(const char *path, const char **args);
\>... my understanding of such a prototype is that the
\>function will not change the characters pointed to by "path", or
\>by "args[0], args[1], ...".  Passing pointers that permit such
\>changes I would expect to be allowed (and is, for "path").
\
\You understand the meaning okay.  The problem ultimately stems from a
\slight overloading of semantics for "const".  [...]

Could you elaborate on this counter-intuitivity?
-- 
The UNIX Way of doing something [...] is to make it look as much like a filter
as possible.  (Richard O'Keefe)        | Maarten Litmaath (mcsun!botter!maart)

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/17/89)

In article <3728@solo10.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>Why?  (See below.)

The added complexity required to accurately specify what you might think
should be the rule for these other cases was not judged to be worth the
effort.  As it is, we were changing the wording about this stuff up to
practically the last minute before printing the final draft, because of
the difficulty in getting even the simpler case specified (a) right, and
(b) intelligibly.  The simpler case suffices for the Standard library
functions (str*() and mem*() in particular), and it was necessary to get
that right.

>\slight overloading of semantics for "const".  [...]
>Could you elaborate on this counter-intuitivity?

Given your propensity for grumbling about the standardization process,
I'm not sure I should.

In essence, a couple of years ago Tom Plum (I think it was) identified
the source of committee disputes about the meaning of type qualifiers
as due to there being three essentially orthogonal attributes involved,
not the two that we had been wrangling with ("const" and "volatile").
That allowed separating out the "noalias" meaning from "readonly", both
of which had been confused together in "const".  Subsequently, "const"
was in effect redefined to have the "readonly" meaning and "noalias"
was added as a separate type qualifier.  To make a long story short,
we had to retract "noalias" late in the review process, which left us
with the newly resurfaced problem of specifying the library facilities
such as str*() parameters in a way that had formerly been covered by
combining two type qualifiers ("const noalias"), one of which had just
vanished.  The best we could do under the circumstances is what is now
specified.  Many of us think "noalias", with the problems in its
specification straightened out, would have been a better solution, but
it wasn't politically feasible to reintroduce such a qualifier.

P.S.  This is my own recollection of the essence of what happened,
and you shouldn't take it as any sort of official X3J11 history!

perry@ccssrv.UUCP (Perry Hutchison) (10/19/89)

In article <11320@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:

+ In essence, a couple of years ago Tom Plum (I think it was) identified
+ the source of committee disputes about the meaning of type qualifiers ...
+ That allowed separating out the "noalias" meaning from "readonly", both
+ of which had been confused together in "const" ... "noalias"
+ was added as a separate type qualifier.  To make a long story short,
+ we had to retract "noalias" late in the review process, which left us
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ with the newly resurfaced problem of specifying the library facilities ...
+ The best we could do under the circumstances is what is now specified.
                       ^^^^^^^^^^^^^^^^^^^^^^^
+ Many of us think "noalias", with the problems in its specification
+ straightened out, would have been a better solution, but
+ it wasn't politically feasible to reintroduce such a qualifier.
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In other words, a _technically_ defective hack was put in the standard at
the last minute, to satisfy someone's _political_ agenda.

It sounds to me like the current "proposed standard" deserves to be voted
down and sent back to committee to have this mess (and any other problems
which may have surfaced) cleaned up.

henry@utzoo.uucp (Henry Spencer) (10/19/89)

In article <742@ccssrv.UUCP> perry@ccssrv.UUCP (Perry Hutchison) writes:
>+ Many of us think "noalias", with the problems in its specification
>+ straightened out, would have been a better solution, but
>+ it wasn't politically feasible to reintroduce such a qualifier.
>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
>In other words, a _technically_ defective hack was put in the standard at
>the last minute, to satisfy someone's _political_ agenda.

Well, yes, but not in the way you meant it.  A technically defective hack
("noalias") was indeed put in the standard at the last minute (second public
review) to satisfy someone's (the number crunchers') semi-political agenda.
There was, quite legitimately and properly, a storm of protest from almost
everyone else in sight, including Dennis Ritchie.  Partly because the hack
really was technically defective, as written.  So it got hastily taken out
again.  Something along those lines might indeed have been the best solution,
but it was introduced far too late and without adequate prior thought.  If
I am not mistaken, it was also an invention of the committee rather than
proven prior art, which is a big no-no for a standards committee.

If the current situation is a botch, which I don't necessarily admit (I'm
of the anti-noalias faction), it is (a) one of the committee's own making,
and (b) too late to fix.
-- 
A bit of tolerance is worth a  |     Henry Spencer at U of Toronto Zoology
megabyte of flaming.           | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

maart@cs.vu.nl (Maarten Litmaath) (10/20/89)

gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
\...  As it is, we were changing the wording about this stuff up to
\practically the last minute before printing the final draft, [...]

Wouldn't it have been beautiful, if X3J11 had been given another year...

\Given your propensity for grumbling about the standardization process,
\I'm not sure I should.

Thanks you did it anyway!
Of course I've been wrong sometimes, but there ARE things which were
handled rather in a rush... (You said so yourself.)
-- 
A symbolic link is a POINTER to a file, | Maarten Litmaath @ VU Amsterdam:
 a hard link is the file system's GOTO. | maart@cs.vu.nl, mcsun!botter!maart

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/20/89)

In article <742@ccssrv.UUCP> perry@ccssrv.UUCP (Perry Hutchison) writes:
>It sounds to me like the current "proposed standard" deserves to be voted
>down and sent back to committee to have this mess (and any other problems
>which may have surfaced) cleaned up.

Fortunately for the C programming community, numerous people in a much
better position than you to make such a judgement have decided that the
currently proposed Standard is technically good enough as it now stands.

I'm sorry if you think I described a "mess".  Perhaps that's what I get
for trying to give an honest but brief description of the relevant
history.  In fact there IS NO MESS in this regard in the proposed
Standard.  There IS a void that has been left unfilled, but its effect
is relatively minor.  The two practical consequences will be:

	Occasionally, interface designers will have to decide whether
	or not 	to require a type cast to be used, as in the execve()
	example that started this thread.

	Certain types of optimization will require more complicated
	global flow analysis, or use of nonstandard extensions.

mcdonald@aries.uiuc.edu (Doug McDonald) (10/21/89)

>
>Well, yes, but not in the way you meant it.  A technically defective hack
>("noalias") was indeed put in the standard at the last minute (second public
>review) to satisfy someone's (the number crunchers') semi-political agenda.
>There was, quite legitimately and properly, a storm of protest from almost
>everyone else in sight, including Dennis Ritchie.  Partly because the hack
>really was technically defective, as written.  So it got hastily taken out
>again.  Something along those lines might indeed have been the best solution,
>but it was introduced far too late and without adequate prior thought.  If
>I am not mistaken, it was also an invention of the committee rather than
>proven prior art, which is a big no-no for a standards committee.
>

Apparently X3 now has been taken by serious second thoughts about
their subcommittees (i.e. J3) inventing new languages, as they have
decided to contine the old one (Fortran77). The flamage in comp.std.c
(and the .lang group) is as nothing, compared to the number of participants,
as is the amount in comp.lang.fortran - in which X3J3 has invented a
language so wholly new that X3 is having to give it a new name. 
Thankfully, X3J11 resisted the temptation.

On the other hand, it looks like X3J3 is going to botch the technical
requirements of the public review sufficiently badly that there will
have to be another one! (They are not going to get out their
replies to the last one - two years ago - in time!).

Doug McDonald

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/22/89)

In article <3753@pinas.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>Wouldn't it have been beautiful, if X3J11 had been given another year...
>Of course I've been wrong sometimes, but there ARE things which were
>handled rather in a rush... (You said so yourself.)

Yeah, life sometimes requires compromise.

There was NO WAY that the C community was going to wait much longer;
the commercial importance of C had increased tremendously since the
time that the standardization effort began.

For the record, I was the only X3J11 member to vote "NO" to sending
the amended draft proposed Standard out for the third public review,
which was expected to result in no further substantive changes to
the proposed Standard, because I didn't think there had been enough
time to adequately evaluate all the second-round comments.  Yet not
even I objected to sending along the final draft to X3 as the
proposed ANSI (and, coincidentally, ISO) standard, because I agreed
that in its current form it is certainly "good enough".  In fact it
seems better overall to me than any other similar standard I've seen,
and I've seen several.

It does not serve the best interests of the C community to keep
tweaking on the document forever, seeking after the inattainable
goal of absolute perfection.  If the Standard meets the needs that
motivated the standardization effort, then that's good enough.

You think the "short" amount of time spent by X3J11 (what was it,
7 years?) was insufficient, you should look at IEEE 1003.  Due
partly to unwarranted pressure from NBS (now NIST), IEEE Std 1003.1
was pushed out the door with major changes appearing only in the
middle of supplemental mailings after the final letter ballot.
Now THERE's a case of rushing through the standardization process.

andy@cit-vax.Caltech.Edu (Andy Fyfe) (10/27/89)

When I look at a prototype of the form
	extern char *strcpy(char *to, const char *from);
I'd like to think of it as not only telling me what the parameter
types are, but also telling me that strcpy will not change the
characters pointed at through "from".  

I had previously brought up the example of "execv", and Doug
Gwyn suggested:
>Personally I would opt for
>	extern int execv( const char *path, char *const *args );
>as the most restrictive declaration that doesn't cause user hassles.

I would rather see the fully constrained
	extern int execv( const char *path, const char *const *args );
With just 
	extern int execv( const char *path, char *const *args );
I would wonder about the "safety" of passing a "const char **" as the
second argument.  Explicitly casting the "const char **" to a "char **"
would work, but only with something external (or a comment or
something) to tell me it's "safe".  Yet to use the fully constrained
version causes compiler warnings in the typical case of passing a "char
**", unless a cast is present.  Such a cast strikes me as a bit
incongruous, as what's allowed with the pointer after the cast was
allowed to begin with.

I can be somewhat pedantic.  I assume that if a compiler puts a literal
string constant in read-only memory (as Gnu CC does, for example), it
should give that string the type "const char *" when type checking (and
Gnu CC will do this, with a -W... option).  Getting something that I
think really should have the type "const char **" is easy (any array of
pointers to literal strings), and since a write into such a string when
using a compiler like Gnu CC can cause a run-time memory fault, I'd
just as soon have the compiler doing some extra checking for me (I'm a
bit too error-prone to do it myself).

Thanks to those who've responded.

Andy Fyfe
	    andy@csvax.caltech.edu wjafyfe@caltech.bitnet
	    andy@cit-vax.UUCP   (...!ames!elroy!cit-vax!andy)

rpjday@ccu.umanitoba.ca (08/01/90)

  I am trying to decode the ANSI draft in front of me, and am having
trouble interpreting the section on the const qualifier.  Rather than
type out the entire example, I'll just refer to the page and line numbers
in the Feb 14, 1990 draft.
  Section 3.5.3, line 26, we have, "For two qualified types to be
compatible, both shall have the identically qualified version of a 
compatible type..."  Does "compatible" mean assignment compatible?
That is, I am not allowed to do 

	const int i = 10;
	int j;
	j = i;   ???

even though this has no effectg on the value of j?

  This is just the beginning.  At the top of the next page, in the
segment of code, line 7 shows an assignment of a const-qualified
structure to a non-const-qualified structure.  But based on the
previous definition, should this work?  The comment suggests it should.
Clarification, please?

  Finally, line 12 of 3.5.3, "If an attempt is made to modify an object
defined with a const-qualified type through use of an lvalue with
non-const-qualified type, the behavior is undefined."  How would one
do this anyway?  Maybe as follows?

	const int j = 10 ;
	int i ;
	*(&i + 1) = 20 ;

  If i and j are allocated in the standard order on the stack,
this assignment would affect the value of j.  Is this what this statement
refers to ?  Is there another example?
  Thanks for the help.

R. Day
U of Manitoba

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/01/90)

In article <1990Aug1.005200.21645@ccu.umanitoba.ca> rpjday@ccu.umanitoba.ca writes:
-  Section 3.5.3, line 26, we have, "For two qualified types to be
-compatible, both shall have the identically qualified version of a 
-compatible type..."  Does "compatible" mean assignment compatible?

No, "compatible type" is a technical term defined in section 3.1.2.6.

-That is, I am not allowed to do 
-	const int i = 10;
-	int j;
-	j = i;   ???
-even though this has no effectg on the value of j?

I don't understand your example.  Certainly it is allowed, and the
value of j is definitely affected (it is set to 10).

-  This is just the beginning.  At the top of the next page, in the
-segment of code, line 7 shows an assignment of a const-qualified
-structure to a non-const-qualified structure.  But based on the
-previous definition, should this work?  The comment suggests it should.

Of course it should work.  What argumentation would you offer for it
being disallowed?

You cannot store INTO a const-qualified object; however, you may
pick up its contents!

-  Finally, line 12 of 3.5.3, "If an attempt is made to modify an object
-defined with a const-qualified type through use of an lvalue with
-non-const-qualified type, the behavior is undefined."  How would one
-do this anyway?

	const int j = 10;
	int *p = (int *)&j;
	*p = 20;

- Maybe as follows?
-	const int j = 10 ;
-	int i ;
-	*(&i + 1) = 20 ;

Yuck!  That's horrible code, which one has no reason to expect to work.

karl@haddock.ima.isc.com (Karl Heuer) (08/01/90)

In article <1990Aug1.005200.21645@ccu.umanitoba.ca> rpjday@ccu.umanitoba.ca writes:
>Section 3.5.3, line 26, we have, "For two qualified types to be
>compatible, both shall have the identically qualified version of a
>compatible type..."  Does "compatible" mean assignment compatible?

No, it means that they really are the exact same type, or could be after
completion.  For example, "void (*f[3])()" and "void (*f[])(double)" are
compatible types, because each can be completed to "void (*f[3])(double)"
(known as the _composite type_).  See 3.1.2.6.

>[deleted stuff that was based on the wrong assumption]
>  Finally, line 12 of 3.5.3, "If an attempt is made to modify an object
>defined with a const-qualified type through use of an lvalue with
>non-const-qualified type, the behavior is undefined."  How would one
>do this anyway?

You can remove const-qualification by using an explicit cast.
	int const i = 10;
	int *p = (int *)&i;
	*p = 20;
The cast itself is legal (though certainly questionable).  The assignment to
`*p' is legal syntactically but not semantically.

Another example is
	extern char const buf[];
	char *p = strchr(buf, c);
where the cast is hidden inside the implementation of strchr().  Logically,
the return type of strchr() is the same as its first actual argument (either
`char const *' or `char *'), but C has no way to declare that.  A similar
problem exists with functions like `memcpy()'.  Caveat emptor.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

rpjday@ccu.umanitoba.ca (08/02/90)

In article <1990Aug1.005200.21645@ccu.umanitoba.ca> I write:

>  Section 3.5.3, line 26, we have, "For two qualified types to be
>compatible, both shall have the identically qualified version of a 
>compatible type..."  Does "compatible" mean assignment compatible?
>That is, I am not allowed to do 
>
>	const int i = 10;
>	int j;
>	j = i;   ???
>
>even though this has no effectg on the value of j?

Of course, what I meant was "no effect on the value of i".  Sigh.

rpjday@ccu.umanitoba.ca (08/02/90)

OK, now that I managed to make a total fool of myself with a well-placed
typo, let me try to prove that I am not a complete cement-head.

In article <13462@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>In article <1990Aug1.005200.21645@ccu.umanitoba.ca> rpjday@ccu.umanitoba.ca writes:

>-  Section 3.5.3, line 26, we have, "For two qualified types to be
>-compatible, both shall have the identically qualified version of a 
>-compatible type..."  Does "compatible" mean assignment compatible?
>
>No, "compatible type" is a technical term defined in section 3.1.2.6.

All right, I can handle that.

>-That is, I am not allowed to do 
>-	const int i = 10;
>-	int j;
>-	j = i;   ???
>-even though this has no effectg on the value of j?
>
>I don't understand your example.  Certainly it is allowed, and the
>value of j is definitely affected (it is set to 10).

Uh, my fault, that should have been "no effect on the value of i".
I realized that, logically, there can be no harm in the above code snippet,
and maybe my confusion is now obvious when I thought "compatible" meant
assignment compatible since, according to the draft, the types
"int" and "const int" are not technically compatible since they are
not identically qualified.  Because of that, I concluded that the
above code, harmless as it was, was somehow illegal.  

>-  This is just the beginning.  At the top of the next page, in the
>-segment of code, line 7 shows an assignment of a const-qualified
>-structure to a non-const-qualified structure.  But based on the
>-previous definition, should this work?  The comment suggests it should.
>
>Of course it should work.  What argumentation would you offer for it
>being disallowed?

See above.  My misunderstanding.

>-  Finally, line 12 of 3.5.3, "If an attempt is made to modify an object
>-defined with a const-qualified type through use of an lvalue with
>-non-const-qualified type, the behavior is undefined."  How would one
>-do this anyway?
>
>	const int j = 10;
>	int *p = (int *)&j;
>	*p = 20;
>
>- Maybe as follows?
>-	const int j = 10 ;
>-	int i ;
>-	*(&i + 1) = 20 ;
>
>Yuck!  That's horrible code, which one has no reason to expect to work.

I wasn't out to win any beauty contests, I just dragged this one out
of the gutter because, in some places, it would do what I wanted --
modify the value of j.

I still, however, have one point of confusion.  On. p. 66, we have
(among other things)

  const struct s { int mem ; } cs = { 1 } ;
  struct s ncs ;
  int *pi;

  pi = &cs.mem;   /* violates type constraints for = */
  ncs = cs ;      /* valid */

Now I can appreciate that the assignment to "pi" should not be allowed,
but PRECISELY which rule makes this illegal?  Is the const qualification
considered part of the "type" so that these are technically different
types and must be cast?  If this is true, I would think that 
the next assignment should be illegal for the same reason (yes,
I know it's totally harmless, but "ncs" and "cs" have different
qualification, so does that make them different types?)

In short, the first assignment should obviously fail, and the second
should obviously work, but what is the rule that makes the first illegal 
and the second valid?  Thanks for the help (and the patience).

R. Day
U of Manitoba

rpjday@ccu.umanitoba.ca (08/02/90)

In article <1990Aug2.011735.1143@ccu.umanitoba.ca> rpjday@ccu.umanitoba.ca writes:
>OK, now that I managed to make a total fool of myself with a well-placed
>typo, let me try to prove that I am not a complete cement-head.

.
.
.

Never mind, it has been pointed out to me that the relevant section
deals with lvalues and function designators (3.2.2.1).  NOW it makes
sense.  thanks to all who mailed. 

R. Day
U of Manitoba

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/05/90)

In article <1990Aug2.011735.1143@ccu.umanitoba.ca> rpjday@ccu.umanitoba.ca writes:
>  const struct s { int mem ; } cs = { 1 } ;
>  struct s ncs ;
>  int *pi;
>  pi = &cs.mem;   /* violates type constraints for = */
>Now I can appreciate that the assignment to "pi" should not be allowed,
>but PRECISELY which rule makes this illegal?

Supposedly the constraint in 3.3.16.1 that requires the thing pointed to
by the LHS to have all the qualifiers of the thing pointed to by the RHS
is violated.  For this to work, the "mem" member of the struct "cs" must
also be considered to be const-qualified, which is reasonable but hard
to deduce from the wording in the standard.  Basically, all parts of an
object declared with a type qualifier are also so qualified.

>  ncs = cs ;      /* valid */
>I know it's totally harmless, but "ncs" and "cs" have different
>qualification, so does that make them different types?)

No constraint is violated by this assignment.

scjones@thor.UUCP (Larry Jones) (08/05/90)

In article <13475@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> Supposedly the constraint in 3.3.16.1 that requires the thing pointed to
> by the LHS to have all the qualifiers of the thing pointed to by the RHS
> is violated.  For this to work, the "mem" member of the struct "cs" must
> also be considered to be const-qualified, which is reasonable but hard
> to deduce from the wording in the standard.  Basically, all parts of an
> object declared with a type qualifier are also so qualified.

It seems to me that there used to be a statement in the standard that
said basically that if an aggregate is qualified, all of the members
are effectively qualified, and if a member of an aggregate is
qualified, then the aggregate is effectively qualified.  Now I don't
seem to be able to find it.  Am I imagining things again, did I miss
it, or did we remove it?
----
Larry Jones                         UUCP: uunet!sdrc!thor!scjones
SDRC                                      scjones@thor.UUCP
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150-2789             AT&T: (513) 576-2070
Girls are like slugs -- they probably serve some purpose, but
it's hard to imagine what. -- Calvin

diamond@tkou02.enet.dec.com (diamond@tkovoa) (08/06/90)

In article <127@thor.UUCP> scjones@thor.UUCP (Larry Jones) writes:

>It seems to me that there used to be a statement in the standard that
>said basically that if an aggregate is qualified, all of the members
>are effectively qualified, and if a member of an aggregate is
>qualified, then the aggregate is effectively qualified.  Now I don't
>seem to be able to find it.  Am I imagining things again, did I miss
>it, or did we remove it?

In section 3.5.3, the Semantics almost say that for arrays.  (However,
if a qualifier is "inherited" along the "wrong" path via a typedef,
then the standard does not define the result.)  The Semantics say
nothing for structs.

However, the Examples are a lot stronger.  The Examples state that
certain things are illegal even though the rules say nothing about
them.  I guess it's time for another interpretation.  (At least this
time, the Examples don't contradict the rules.)
-- 
Norman Diamond, Nihon DEC     diamond@tkou02.enet.dec.com
This is me speaking.  If you want to hear the company speak, you need DECtalk.

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/06/90)

In article <127@thor.UUCP> scjones@thor.UUCP (Larry Jones) writes:
>In article <13475@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>It seems to me that there used to be a statement in the standard that
>said basically that if an aggregate is qualified, all of the members
>are effectively qualified, and if a member of an aggregate is
>qualified, then the aggregate is effectively qualified.  Now I don't
>seem to be able to find it.  Am I imagining things again, did I miss
>it, or did we remove it?

Yeah, I was looking for that too, and I didn't find it either.
The only thing I found that was at all relevant said that a qualifier
in an array declaration actually qualifies the elements of the array,
not the array itself.  However, that's not what we're looking for..
I have no idea what might have happened to the part<->whole clause.

walter@hpcllca.HP.COM (Walter Murray) (08/10/90)

Larry Jones:

>It seems to me that there used to be a statement in the standard that
>said basically that if an aggregate is qualified, all of the members
>are effectively qualified, and if a member of an aggregate is
>qualified, then the aggregate is effectively qualified.  Now I don't
>seem to be able to find it.  Am I imagining things again, did I miss
>it, or did we remove it?

Doug Gwyn:

>Yeah, I was looking for that too, and I didn't find it either.
>The only thing I found that was at all relevant said that a qualifier
>in an array declaration actually qualifies the elements of the array,
>not the array itself.  However, that's not what we're looking for..
>I have no idea what might have happened to the part<->whole clause.

If you access a member of a struct or union that has qualified type,
using the . operator or the -> operator, the qualifiers of the
struct or union apply to the member.  Section 3.3.2.3.

Going the other way, a struct or union can't be a modifiable lvalue
if it has a member with a const-qualified type.  Section 3.2.2.1.

Taken with the semantics rules in 3.5.3, these seem to provide what
we are looking for.

Walter Murray
----------