Open chestnykh opened 1 week ago
@llvm/issue-subscribers-clang-frontend
Author: Dmitry Chestnykh (chestnykh)
CC: @AaronBallman @Fznamznon
&f - &f
is constraint-violating ("ill-formed") in C, and Clang conformingly rejects it with -pedantic-errors
(Godbolt link).
Per 6.6 p10
An arithmetic constant expression shall have arithmetic type and shall only have operands that are integer literals, floating literals, named or compound literal constants of arithmetic type, character literals, sizeof expressions whose results are integer constant expressions, and alignof expressions.
AFAIK pointer type is not an arithmetic type, so I guess this is not valid.
It is a funny thing that clang accepts it as "GNU extension" whereas gcc rejects it.
@AaronBallman , would it be better to always reject for constexpr
variables?
We have latitude to extend what is a valid constant expression (C23 6.6p14: An implementation may accept other forms of constant expressions; however, it is implementation-defined whether they are an integer constant expression.)
The GNU extension is on arithmetic with function pointer types (that's UB in C, see C23 6.5.7p2), so Clang is fine to support that. (C23 6.6p11 points out that an address constant can be a pointer to a function designator, so because Clang allows addition and subtraction on non-object types, that function pointer type is still an address constant, and thus is fine to use in an arithmetic constant expression, which is valid for use in an initializer.)
The behavior with const int
is both correct per spec and perhaps a bit suspect in Clang thanks to extensions.
C23 6.7.2p6: If an object or subobject declared with storage-class specifier constexpr has pointer, integer, or arithmetic type, any explicit initializer value for it shall be null, an integer constant expression, or an arithmetic constant expression, respectively. ...
So given:
const int x = 4;
constexpr auto a = x - x;
we deduce the type of a
as being int
and thus the object has integer type, and thus requires the initializer to be an integer constant expression. Clang and GCC both reject because use of const int
does not produce a valid integer constant expression (C23 6.6p8). This is why you get a VLA warning in code like this: https://godbolt.org/z/P1nYveWKs. However, if we change the example slightly, then GCC accepts... and Clang continues to reject:
const int x = 4;
constexpr float a = x - x;
Now a
has an arithmetic type rather than an integer type, and so the initializer is required to be an arithmetic constant expression. It seems GCC allows const int
in an arithmetic constant expression but Clang does not: https://godbolt.org/z/nfTKW4r51
So I think Clang's behavior here is correct, but we may have a GCC compatibility bug regarding what's considered a valid arithmetic constant expression. GCC may have the behavior they have because extending an integer constant expression can be awkward thanks to VLAs, but extending an arithmetic constant expression only impacts what's a valid object initializer.
(that's UB in C, see C23 6.5.7p2)
Oh, IIUC that's not UB, because the paragraph is under Constraints.
(that's UB in C, see C23 6.5.7p2)
Oh, IIUC that's not UB, because the paragraph is under Constraints.
Ah sorry, yes, that's a constraint violation not pure UB. The end result is the same either way -- we extend the language and issue a pedantic diagnostic as a result.
Consider the following code
but trunk gcc rejects both constexpr variables with the same diagnostic
So i guess that clang should also reject the initialization of the 2nd constexpr variable