+2020-08-25 Bruno Haible <bruno@clisp.org>
+
+ verify: Avoid warnings when assume(0) is used.
+ Reported by Mattias EngdegÄrd <mattiase@acm.org> via Paul Eggert in
+ <https://lists.gnu.org/archive/html/emacs-devel/2020-08/msg00838.html>.
+ * lib/verify.h (assume): Use __builtin_unreachable if the argument is
+ the constant 0.
+ * tests/test-verify.c (f): New function.
+ (state): New type.
+ (test_assume_expressions, test_assume_optimization,
+ test_assume_noreturn): New functions.
+
2020-08-25 Bruno Haible <bruno@clisp.org>
fstrcmp: Clarification regarding NOTE_ORDERED.
based on __builtin_unreachable does not. (GCC so far has only
__builtin_unreachable.) */
#if _GL_HAS_BUILTIN_ASSUME
-/* Use a temporary variable, to avoid a clang warning
+/* Use __builtin_constant_p to help clang's data-flow analysis for the case
+ assume (0).
+ Use a temporary variable, to avoid a clang warning
"the argument to '__builtin_assume' has side effects that will be discarded"
if R contains invocations of functions not marked as 'const'.
The type of the temporary variable can't be __typeof__ (R), because that
instead. */
# if defined __cplusplus
# define assume(R) \
- ((void) ({ bool _gl_verify_temp = (R); \
- __builtin_assume (_gl_verify_temp); }))
+ (__builtin_constant_p (R) && !(R) \
+ ? (void) __builtin_unreachable () \
+ : (void) ({ bool _gl_verify_temp = (R); \
+ __builtin_assume (_gl_verify_temp); }))
# else
# define assume(R) \
- ((void) ({ _Bool _gl_verify_temp = (R); \
- __builtin_assume (_gl_verify_temp); }))
+ (__builtin_constant_p (R) && !(R) \
+ ? (void) __builtin_unreachable () \
+ : (void) ({ _Bool _gl_verify_temp = (R); \
+ __builtin_assume (_gl_verify_temp); }))
# endif
#elif _GL_HAS_BUILTIN_UNREACHABLE
# define assume(R) ((R) ? (void) 0 : __builtin_unreachable ())
# define EXP_FAIL 0
#endif
+/* ======================= Test verify, verify_expr ======================= */
+
int x;
enum { a, b, c };
{
return !(function (0) == 0 && function (1) == 8);
}
+
+/* ============================== Test assume ============================== */
+
+static int
+f (int a)
+{
+ return a;
+}
+
+typedef struct { unsigned int context : 4; unsigned int halt : 1; } state;
+
+void
+test_assume_expressions (state *s)
+{
+ /* Check that 'assume' accepts a function call, even of a non-const
+ function. */
+ assume (f (1));
+ /* Check that 'assume' accepts a bit-field expression. */
+ assume (s->halt);
+}
+
+int
+test_assume_optimization (int x)
+{
+ /* Check that the compiler uses 'assume' for optimization.
+ This function, when compiled with optimization, should have code
+ equivalent to
+ return x + 3;
+ Use 'objdump --disassemble test-verify.o' to verify this. */
+ assume (x >= 4);
+ return (x > 1 ? x + 3 : 2 * x + 10);
+}
+
+_Noreturn void
+test_assume_noreturn (void)
+{
+ /* Check that the compiler's data-flow analysis recognizes 'assume (0)'.
+ This function should not elicit a warning. */
+ assume (0);
+}