Topic: Array function params and const qualifier
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1996/04/11 Raw View
In article rp3@mozart.wg.icl.co.uk, Adel El-Beik <A.El-Beik@man0506.wins.icl.co.uk> writes:
>I have a question concerning MSVC++ v.4.00 and the April DWP C++.
>
>The following code fails on MSVC++. It doesn't like line labelled 1.
>It complains with
>
>C:\array\array.cpp(16) : error C2664: 'func' : cannot convert parameter 1
>from 'long [2][2]' to 'const long [][2]' (new behavior; please see help)
You have run into effectively the same rule that prohibits implicit
conversion from "T**" to "const T**". That prohibition is not new,
but is in the ISO/ANSI C standard, and has not been changed, since
it would open a hole in the type system.
I believe the subject is covered in the comp.lang.c FAQ list.
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/04/12 Raw View
clamage@Eng.Sun.COM (Steve Clamage) writes:
>Adel El-Beik <A.El-Beik@man0506.wins.icl.co.uk> writes:
>>I have a question concerning MSVC++ v.4.00 and the April DWP C++.
>>
>>The following code fails on MSVC++. It doesn't like line labelled 1.
>>It complains with
>>
>>C:\array\array.cpp(16) : error C2664: 'func' : cannot convert parameter 1
>>from 'long [2][2]' to 'const long [][2]' (new behavior; please see help)
>
>You have run into effectively the same rule that prohibits implicit
>conversion from "T**" to "const T**". That prohibition is not new,
>but is in the ISO/ANSI C standard, and has not been changed, since
>it would open a hole in the type system.
I suspect you are mistaken. I believe Adel El-Beik has run into a bug
in MSVC++, rather than any prohibition in the draft C++ standard.
By my reading of the January 96 draft, I believe Adel El-Beik's code is
well-formed (i.e. legal).
[moderator's note: I agree I was wrong. Sorry for the confusion. -sdc ]
>I believe the subject is covered in the comp.lang.c FAQ list.
The comp.lang.c FAQ list may cover the case of conversion from `T**' to
`const T**' (although I couldn't find it in my old copy), but I'm sure
it does not cover the case of conversion from `T[n][m]' to `const
T(*)[m]', which I think is quite safe, and which is, I believe,
permitted by the draft C++ standard.
Here's the code again, and an explanation of why I believe the code is legal.
typedef long bar[2][2];
void func( const bar param ){}
int main()
{
bar x;
func(x); // rejected by
}
The parameter of `func' is declared to have type `const bar', where
`bar' is a typedef which names an array type. Consulting 3.9.3/3,
| 3.9.3 CV-qualifiers [basic.type.qualifier]
|
| 2 A compound type (_basic.compound_) is not cv-qualified by the cv-
| qualifiers (if any) of the type from which it is compounded. Any cv-
| qualifiers that appear in an array declaration apply to the array ele-
| ment type, not the array type (_dcl.array_).
I think we can discern that the declared type of the
parameter is "array [2] of array [2] of const long", rather than
"const array [2] of array [2] of long". The wording is quite vague [*]
but I'm pretty sure that's the intent. However, this is certainly
the weakest step in my chain of reasoning.
[*] What exactly is an "array declaration"? Does `const bar'
count as one? Does this rule apply recursively to arrays
of arrays?
Next, we need to consult 8.3.5/3.
| 8.3.5 Functions [dcl.fct]
|
| 3 [...] The type of a function is determined using the follow-
| ing rules. The type of each parameter is determined from its own
| decl-specifier-seq and declarator. After determining the type of each
| parameter, any parameter of type "array of T" or "function returning
| T" is adjusted to be "pointer to T" or "pointer to function returning
| T," respectively. [...]
In this case, the type of the parameter is adjusted from "array [2] of
array [2] of const long" to "pointer to array [2] of const long".
So, we are trying to convert a value of type "array [2] of array [2] of long"
to type "pointer to array [2] of const long". According to 4/1,
| 4 Standard conversions [conv]
|
| 1 Standard conversions are implicit conversions defined for built-in
| types. The full set of such conversions is enumerated in this clause.
| A standard conversion sequence is a sequence of standard conversions
| in the following order:
|
| --Zero or one conversion from the following set: lvalue-to-rvalue con-
| version, array-to-pointer conversion, and function-to-pointer con-
| version.
|
| --Zero or one conversion from the following set: integral promotions,
| floating point promotion, integral conversions, floating point con-
| versions, floating-integral conversions, pointer conversions,
| pointer to member conversions, base class conversions, and boolean
| conversions.
|
| --Zero or one qualification conversion.
The first conversion we apply, then, is an array-to-pointer conversion.
Consulting 4.2/1,
| 4.2 Array-to-pointer conversion [conv.array]
|
| 1 An lvalue or rvalue of type "array of N T" or "array of unknown bound
| of T" can be converted to an rvalue of type "pointer to T." The
| result is a pointer to the first element of the array.
we see that we can convert our value of type "array [2] of array[2] of long"
to "pointer to array [2] of long".
We don't need to apply any conversions from the second set, but we
do need to apply a qualification conversion before we can get to
"pointer to array [2] of const long". At first glance, 4.4/1
| 4.4 Qualification conversions [conv.qual]
|
| 1 An rvalue of type "pointer to cv1 T" can be converted to an rvalue of
| type "pointer to cv2 T" if "cv2 T" is more cv-qualified than "cv1 T."
does not seem to be of any help, since the "const" is on the wrong
side of the "array of". However, this must be read in the context
of 3.9.3/5.
| 3.9.3 CV-qualifiers [basic.type.qualifier]
|
| 5 In this International Standard, the notation cv (or cv1, cv2, etc.),
| used in the description of types, represents an arbitrary set of cv-
| qualifiers, i.e., one of {const}, {volatile}, {const, volatile}, or
| the empty set. Cv-qualifiers applied to an array type attach to the
| underlying element type, so the notation "cv T," where T is an array
| type, refers to an array whose elements are so-qualified. Such array
| types can be said to be more (or less) cv-qualified than other types
| based on the cv-qualification of the underlying element types.
In our case, T is indeed an array type. Reading 4.4/1 with `cv T'
everywhere replaced with `array of cv T', as is required by 3.9.3,
gives us the following rule:
|| An rvalue of type "pointer to array of cv1 T" can be converted to an
|| rvalue of type "pointer to array of cv2 T" if "cv2 T" is more
|| cv-qualified than "cv1 T."
Applying this rule to the case in question, we can convert to "pointer
to array [2] of long" to "pointer to array [2] of const long", since
"const long" is more cv-qualified than "long". At this point, we
have shown that there exists a standard conversion sequence which converts
the type of the actual parameter of `func' to the type of its formal
parameter, and so it should be clear that the example is well-formed.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: jason@cygnus.com (Jason Merrill)
Date: 1996/04/12 Raw View
>>>>> Steve Clamage <clamage@Eng.Sun.COM> writes:
> In article rp3@mozart.wg.icl.co.uk, Adel El-Beik <A.El-Beik@man0506.wins.icl.co.uk> writes:
>> I have a question concerning MSVC++ v.4.00 and the April DWP C++.
>>
>> The following code fails on MSVC++. It doesn't like line labelled 1.
>> It complains with
>>
>> C:\array\array.cpp(16) : error C2664: 'func' : cannot convert parameter 1
>> from 'long [2][2]' to 'const long [][2]' (new behavior; please see help)
> You have run into effectively the same rule that prohibits implicit
> conversion from "T**" to "const T**". That prohibition is not new,
> but is in the ISO/ANSI C standard, and has not been changed, since
> it would open a hole in the type system.
But converting long (*)[2] to const long (*)[2] is more like converting
long ** to const long *const * than it is like converting long ** to const
long **, because there is no way to modify the array -- there is, in fact,
no array entity in memory, only two longs. A long (*)[2] points to two
longs, whereas a const long (*)[2] points to two const longs. I don't see
a constness hole there.
I suspect this is an oversight.
Jason
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/04/15 Raw View
[Note: this article is crossposted to comp.std.c++ and comp.std.c.]
In comp.std.c++, jason@cygnus.com (Jason Merrill) writes:
>>>>>> Steve Clamage <clamage@Eng.Sun.COM> writes:
>
>> Adel El-Beik <A.El-Beik@man0506.wins.icl.co.uk> writes:
>>> I have a question concerning MSVC++ v.4.00 and the April DWP C++.
[...]
>>> C:\array\array.cpp(16) : error C2664: 'func' : cannot convert parameter 1
>>> from 'long [2][2]' to 'const long [][2]' (new behavior; please see help)
>
>> You have run into effectively the same rule that prohibits implicit
>> conversion from "T**" to "const T**". That prohibition is not new,
>> but is in the ISO/ANSI C standard, and has not been changed, since
>> it would open a hole in the type system.
>
>But converting long (*)[2] to const long (*)[2] is more like converting
>long ** to const long *const * than it is like converting long ** to const
>long **, because there is no way to modify the array -- there is, in fact,
>no array entity in memory, only two longs. A long (*)[2] points to two
>longs, whereas a const long (*)[2] points to two const longs. I don't see
>a constness hole there.
>
>I suspect this is an oversight.
Yes, but the oversight is in the implementation, not in the standard.
The conversion in question is allowed by the draft C++ standard. (See
my other post to comp.std.c++ in this thread for a detailed explanation.)
The conversion is also allowed by a variety of other implementations,
including cfront, gcc, and SGI C++ (EDG).
Interestingly, even though this conversion is presumably disallowed by
the ANSI/ISO C standard, many supposedly conforming C compilers fail to
issue a diagnostic for it. Of the six I tried, only two issued any
diagnostic, even with all the appropriate options for selecting ANSI
conformance and enabling warnings.
Compiler Options Diagnostic?
-------- ------- -----------
GNU C gcc -ansi -pedantic -Wall No
SGI C cc -ansi -pedantic -fullwarn -wlint,p No
DEC OSF/1 C cc -std1 No
DEC C cc -std1 -migrate -check No
Sun C cc -Xc -v Yes (warning)
LCC lcc -A -A Yes (error)
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Adel El-Beik <A.El-Beik@man0506.wins.icl.co.uk>
Date: 1996/04/10 Raw View
I have a question concerning MSVC++ v.4.00 and the April DWP C++.
The following code fails on MSVC++. It doesn't like line labelled 1.
It complains with
C:\array\array.cpp(16) : error C2664: 'func' : cannot convert parameter 1
from 'long [2][2]' to 'const long [][2]' (new behavior; please see help)
Now as far as I can understand from DWP an implicit conversion should
take place on x. i.e. it is const qualified, and so MSVC++ should not
raise an error. MSVC++ accepts line labelled 2, which should be
what MSVC++ converts the funcion argument and parameter to on 1.
Is their something I've missed, i.e. MSVC++ behaviour matches April
DWP ? Or is MSVC++ followed its own standard, Microsoft claim to
be following evolving standard.
Thanks in advance.
Adel.
// CODE START
typedef long bar[2][2];
typedef const long (*const_bar)[2];
void func( const bar param ){}
void main()
{
bar x;
func( x ); // 1
func( (const_bar)x ); // 2
}
// CODE END
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]