1

This line-palindromic entry from the 1987 IOCCC:

https://www.ioccc.org/years.html#1987_westley

...is causing TCC 0.9.27 no issues during default compilation and works as intended.

However, GCC 9.3.0, even in -std=c89 mode, complains that the following instances of (int) (tni) are not lvalues:

    for (; (int) (tni);)
        (int) (tni) = reviled;
                    ^
(lvalue required as left operand of assignment)
...
    for ((int) (tni)++, ++reviled; reviled * *deliver; deliver++, ++(int) (tni))
                                                                  ^~
(lvalue required as increment operand)

(code beautified for better context)

My current thoughts:

In the = case, I suspect that the use of (int) (tni) as a condition in the for loop is disqualifying it as a lvalue, but I am not sure.

In the ++ case, I can see later in that code how its palindromic nature forces the author to use a -- operator between (int) and (tni) which is not considered as an issue. So GCC requires the ++ operator just before the variable, not before its casting, but hints at this requirement with a lvalue complaint.

Is there a definitive answer to these GCC complaints? Is TCC too lax in letting these off the hook?

Thanks in advance!

EDIT: I was kindly pointed towards a similar question which answers the casting issue here - please see my comment below for the solution!

  • 1
    according to comments in the question I linked - lvalue casts used to be a gcc extension that was removed in 2005 –  Oct 15 '20 at 10:52
  • Thanks for the related question suggested! The way to "fix" the disallowed cast in this code is to replace the two offending ```(int)(tni)``` instances with ```*((int*)&(tni))``` - now GCC happily compiles it and the result is as expected. – ChemicalDruid Oct 15 '20 at 12:41

1 Answers1

2

TCC is not a conforming C implementation as is well known - TCC tries to be small and fast compiler that attempts to compile correct C code, and it often does not produce diagnostics that would be required by the standard. And as is known even more widely is that the first C standard came into being in 1989, and most widely known is that year 1987 preceded 1989.

C11 6.5.4p5:

  1. Preceding an expression by a parenthesized type name converts the value of the expression to the named type. This construction is called a cast. 104) A cast that specifies no conversion has no effect on the type or value of an expression.

The footnote 104 notes that:

  1. A cast does not yield an lvalue. Thus, a cast to a qualified type has the same effect as a cast to the unqualified version of the type.

For assignment operator, 6.5.16p2 says:

  1. An assignment operator shall have a modifiable lvalue as its left operand.

6.5.16p2 is in constraint section, so violations must be diagnosed.

  • 1
    Would "That is a bug in TCC." be a summary or inappropriatly simplifying things? (If neither I think I did not get the point of your answer....) – Yunnosch Oct 15 '20 at 10:43
  • For all code written before 1989 I would use a non-conforming C implementation, but would also like to know if more conforming implementations such as GCC have enough "empathy" for such pre-1989 code :) – ChemicalDruid Oct 15 '20 at 10:46
  • @Yunnosch it is not a "bug" in TCC, in TCC these kinds of things are "features", it's what makes it fast and *small*. TCC wants to compile correct C programs *fast* and *correctly* and it is not compromised here. – Antti Haapala -- Слава Україні Oct 15 '20 at 11:20
  • I thought that I was not getting everything here. Maybe put that into the answer itself? – Yunnosch Oct 15 '20 at 12:01