• Why does clang 10.0.1 (FreeBSD 12.2) warn about this?

    From The Doctor@21:1/5 to wbe@UBEBLOCK.psr.com.invalid on Sun Feb 7 13:38:37 2021
    In article <ydr1lsa5yv.fsf@UBEblock.psr.com>,
    Winston <wbe@UBEBLOCK.psr.com.invalid> wrote:
    Passing char *p to a function foo(const char *p) is common.

    Passing const char *p to a function foo(char *p) gets a warning about >discarding const, as one would expect.

    Maybe I'm just not thinking clearly at the moment, but I don't see why >passing char *p using foo(&p) to the function foo(const char **pp) causes >this warning:

    [...].c: warning: passing 'char **' to parameter of type 'const char **'
    discards qualifiers in nested pointer types
    [-Wincompatible-pointer-types-discards-qualifiers]

    [...].h: note: passing argument to parameter 'pp' here
    extern char * foo(const char **pp);

    Is this a bug, or what am I missing? Thanks,
    -WBE

    Is this a port or a newly made application?
    --
    Member - Liberal International This is doctor@@nl2k.ab.ca Ici doctor@@nl2k.ab.ca
    Yahweh, Queen & country!Never Satan President Republic!Beware AntiChrist rising!
    Look at Psalms 14 and 53 on Atheism https://www.empire.kred/ROOTNK?t=94a1f39b NFLD on 13 Feb vote Liberal !

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Winston@21:1/5 to The Doctor on Mon Feb 8 02:02:23 2021
    I previously posted:
    Passing char *p to a function foo(const char *p) is common.

    Passing const char *p to a function foo(char *p) gets a warning about >>discarding const, as one would expect.

    Maybe I'm just not thinking clearly at the moment, but I don't see why >>passing char *p using foo(&p) to the function foo(const char **pp) causes >>this warning:

    [...].c: warning: passing 'char **' to parameter of type 'const char **'
    discards qualifiers in nested pointer types
    [-Wincompatible-pointer-types-discards-qualifiers]

    [...].h: note: passing argument to parameter 'pp' here
    extern char * foo(const char **pp);

    Is this a bug, or what am I missing? Thanks,

    to which doctor@doctor.nl2k.ab.ca (The Doctor) asked:
    Is this a port or a newly made application?

    It was code I'd just written, not something distributed by FreeBSD.
    -WBE

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Floyd@21:1/5 to Winston on Mon Feb 8 09:54:45 2021
    On Sat, 06 Feb 2021 22:53:44 -0500, Winston <wbe@UBEBLOCK.psr.com.invalid> wrote:
    Passing char *p to a function foo(const char *p) is common.

    Passing const char *p to a function foo(char *p) gets a warning about discarding const, as one would expect.

    Maybe I'm just not thinking clearly at the moment, but I don't see why passing char *p using foo(&p) to the function foo(const char **pp) causes this warning:

    [...].c: warning: passing 'char **' to parameter of type 'const char **'
    discards qualifiers in nested pointer types
    [-Wincompatible-pointer-types-discards-qualifiers]

    [...].h: note: passing argument to parameter 'pp' here
    extern char * foo(const char **pp);

    It's a question of indirection. No indirection and one level of
    indirection will always be considered for implicit conversion. The
    second level (and any further levels) aren't automatically considered.
    See the entry on implicit conversion on cppreference.com

    A+
    Paul
    --
    Paul Floyd http://paulf.free.fr

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Winston@21:1/5 to kindly on Mon Feb 8 13:02:57 2021
    I originally posted:
    Maybe I'm just not thinking clearly at the moment, but I don't see why
    passing char *p using foo(&p) to the function foo(const char **pp) causes
    this warning:

    [...].c: warning: passing 'char **' to parameter of type 'const char **'
    discards qualifiers in nested pointer types
    [-Wincompatible-pointer-types-discards-qualifiers]

    [...].h: note: passing argument to parameter 'pp' here
    extern char * foo(const char **pp);

    Paul Floyd <root@127.0.0.1> kindly replied:
    It's a question of indirection. No indirection and one level of
    indirection will always be considered for implicit conversion. The
    second level (and any further levels) aren't automatically considered.

    OK, thanks. That would explain WHY.

    As to WHAT, I'll contend that a warning message that says "discards
    qualifiers" in such a case (the same as the compiler warns for (const
    char *) passed to a (char *) argument) is misleading.

    See the entry on implicit conversion on cppreference.com

    [To others reading this thread: the word "implicit" did not appear on https://cpreference.com/, and using the search box there to search for "implicit conversion" suprisingly found no results. After following a
    few likely links related to C (not C++), I ended up at:

    https://en.cppreference.com/w/c/language/conversion

    talking about conversions "as if by assignment" and "implicit conversion semantics". I saw nothing there about conversion depth, but at the
    bottom of that page, under "See also", it linked to a description of C++ implicit conversions. I followed that link to:

    https://en.cppreference.com/w/cpp/language/implicit_conversion

    which said that the addition of const/volatile qualifiers at arbitrary
    depths ARE acceptable, but that when there's effectively an array of
    unknown bounds involved, additional const qualifiers are needed. It
    gave a C++ example that pretty directly matched my original question:

    char** p = 0;
    const char** p1 = p; // error: level 2 more cv-qualified but level 1 is not const
    const char* const * p2 = p; // OK: level 2 more cv-qualified and const added at level 1

    I'm a bit surprised at this end result, but at least now I know about
    it. Thanks, Paul.
    -WBE

    [I still think "discards qualifiers" is misleading.
    "Requires qualifiers" for this case would be more accurate.]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Winston@21:1/5 to All on Sat Feb 6 22:53:44 2021
    Passing char *p to a function foo(const char *p) is common.

    Passing const char *p to a function foo(char *p) gets a warning about discarding const, as one would expect.

    Maybe I'm just not thinking clearly at the moment, but I don't see why
    passing char *p using foo(&p) to the function foo(const char **pp) causes
    this warning:

    [...].c: warning: passing 'char **' to parameter of type 'const char **'
    discards qualifiers in nested pointer types
    [-Wincompatible-pointer-types-discards-qualifiers]

    [...].h: note: passing argument to parameter 'pp' here
    extern char * foo(const char **pp);

    Is this a bug, or what am I missing? Thanks,
    -WBE

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mikhail T.@21:1/5 to Winston on Thu Feb 11 23:08:59 2021
    On 08.02.21 13:02, Winston wrote:
    OK, thanks. That would explain WHY.

    As to WHAT, I'll contend that a warning message that says "discards qualifiers" in such a case (the same as the compiler warns for (const
    char *) passed to a (char *) argument) is misleading.

    This is not an operating system topic. This is a compiler topic...

    -mi

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jens Schweikhardt@21:1/5 to All on Sat Feb 13 11:46:10 2021
    Winston <wbe@ubeblock.psr.com.invalid> wrote
    in <ydr1lsa5yv.fsf@UBEblock.psr.com>:
    # Passing char *p to a function foo(const char *p) is common.
    #
    # Passing const char *p to a function foo(char *p) gets a warning about
    # discarding const, as one would expect.
    #
    # Maybe I'm just not thinking clearly at the moment, but I don't see why
    # passing char *p using foo(&p) to the function foo(const char **pp) causes
    # this warning:
    #
    # [...].c: warning: passing 'char **' to parameter of type 'const char **'
    # discards qualifiers in nested pointer types
    # [-Wincompatible-pointer-types-discards-qualifiers]
    #
    # [...].h: note: passing argument to parameter 'pp' here
    # extern char * foo(const char **pp);
    #
    # Is this a bug, or what am I missing?

    This looks like a C FAQ: http://c-faq.com/ansi/constmismatch.html

    comp.lang.c FAQ list · Question 11.10

    Q: Why can't I pass a char ** to a function which expects a const char **?

    A: You can use a pointer-to-T (for any type T) where a
    pointer-to-const-T is expected. However, the rule (an explicit
    exception) which permits slight mismatches in qualified pointer types is
    not applied recursively, but only at the top level. (const char ** is pointer-to-pointer-to-const-char, and the exception therefore does not
    apply.)

    The reason that you cannot assign a char ** value to a const char **
    pointer is somewhat obscure. Given that the const qualifier exists at
    all, the compiler would like to help you keep your promises not to
    modify const values. That's why you can assign a char * to a const char
    *, but not the other way around: it's clearly safe to ``add'' const-ness
    to a simple pointer, but it would be dangerous to take it away. However, suppose you performed the following more complicated series of
    assignments:

    const char c = 'x'; /* 1 */
    char *p1; /* 2 */
    const char **p2 = &p1; /* 3 */
    *p2 = &c; /* 4 */
    *p1 = 'X'; /* 5 */

    In line 3, we assign a char ** to a const char **. (The compiler should complain.) In line 4, we assign a const char * to a const char *; this
    is clearly legal. In line 5, we modify what a char * points to--this is supposed to be legal. However, p1 ends up pointing to c, which is const.
    This came about in line 4, because *p2 was really p1. This was set up in
    line 3, which is an assignment of a form that is disallowed, and this is exactly why line 3 is disallowed.

    Assigning a char ** to a const char ** (as in line 3, and in the
    original question) is not immediately dangerous. But it sets up a
    situation in which p2's promise--that the ultimately-pointed-to value
    won't be modified--cannot be kept.

    (C++ has more complicated rules for assigning const-qualified pointers
    which let you make more kinds of assignments without incurring warnings,
    but still protect against inadvertent attempts to modify const values.
    C++ would still not allow assigning a char ** to a const char **, but it
    would let you get away with assigning a char ** to a const char * const
    *.)

    In C, if you must assign or pass pointers which have qualifier
    mismatches at other than the first level of indirection, you must use
    explicit casts (e.g. (const char **) in this case), although as always,
    the need for such a cast may indicate a deeper problem which the cast
    doesn't really fix.

    References: ISO Sec. 6.1.2.6, Sec. 6.3.16.1, Sec. 6.5.3
    H&S Sec. 7.9.1 pp. 221-2

    Regards,

    Jens
    --
    Jens Schweikhardt http://www.schweikhardt.net/
    SIGSIG -- signature too long (core dumped)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Winston@21:1/5 to I originally on Sat Feb 13 08:37:30 2021
    I originally asked (in part):
    ... I don't see why passing char *p using foo(&p) to the function
    foo(const char **pp) causes this warning:

    [...].c: warning: passing 'char **' to parameter of type 'const char **'
    discards qualifiers in nested pointer types
    [-Wincompatible-pointer-types-discards-qualifiers]

    [...].h: note: passing argument to parameter 'pp' here
    extern char * foo(const char **pp);

    Is this a bug, or what am I missing?

    to which Jens Schweikhardt <usenet@schweikhardt.net> kindly replied:
    This looks like a C FAQ: http://c-faq.com/ansi/constmismatch.html

    Hadn't heard of that FAQ before. I'll add it to my references
    collection. :)

    comp.lang.c FAQ list · Question 11.10

    Q: Why can't I pass a char ** to a function which expects a const char **?

    The exact case in question, and for C, not C++. Nice!

    (C++ has more complicated rules for assigning const-qualified pointers

    Indeed, and that was where I ended up when I followed the other C
    reference. That led to an alternative explanation of why, but the one
    you posted sticks to C in explaining why.

    In C, if you must assign or pass pointers which have qualifier
    mismatches at other than the first level of indirection, you must use explicit casts (e.g. (const char **) in this case), although as always,
    the need for such a cast may indicate a deeper problem which the cast
    doesn't really fix.

    Thanks, Jens!
    -WBE

    [I still think warning "discards qualifiers" reads too much like
    (const char *) passed to (char *) and is thus misleading in a case like
    this which superficially appears similar, even if it's potentially true
    as the FAQ example showed.]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)