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

Reply via email to