I think it should not warn about:
char *x; *(char * volatile *)&x; as this is regular qualifier adding and this is a bug in GCC. I would guess it looks at all qualifiers added at all level but should ignore the one on the first level. Martin Am Samstag, dem 15.06.2024 um 10:17 -0700 schrieb Ryan Libby via Gcc: > I'm not a C language expert and I'm looking for advice on whether a > -Wcast-qual diagnostic in one situation and not another is intentional > behavior. > > Here's a set of examples (same as attachment). > > % cat cast-qual-example.c > #define F(name, type, qual) \ > typedef type t_##name; \ > void name(void) { \ > t_##name x = 0, y, z; \ > y = *(t_##name qual *)&x; \ > z = *(t_##name qual *){&x}; \ > } > > F(fcc, char, const) > F(fpc, char *, const) > F(fcv, char, volatile) > F(fpv, char *, volatile) > > void fpv2(void) { > char *x = 0, *y, *z; > y = *(char * volatile *)&x; > z = *(char * volatile *){&x}; > } > > void eg1(void) { > /* Adapted from -Wcast-qual doc */ > char v0 = 'v'; > char *v1 = &v0; > char **p = &v1; > /* p is char ** value. */ > char * volatile *q = (char * volatile *) p; > /* Assignment of volatile pointer to char is OK. */ > char u0 = 'u'; > char * volatile u1 = &u0; > *q = u1; > /* Now *q is accessed through a non-volatile-qualified pointer. */ > *p = 0; > } > > void eg2(void) { > char v = 'v'; > char *p = &v; > /* p is char * value. */ > char volatile *q = (char volatile *) p; > /* Assignment of volatile char is OK (and also plain char). */ > char volatile u = 'u'; > *q = u; > /* Now *q is accessed through a non-volatile-qualified pointer. */ > *p = 0; > } > > % gcc13 -std=c17 -Wall -Wextra -Wcast-qual -Wno-unused -c > cast-qual-example.c -o /dev/null > cast-qual-example.c: In function 'fpv': > cast-qual-example.c:5:14: warning: to be safe all intermediate > pointers in cast from 'char **' to 'char * volatile*' must be 'const' > qualified [-Wcast-qual] > 5 | y = *(t_##name qual *)&x; \ > | ^ > cast-qual-example.c:12:1: note: in expansion of macro 'F' > 12 | F(fpv, char *, volatile) > | ^ > cast-qual-example.c: In function 'fpv2': > cast-qual-example.c:16:14: warning: to be safe all intermediate > pointers in cast from 'char **' to 'char * volatile*' must be 'const' > qualified [-Wcast-qual] > 16 | y = *(char * volatile *)&x; > | ^ > cast-qual-example.c: In function 'eg1': > cast-qual-example.c:26:30: warning: to be safe all intermediate > pointers in cast from 'char **' to 'char * volatile*' must be 'const' > qualified [-Wcast-qual] > 26 | char * volatile *q = (char * volatile *) p; > | ^ > % clang -std=c17 -Wall -Wextra -Wcast-qual -Wno-unused -c > cast-qual-example.c -o /dev/null > % > > The macro and typedef are to illustrate the point, they aren't otherwise > needed, and fpv2 shows the same thing without them. > > So, in the conversion of char ** to char * volatile *, the cast before > the assignment of y is diagnosed, but the conversion in the > initialization of the compound literal for the assignment of z is not. > > First, is the cast construct actually different from the initialization > construct in terms of safety? I would think not, but maybe I am > missing something. > > I think that both assignment expressions in fpv as a whole are > ultimately safe, considering also the immediate dereference of the > temporary outer pointer value. > > In eg1 and eg2 I modified examples from the -Wcast-qual documentation. > eg1 is diagnosed, eg2 is not. > > I think that the *p assignment in eg1 might be undefined behavior > (6.7.3, referring to an object with volatile-qualified type (*q) through > an lvalue without volatile-qualified type (*p)). > > But then I don't get why the same wouldn't be true if we take away the > inner pointer and repeat the exercise with plain char (eg1 vs eg2). > > So, what's going on here? Is the gcc behavior intentional? Is it > consistent? And is there a recommended way to construct a temporary > volatile pointer to an object (which may itself be a pointer) without > tripping -Wcast-qual, without just casting away type information (as in, > without intermediate casts through void *, uintptr_t, etc), and > preferably also without undefined behavior? > > I have checked that the behavior is the same with current sources and > -std=c23 (gcc (GCC) 15.0.0 20240614 (experimental)). > > P.s. I have seen gcc bug 84166 that advises that the -Wcast-qual warning > from the cast is intentional in that case. I think this case is > different because in that case the qualifiers are on the innermost type. > > Thank you, > > Ryan Libby