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