From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com [IPv6:2a00:1450:4864:20::32b]) by sourceware.org (Postfix) with ESMTPS id 341693858430 for ; Tue, 16 Nov 2021 12:34:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 341693858430 Received: by mail-wm1-x32b.google.com with SMTP id y196so16758366wmc.3 for ; Tue, 16 Nov 2021 04:34:38 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:sender:message-id:date:mime-version:user-agent :subject:content-language:to:cc:references:from:in-reply-to :content-transfer-encoding; bh=BYAdBAAy03+e/Dl04mk6fmjGQAcxfjnTDHpmfGNnMZE=; b=2Gmts7tVKV35/TDsyZYLWiCBSNhnJlqwAhqydG7U0X6P+co5AW/ku41LCjdsInRVuU PSx8NUDUo4cbAFdsAefz3ecf1poniltBKg9tx9ZnacJsFBHaUFT/FEQSgOk0hznm1/iW 5LZ+kMNhCZN1alquuBSm5BoIx6EThyT/3I3YndKYNpjOZnGe/vscmUJ4ZzcJnY8C+eyQ Gz20bh1gIj/aFH9DvO+IxkBklgpn3WLvS6N8+q+jWbWosdTpABHv0cJpPp/fo1FY8gHE vvc6IG5ph/d6RMIELakwV70ayvLyKNTqx+ssldil47+gyPdoyqq1GI3SQe+HkhO3EyO7 yTcg== X-Gm-Message-State: AOAM530X6irOBHi85MidFHWVTmysKn1Y3BJIsPMtGqF0c7Ihj3fYTKtO iSv22eDt01WbV3+SAqTns98= X-Google-Smtp-Source: ABdhPJwbpP40jr5VNi7dfo20w7pjTgjgXZY9GVMEytq4vDUIpjqHNcrvOlQA1sVMAjPC4+gIHUNN6A== X-Received: by 2002:a1c:ed18:: with SMTP id l24mr14918320wmh.99.1637066077094; Tue, 16 Nov 2021 04:34:37 -0800 (PST) Received: from [10.168.10.170] ([170.253.36.171]) by smtp.gmail.com with ESMTPSA id v15sm13589183wro.35.2021.11.16.04.34.36 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 16 Nov 2021 04:34:36 -0800 (PST) Sender: Alejandro Colomar Message-ID: Date: Tue, 16 Nov 2021 13:34:35 +0100 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.3.0 Subject: Re: ISO C3X proposal: nonnull qualifier Content-Language: en-US To: Joseph Myers Cc: gcc@gcc.gnu.org, cfe-dev@lists.llvm.org References: <56a1a945-608e-0e5e-7610-c35481abb980@gmail.com> <4883fa8c-2d99-2611-a8e2-6c7612283da4@gmail.com> From: "Alejandro Colomar (man-pages)" In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-6.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 16 Nov 2021 12:34:40 -0000 Hi Joseph, On 11/15/21 23:47, Joseph Myers wrote: > On Mon, 15 Nov 2021, Alejandro Colomar (man-pages) via Gcc wrote: > >> Hi Joseph, >> >> On 11/15/21 23:17, Joseph Myers wrote: >>> On Mon, 15 Nov 2021, Alejandro Colomar (man-pages) via Gcc wrote: >>> >>>> How is restrict handling that problem of lvalue-to-rvalue already? >>> >>> restrict has tricky rules about "based on" (6.7.3.1). >> >> Hmm, I think I can "base on" that, >> to define what I had in mind. :) > > "based on" is about optimizations; I think it's even less suited to > anything relating to diagnostics than it is to optimization. > > To restrict assignment between different kinds of pointers, I'd think > you'd want pointer type variants that differ in some way *other* than > qualifiers, a way that's unaffected by lvalue-to-rvalue conversion, but > that comes with its own rules on implicit conversion as if by assignment > (6.5.16.1) (though then you also need to work out what's allowed in terms > of mixing these pointer type variants in all the other operations allowing > pointers, what type results of pointer arithmetic have, etc.). And there > should surely also be some way of converting a normal pointer to this > variant with a runtime check for NULL. > > Note that discussion of prior art in such a proposal should also consider > relevant prior art (for constraining possible values of a variable through > the type system) in C++ or other languages if possible. > The only other language that I know is C++, so I'll talk about it: C++ added long ago something close to this: references. However, IMO: - They don't provide any enforced safety at all. It's just as safe as using [[gnu::nonnull]]. See an example code below showing why. - They unnecessarily changed pointer syntax to use value syntax. This syntax has not been widely accepted by some C programmers, which would have to adapt their minds considerably. Clang's _Nonnull (and _Nullable) qualifiers (are they?): - Do have the safety that C++ references should have had, if they had been properly designed. Again, see the example code below. - They have an intuitive syntax for C programmers, by just adding a qualifier to a pointer, you mark it as either possibly being NULL or not. It has the appearance of a qualifier, and the documentation refers to it as a qualifier, but how does it implement it clang internally? Is it implemented as a completely different type with some implicit conversion rules? I don't know. See . --- $ cat nonnull.c [[gnu::returns_nonnull]] int *foo(int *p) { return p; } /* * No (nonnull-related) diagnostics from the following commands: * $ gcc -Wall -Wextra -std=gnu2x -S nonnull.c * $ clang -Weverything -std=gnu2x -S nonnull.c */ /*++++++++++++*/ /* Clang only */ int *_Nonnull bar(int *_Nullable p) { return p; } /* * Clang provides safety here: * * $ clang -Weverything -std=gnu2x -S nonnull.c * nonnull.c:17:9: warning: implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull' [-Wnullable-to-nonnull-conversion] * return p; * ^ */ /*++++++++++++*/ /* C++ only */ int *baz(int *p) { int &q = *p; return &q; } /* No (nonnull-related) diagnostics from the following commands: * $ gcc -Wall -Wextra -std=gnu++2b -S nonnull.cxx * $ clang -Weverything -std=gnu++20 -S nonnull.cxx */ --- So we have the following list of prior art: - [[gnu::nonnull]] (GCC) - _Nonnull (Clang) - & (references) (C++) From which I completely dislike references, for not adding any real benefits, and being unnecessarily unintuitive (to C programmers). I like from _Nonnull that it enforces diagnostics. And I like from [[gnu::nonnull]] that it allows optimizations. I'm trying to mix them in a good way. Since Clang's _Nonnull is closer to what I have in mind, I did further tests to _Nonnull, to see what I like, and what I dislike: --- $ cat _Nonnull.c #include int *_Nonnull f(int *_Nullable p) { if (!p) exit(1); return p; } int *_Nonnull g(int *_Null_unspecified p) { return p; } int *_Nonnull h(int *p) { return p; } int *_Nullable i(int *_Nonnull p) { return p; } --- First of all, I see unnecessary (probably over-engineered) qualifiers: - _Null_unspecified seems to me the same as nothing. If I didn't specify its nullability, it's by definition unspecified. Right? - _Nullable seems to me also the same as nothing. The language allows for a pointer to be NULL, so if you don't specify if it can or not be null, you better stay on the safe side and consider it as nullable. Then, I see other problems: - I don't get a warning from g(), nor from h(), which I'd want. To get something like const-safety, we need to design it so that it can be enforced; either you guarantee that a pointer cannot be NULL (_Nonnull), or you cannot guarantee it (not _Nonnull). Otherwise, [[gnu::nonnull]] would seem better to me. So, I'd leave out of the design everything but _Nonnull, and consider everything else as nullable by default. - I get a warning from f(). Ideally, a programmer should not need to cast (casts are dangerous), to convert a nullable pointer to a _nonnull pointer. For that, appropriate checks should be in the preceeding code. Otherwise, a diagnostic should be issued. To be on the safe side, if a compiler has doubts, it should diagnose. There's some Clang document that talks about something similar. I don't know its validity, or if it was a draft before _Nonnull qualifiers. Thanks! Alex