shankar@hpclscu.HP.COM (Shankar Unni) (07/06/89)
A question has come up with regard to the interpretation of a parenthesized sentence in Sec 3.5.4.3 (page 69, lines 24, 25 in the Dec 88 draft). I'll quote here in full the paragraph in question (I've put in some blank lines between conditions, just to make it a little easier to read - in the standard document, all this is one giant paragraph): For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, (a) shall agree in the number of parameters and in the use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an (b) ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions. If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list, both shall agree in the number of parameters and the (c) type of each prototype parameter shall be compatible with the type that results from the application of the default argument promotions to the type of the corresponding identifier. (For each parameter declared with a function or array type, its type for these comparisons is the one that results from conversion to a pointer type, as in Sec 3.7.1. For each (->) parameter declared with a qualified type, its type for these comparisons (->) is the unqualified version of its declared type.) (Phew!) The clauses marked (a), (b) and (c) are three distinct combinations of function-declarator styles (prototype - prototype, prototype - old-style declaration, prototype - old-style definition). The debate is whether the parenthesized sentences (especially the one marked with "->") apply only to the last combination, or to all three. Specifically, are all the following correct combinations of declarations? If so, what are the composite types of these function types?: (a) int func1 (const int); int func1 (int p) { /* can "p" be modified here? */ } (b) int func2 (); int func2 (const int); (c) int func3 (const int); int func3 (p) int p; { /* can "p" be modified here? */ } In both (a) and (c), this is a crucial question. The composite type determines whether "p" is a const or not (in the body). Another question is: if any of these is deemed to be wrong (let's say that the types in (a) are not compatible): Am I violating a constraint if I allow assignment to "p"? What if the declaration had no const and the definition had one? My personal opinion (based on a "gut feeling") is that qualifiers should be stripped from definitions *for the purposes of comparisons only*. I.e. in case (a), the combination should be OK, and "p" should be modifiable. If it was the other way round (declaration without "const", definition with "const"), then "p" should not be modifiable. It shouldn't matter to the caller whether the parameter is a const or not - it will never change the semantics of the actual call. Could the gurus please impart their wisdom to us on this earth-shaking topic? It will be much appreciated. (p.s. the non-gurus are welcome with their opinions, too, so don't be shy :-)). -------- Shankar Unni Hewlett-Packard California Language Lab. Internet: shankar@hpda.hp.com Phone: (408) 447-5797 UUCP: ...!hplabs!hpda!shankar
walter@hpclwjm.HP.COM (Walter Murray) (07/06/89)
Shankar Unni writes: > A question has come up with regard to the interpretation of a parenthesized > sentence in Sec 3.5.4.3 (page 69, lines 24, 25 in the Dec 88 draft). [excerpt from pANS deleted] > The clauses marked (a), (b) and (c) are three distinct combinations of > function-declarator styles (prototype - prototype, prototype - old-style > declaration, prototype - old-style definition). > The debate is whether the parenthesized sentences (especially the one marked > with "->") apply only to the last combination, or to all three. As I read it, the parenthesized sentences apply to the entire paragraph. > Specifically, > are all the following correct combinations of declarations? If so, what > are the composite types of these function types?: > (a) int func1 (const int); > int func1 (int p) { /* can "p" be modified here? */ } > (b) int func2 (); > int func2 (const int); > (c) int func3 (const int); > int func3 (p) int p; { /* can "p" be modified here? */ } As I read it, all three examples are legal (strictly conforming), and in both (a) and (c), "p" is a modifiable lvalue. > In both (a) and (c), this is a crucial question. The composite type > determines whether "p" is a const or not (in the body). Why do you say this? It seems to me that whether "p" may be treated as modifiable by statements in the function body depends solely on how "p" is declared in the function definition, and not on how it may be declared in any other declarations of the function. In (b) and (c) above, I would say that the composite type of the function is "int (const int)". In (a), although I think it's legal, I don't think the pANS defines the composite type. Fortunately, it doesn't make any difference, as far as I can tell, whether the composite type is considered to be "int (int)" or "int (const int)". > My personal opinion (based on a "gut feeling") is that qualifiers should > be stripped from definitions *for the purposes of comparisons only*. I.e. > in case (a), the combination should be OK, and "p" should be modifiable. > If it was the other way round (declaration without "const", definition with > "const"), then "p" should not be modifiable. It shouldn't matter to the > caller whether the parameter is a const or not - it will never change > the semantics of the actual call. I reach the same conclusions. > Shankar Unni Walter Murray In case there's any doubt, these are my personal opinions. ----------
dfp@cbnewsl.ATT.COM (david.f.prosser) (07/06/89)
In article <12570014@hpclscu.HP.COM> shankar@hpclscu.HP.COM (Shankar Unni) writes: >A question has come up with regard to the interpretation of a parenthesized >sentence in Sec 3.5.4.3 (page 69, lines 24, 25 in the Dec 88 draft). > >I'll quote here in full the paragraph in question (I've put in some blank >lines between conditions, just to make it a little easier to read - in the >standard document, all this is one giant paragraph): There's a good reason why it's all one paragraph--so that the applicability of the parenthetical sentences would be clear. [most of the quoted text deleted] > (For each parameter declared with > a function or array type, its type for these comparisons is the one that > results from conversion to a pointer type, as in Sec 3.7.1. For each >(->) parameter declared with a qualified type, its type for these comparisons >(->) is the unqualified version of its declared type.) > >The debate is whether the parenthesized sentences (especially the one marked >with "->") apply only to the last combination, or to all three. They apply to the entire paragraph. >Specifically, >are all the following correct combinations of declarations? If so, what >are the composite types of these function types?: There is a misunderstanding here. The parenthetical sentences are not differences in type that participate in producing a (possibly different) composite type. Many people also seem to believe that type qualifiers have this sort of connection with composite types, for whatever reason. These sentences state that these "rewrites" of the parameter types are part of the type comparison: types that are the same after the rewrite are the same. > >(a) int func1 (const int); > int func1 (int p) { /* can "p" be modified here? */ } Yes. The type of the parameter is "int". > >(b) int func2 (); > int func2 (const int); These are compatible types. > >(c) int func3 (const int); > int func3 (p) int p; { /* can "p" be modified here? */ } Yes. The parameter has type "int". > >In both (a) and (c), this is a crucial question. The composite type >determines whether "p" is a const or not (in the body). No. The rules for composite types have nothing to do with qualified or unqualified versions of types. The composite type for all of the above examples is the same: function returning int with one int parameter. Only those differences listed in section 3.1.2.6 (array with unknown vs. known size, function without parameter information vs. with parameter information) come into action in the creation of a composite type. > >Another question is: if any of these is deemed to be wrong (let's say >that the types in (a) are not compatible): Am I violating a constraint >if I allow assignment to "p"? What if the declaration had no const and >the definition had one? All the above examples are compatible, but it is the actual type of the function definition that determines the allowed behavior in the function: int f(const int); int f(int a){return ++a;} /* valid */ int g(int); int g(const int a){return ++a;} /* invalid, but only due to the ++ */ > >My personal opinion (based on a "gut feeling") is that qualifiers should >be stripped from definitions *for the purposes of comparisons only*. I.e. >in case (a), the combination should be OK, and "p" should be modifiable. >If it was the other way round (declaration without "const", definition with >"const"), then "p" should not be modifiable. It shouldn't matter to the >caller whether the parameter is a const or not - it will never change >the semantics of the actual call. This is what the pANS describes. It is unfortunate that the draft doesn't seem to make it clear, and you have to rely on "gut feelings". Dave Prosser ...not an official X3J11 answer...
gwyn@smoke.BRL.MIL (Doug Gwyn) (07/06/89)
In article <12570014@hpclscu.HP.COM> shankar@hpclscu.HP.COM (Shankar Unni) writes: >The debate is whether the parenthesized sentences (especially the one marked >with "->") apply only to the last combination, or to all three. All of them, of course. That paragraph is specifying what it takes for function interfaces to have compatible types, and the parenthetical clarifies some aspects of parameter type compatibility, which is a subissue within the more general function type compatibility issue.
kathy@hpfcdc.HP.COM (Kathy Harris) (07/07/89)
I'm still not clear on this. Is it only the "top-level" qualifier that
is to be ignored for comparisons, or all qualifiers. For example, are
the following compatible or not:
int f(const int * p);
int f(int * p);
where the 'const' qualifier applies to the 'int' not to the 'pointer'.
If you do ignore this for comparisons, then it still makes a difference
in the composite type, because it will determine whether the following
generates a diagnostic about passing a pointer to a constant to a plain
pointer.
main() {
const int *q;
f(q);
}
Kathy Harris
Hewlett Packard Colorado Language Lab
hplabs!hpdcdb!kathy
shankar@hpclscu.HP.COM (Shankar Unni) (07/08/89)
Thanx, all, for the replies. It's a little clearer now. Dave, you're right: I was getting a little confused re: composite types and qualifiers. You see, on the one hand, section 3.1.2.6 states (third bullet) that the composite type of two function types with parameter lists is a function type with a parameter list, with the type of each parameter being the composite type of the corresponding parameters from the two function types. On the other hand, if one has a parameter of type "const int", and the other has a parameter of type "int", clearly there is no "composite type" of these two types (via sec. 3.5.3). Thus, the point to be made clear, IMO, is that the "function type" really contains an imaginary parameter list, which is identical to the parameter list with which it is declared, except that the qualifiers on the parameter types are ignored. E.g., in the function definition int foo (const int bar) { /* */ } the type of "foo" is int () (int) (my notation for: return type == int, parameter list = "int"). However, the type of "bar" is "const int". Am I off target? Maybe a slight clarification needs to be put into the standard or the rationale at some stage. ---- Shankar.
dfp@cbnewsl.ATT.COM (david.f.prosser) (07/10/89)
In article <12040016@hpfcdc.HP.COM> kathy@hpfcdc.HP.COM (Kathy Harris) writes: > >I'm still not clear on this. Is it only the "top-level" qualifier that >is to be ignored for comparisons, or all qualifiers. For example, are >the following compatible or not: > > int f(const int * p); > int f(int * p); > >where the 'const' qualifier applies to the 'int' not to the 'pointer'. These are not compatible types. Thus, in your example, main() { extern f(int *); const int *q; f(q); } a diagnostic is required. Dave Prosser ...not an official X3J11 answer...
walter@hpclwjm.HP.COM (Walter Murray) (07/11/89)
Kathy Harris writes: > I'm still not clear on this. Is it only the "top-level" qualifier that > is to be ignored for comparisons, or all qualifiers. Only the "top-level" qualifier, as you call it. This gets into the concept of "top type", or "type category" as it is now called. (See 3.1.2.5.) I think the key statement is, "A derived type is not qualified by the qualifiers (if any) of the type from which it is derived." Page 25, line 22, 12/88 dpANS. For example, "int * const p" is a qualified type, but "const int * p" is not, if I have it right. > For example, are > the following compatible or not: > int f(const int * p); > int f(int * p); > where the 'const' qualifier applies to the 'int' not to the 'pointer'. These are *NOT* compatible. But the following *ARE* compatible: int f(int * const p); int f(int * p); I hope someone who understands "top type" will confirm my understanding on this, or straighten me out. > Kathy Harris Walter Murray Not speaking for X3J11 or Hewlett-Packard. ----------
dfp@cbnewsl.ATT.COM (david.f.prosser) (07/11/89)
In article <12570016@hpclscu.HP.COM> shankar@hpclscu.HP.COM (Shankar Unni) writes: >Thus, the point to be made clear, IMO, is that the "function type" really >contains an imaginary parameter list, which is identical to the parameter >list with which it is declared, except that the qualifiers on the parameter >types are ignored. > >E.g., in the function definition > > int foo (const int bar) { /* */ } > >the type of "foo" is > > int () (int) > >(my notation for: return type == int, parameter list = "int"). However, the >type of "bar" is "const int". > >Am I off target? Maybe a slight clarification needs to be put into the >standard or the rationale at some stage. I think you've got it. Two types must be compatible before a composite type from the two can be attempted. When checking whether two prototypes are compatible, the "meaningless" type qualifiers are stripped from each parameter, and each function or array parameter is rewritten as an appropriate pointer type. It is this rewritten type that must be used for the composite type construction. On the other hand, it doesn't matter whether the "meaningless" qualifiers are kept in the composite type, since they are always ignored for all purposes, except within the function definition. At this point, I doubt that anything will be done to the Rationale or the pANS, but the interpretations phase of the Committee must answer these sorts of questions, but it will probably takes months... Dave Prosser ...not an official X3J11 answer...
gwyn@smoke.BRL.MIL (Doug Gwyn) (07/12/89)
In article <12570017@hpclwjm.HP.COM> walter@hpclwjm.HP.COM (Walter Murray) writes: >I hope someone who understands "top type" will confirm my understanding >on this, or straighten me out. I think you got it right. A pointer to a qualified type is not itself a qualified type (unless of course an ADDITIONAL qualifier is supplied at the top level). You think 3.1.2.5 is puzzling now, you should have seen it before the last major overhaul. I think it's about as clear as we are able to make it. I don't know if that reflects upon the actual language design or upon our ability to describe it..