Skip to content

Commit c3b9a39

Browse files
committed
compiler.h: Explain how __is_constexpr() works
The __is_constexpr() macro is dark magic. Shed some light on it with a comment to explain how and why it works. Acked-by: Gustavo A. R. Silva <[email protected]> Reviewed-by: Jani Nikula <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Kees Cook <[email protected]>
1 parent bd1ebf2 commit c3b9a39

File tree

1 file changed

+39
-0
lines changed

1 file changed

+39
-0
lines changed

include/linux/compiler.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,45 @@ static inline void *offset_to_ptr(const int *off)
231231
* This returns a constant expression while determining if an argument is
232232
* a constant expression, most importantly without evaluating the argument.
233233
* Glory to Martin Uecker <[email protected]>
234+
*
235+
* Details:
236+
* - sizeof() return an integer constant expression, and does not evaluate
237+
* the value of its operand; it only examines the type of its operand.
238+
* - The results of comparing two integer constant expressions is also
239+
* an integer constant expression.
240+
* - The first literal "8" isn't important. It could be any literal value.
241+
* - The second literal "8" is to avoid warnings about unaligned pointers;
242+
* this could otherwise just be "1".
243+
* - (long)(x) is used to avoid warnings about 64-bit types on 32-bit
244+
* architectures.
245+
* - The C Standard defines "null pointer constant", "(void *)0", as
246+
* distinct from other void pointers.
247+
* - If (x) is an integer constant expression, then the "* 0l" resolves
248+
* it into an integer constant expression of value 0. Since it is cast to
249+
* "void *", this makes the second operand a null pointer constant.
250+
* - If (x) is not an integer constant expression, then the second operand
251+
* resolves to a void pointer (but not a null pointer constant: the value
252+
* is not an integer constant 0).
253+
* - The conditional operator's third operand, "(int *)8", is an object
254+
* pointer (to type "int").
255+
* - The behavior (including the return type) of the conditional operator
256+
* ("operand1 ? operand2 : operand3") depends on the kind of expressions
257+
* given for the second and third operands. This is the central mechanism
258+
* of the macro:
259+
* - When one operand is a null pointer constant (i.e. when x is an integer
260+
* constant expression) and the other is an object pointer (i.e. our
261+
* third operand), the conditional operator returns the type of the
262+
* object pointer operand (i.e. "int *). Here, within the sizeof(), we
263+
* would then get:
264+
* sizeof(*((int *)(...)) == sizeof(int) == 4
265+
* - When one operand is a void pointer (i.e. when x is not an integer
266+
* constant expression) and the other is an object pointer (i.e. our
267+
* third operand), the conditional operator returns a "void *" type.
268+
* Here, within the sizeof(), we would then get:
269+
* sizeof(*((void *)(...)) == sizeof(void) == 1
270+
* - The equality comparison to "sizeof(int)" therefore depends on (x):
271+
* sizeof(int) == sizeof(int) (x) was a constant expression
272+
* sizeof(int) != sizeof(void) (x) was not a constant expression
234273
*/
235274
#define __is_constexpr(x) \
236275
(sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))

0 commit comments

Comments
 (0)