On 12/3/25 01:38, Александр Поваляев via Gcc wrote:
Hi there! Thank you for being on it!
You've written quite a lot of messages and replies. Thank you again for
this.
However, I still don't see how you're proving that such a kind of
conversion must be rejected by any C compiler within an error.
Liu previously tried to do it (to provide logical reasoning), but his prove
lacks some logical consistency.
And so, I don't see that such conversion ("Foo**" -> "const Foo * const *
const) is NOT explicitly prohibited by C standard.
Per ISO/IEC 9899:2023 section 6.7.10 clause 12 states "The initializer
for a scalar shall be a single expression, optionally enclosed in
braces, or it shall be an empty initializer. If the initializer is the
empty initializer, the initial value is the same as the initialization
of a static storage duration object. Otherwise, the initial value of the
object is that of the expression (after conversion); the same type
constraints and conversions as for simple assignment apply, taking the
type of the scalar to be the unqualified version of its declared type."
Because the question is about assigning to an object with type "const
Foo * const * const", the resultant type of the RHS must be "const Foo *
const *" for the initialization to be legal.
With that requirement, the question that must be answered is "can Foo**
be implicitly converted to const Foo * const *?". To answer that the
constraints and conversions of simple assignment must be reviewed. The
constraints are listed in 6.5.16.1.
Section 6.5.16.1 clause 1 states that one of the constraints shall hold.
Considering each constraint the only one that could possibly hold is
"the left operand has atomic, qualified, or unqualified pointer type,
and (considering the type the left operand would have after lvalue
conversion) both operands are pointers to qualified or unqualified
versions of compatible types, and the type pointed to by the left
operand has all the qualifiers of the type pointed to by the right operand".
However, this constraint holds only if "Foo**" is a compatible type of
"const Foo * const *".
Which leads to section 6.7.6.1 paragraph 2, "For two pointer types to be
compatible, both shall be identically qualified and both shall be
pointers to compatible types."
'Foo **' and 'const Foo * const *' are not identically qualified.
Therefore, they are not compatible.
This also means the constraint I referenced from 6.5.16.1 does not hold;
therefore, initializing an object of type const Foo * const * (or const
Foo * const * const) with a value of type Foo** results in a constraint
violation.
and per section section 5.1.1.3 clause 1, "A conforming implementation
shall produce at least one diagnostic message (identified in an
implementation-defined manner) if a preprocessing translation unit or
translation unit contains a violation of any syntax rule or constraint,
even if the behavior is also explicitly specified as undefined or
implementation-defined. Diagnostic messages need not be produced in
other circumstances."
the compiler is required to produce a "diagnostic message".
And still there is no sign that what is not explicitly prohibited by C
standard should end up with a compiler error.
Based on my read and understand of the specification, you are correct.
There is nothing that says it should end up as a compiler error.
Conversely, there's nothing in the standard that forbids it either.
The only requirement is that a "diagnostic message" be produced.
> > Per my understanding, an error "diagnostic" message should be
present only
if there is a possible way of getting the program working wrong or leading
to fault.
And a warning "diagnostic" message should be present if there is a possible
way of unsafe behavior.
The C standard makes no such distinctions, only that the message be
generated in an "implementation-defined" manner. Therefore, if your
understanding is correct, then the behavior as you described it should
be documented inside the GCC manual. I leave it as an exercise for you
to find the relevant passage(s).
But in our case, a conversion "Foo**" -> "const Foo * const * const" is an
absolutely safe way of coding.
safe or not, it's forbidden as explained above.
This is the reason why commercial compilers (like Microsoft/IBM and Intel)
DO support such a kind of conversion.
And so this is an artefact.
It appears when an absolutely safe way of coding which is not explicitly
prohibited by C standard is identified by an ERROR.
I consider such behaviour as a BUG which should be fixed.
This is my attitude.
It is prohibited, as explained above. GCC's behavior is not a bug.
Regards,
Nicholas Vinson
Respectfully,
Aleksandr G Povaliaev.
ср, 3 дек. 2025 г. в 06:08, Andrey Tarasevich <[email protected]>:
It looks like we are getting nowhere here... To conclude this "discussion"
I'll
reiterate just the relevant points as concisely as I can:
1. Standard C language does not allow the following pointer conversions as
implicit conversions:
T ** -> const T *const *
T ** -> const T *const *const
A program that attempts to rely on such conversions (as implicit
conversions) is
invalid, i.e. it contains a constraint violation - a "hard error" in
standard C.
2. Compliant C compilers are required to issue diagnostic messages for
constraint violations. Format and wording of such diagnostic messages are
not
standardized in any way. Standard C does not have concepts of "errors" or
"warnings".
It is your responsibility to figure out that a diagnostic message issued
for
this constraint violation indicates a "hard error", provided you possess
sufficiently pedantic knowledge of C standard. If you don't possess this
level
of knowledge of C standard (which is apparently the case in your case),
but
still want to write code in standard C, configuration settings like
`-pedantic-errors` will help you. Moreover, in the latter case, you are
not
allowed to even approach C compilers without `-pedantic-errors`. Trying to
do so
will only lead to confusion.
3. If you do not have a "language-lawyer" level of knowledge of C
standard, you
do not get to make such bold statements as "I found a bug in C compiler".
Which
is well-illustrated by this thread: in this case there's no bug. The
compiler is
behaving 100% correctly, despite your claims to the contrary.
4. As it has been stated repeatedly, there's ongoing work aiming to
support such
conversions in future iterations of C language standard. But as of C23,
these
conversions are not supported (as implicit conversions).
--
Best regards,
Andrey