Warnings during build with older version of clang

H. Thiele thiele at streamline-x.org
Tue Apr 16 22:59:13 UTC 2024


Hi there,

On 13/04/24 9:15 AM, Uli Schlachter wrote:

> So... this might not be a helpful answer, but: Are you sure you didn't 
> also get the warning before?

It's my first time building Cairo myself. The old build came in via
"Homebrew" (probably in a "binary bottle") which I'm currently in the
process of entirely wiping off my installation… one package at a time.


> For what is actually going on: Cairo plays some tricks with enums. There 
> is a cairo_status_t that is public API and there is _cairo_int_status 
> that is used internally and has more values. As far as I know, this is 
> legal C code that existed in cairo before I even knew what cairo was. 
> So, I can't say why you get this warning.

Thanks to your hints and input I managed to write a somewhat "elaborate"
test to reproduce the warnings in some simple code (see attachment) and
verify what it actually would generate in the end.

The good news is that code parts in those cases do NOT get optimized
away. That's entirely different to the pretty much same sounding warning
about signed comparison (-Wtautological-compare) where code actually
DOES get optimized away. I'm familiar with that one, hence when another
warning sounds pretty much the same, then I do assume the compiler also
does the same? Not the case! So this -Wtautological-constant-out-of-
range-compare is just one heck of useless warning with a very confusing
message it seems. Also its implementation seems to be a bit buggy in my
old version of clang (see comments in the example code).

Other observations I made along the way:
* the warnings can be silenced by casting the enum type variables to
   (int) (I could make a diff/patch, if needed?)
* GNU gcc (v9.2 here) doesn't warn about those, but has countless
   warnings about things that "may be used uninitialized".
* forcing clang into a more modern C standard breaks the build entirely
   (-Dc_std='c11' or -Dc_std='c99' as inputs for the meson build)



For now I assume my Cairo build is actually working as designed. If not
then I may find out in a month or two with my current speed of building 
more packages when something, that depends on Cairo, will randomly crash
or misbehave in unexpected other ways. :-)

Thanks for your reply, Uli!

H. Thiele
-------------- next part --------------
/*  Compile with optimization:
 *  $ clang -O3 foobar.c -o foobar4
 */

#include <stdio.h>

typedef enum {
	a, /* 0 */
	b, /* 1 */
	/* c, <- if I add that, then the first warning
	 * goes away too w/o need for int casting
	 */
} test_enum_t;

typedef enum {
	f = 0,
	/* skip one */
	g = 2, 
} test_enum2_t;

typedef enum {
    x, /* 0 */
	y, /* 1 */
	z, /* 2 */
} test_enum3_t;


int main() {
	/* Note: volatile to make it assume this are "hot" variables and not just constants
	 */
	test_enum_t  volatile test  = 5; /* here it probably should trigger a warning instead, like "enum out of range!" */
	test_enum2_t volatile test2 = 5;
	test_enum3_t volatile test3 = 5;
	unsigned int volatile test4 = 5;

	/*  it assumes "test" only can be 0 or 1, but not 2, so it triggers the odd warning:
	 *
	 *  warning: comparison of constant 2 with expression of type 'test_enum_t' is always
	 *     true [-Wtautological-constant-out-of-range-compare]
	 */
	if (test < 2) 	{
		printf("1: true\n");
	} else {
		printf("1: false\n");
	}

	/*  We can silence the warning by casting the enum type to int
	 */
	if ((int)test < 2) {
		printf("2: true\n");
	} else {
		printf("2: false\n");
	}

	/*  It doesn't warn here for some reason…  shouldn't it?
	 */
	if (test2 < 3) {
		printf("3: true\n");
	} else {
		printf("3: false\n");
	}

	if (test3 < 3) {
		printf("4: true\n");
	} else {
		printf("4: false\n");
	}

	/*  …but here it does again…
	 *
	 *  warning: comparison of constant 4 with expression of type 'test_enum2_t' is
	 *       always true [-Wtautological-constant-out-of-range-compare]
	 *  warning: comparison of constant 4 with expression of type 'test_enum3_t' is
	 *       always true [-Wtautological-constant-out-of-range-compare]
	 */
	if (test2 < 4) {
		printf("5: true\n");
	} else {
		printf("5: false\n");
	}

	if (test3 < 4) {
		printf("6: true\n");
	} else {
		printf("6: false\n");
	}

	/*  And just for comparison, another warning, but the same wording about "always false/true":
	 *
	 *  warning: comparison of unsigned expression < 0 is always false [-Wtautological-compare]
	 */
	if (test4 < 0)
	{
		/* Note:  but unlike above cases this actually will be optimized away, since the
		 *        check is "always false", see results below. No "7: true" string makes it
		 *        to the binary.
		 */
		printf("7: true\n");
	} else {
		printf("7: false\n");
	}


	/*    $ ./foobar4 
	 *    1: false
	 *    2: false
	 *    3: false
	 *    4: false
	 *    5: false
	 *    6: false
	 *    7: false
	 */

	/*    $ strings -a foobar4 
	 *    7: false
	 *    1: false
	 *    2: false
	 *    3: false
	 *    4: false
	 *    5: false
	 *    6: false
	 *    6: true
	 *    5: true
	 *    4: true
	 *    3: true
	 *    2: true
	 *    1: true
	 */
	
	return 0;
}


More information about the cairo mailing list