Discussion:
Proposal to allow static qualifier for pointer parameters
(too old to reply)
a***@a3f.at
2016-10-23 12:18:18 UTC
Permalink
Hello,

I'd like to propose extending the syntax for pointer parameter declarations to allow following construct:

int f(int * static p);

Which should be equivalent to

int f(int p[static 1]);


For incomplete types, the static qualified pointer means that the pointer argument shall not be null.

Additionally, functions specified within the standard, for which passing a null pointer invokes undefined behavior shall have their pointer parameters revised to include the new static qualifier.

Background:

C99 introduced the ability to specify a minimum argument array length to be honored by the caller, like so:

int max(int arr[static 1]);

The same revision also introduced the ability to qualify pointer parameters written in array form, like so:

int swap(int a[restrict static 1], int b[restrict static 1]);

Specifying 1 as the minimum array length, effectively means that the pointer shall be valid and non-null. It's not possible to convey this information while using the pointer parameter syntax.

Additionally, following constructs with parameters pointing to incomplete types are invalid:

struct tm;
time_t f(struct tm[static 1]);

memmove(void[static 1], void[static 1], size_t);

And no standard way of specifying that the pointers in the previous listing are non-null exists.

GNU C solves this with __attribute__((nonnull(...))). Examples of usage can be found in both the GNU and BSD libc standard headers.

The Clang, GNU and Intel C compilers all provide basic diagnostics for __attribute__((nonnull)). Clang also provides warnings for when it can deduce the array argument is too small.

This proposal would allow specifying the non-null constraint directly in code, to be seen by programmer as well as static analyzer.

No existing code is affected. New code willing to make use of the feature, needs only to add a static after the *, which will always be possible, unlike the array syntax which doesn't work for incomplete types.

Examples:

int max(int * static arr]);
int swap(int * restrict static a, int * restrict static b);
struct tm;
time_t f(struct tm * static);
memmove(void * static, void * static, size_t);


Thanks for reading. Comments requested. If there is a good reception, I will look into drafting a formal proposal and the official channels through which to submit it.

--

Ahmad Fatoum
Tim Rentsch
2016-10-23 16:03:52 UTC
Permalink
Post by a***@a3f.at
I'd like to propose extending the syntax for pointer parameter
int f(int * static p);
Which should be equivalent to
int f(int p[static 1]);
For incomplete types, the static qualified pointer means that the
pointer argument shall not be null. [.. snip elaboration ..]
ISTM that it would be easier, and also more useful, simply to
allow array notation to be used with incomplete types.
Post by a***@a3f.at
Additionally, functions specified within the standard, for which
passing a null pointer invokes undefined behavior shall have their
pointer parameters revised to include the new static qualifier.
I'm opposed to this. The Standard leaves such cases as undefined
behavior, but an implementation might choose to define the
behavior in certain cases. Requiring prototypes in system
headers to label their parameters this way is misleading and
potentially dangerous. Remember, undefined behavior doesn't mean
something won't work - it means an implementation may choose to
define it any way at all, including in some useful way.
Post by a***@a3f.at
Thanks for reading. Comments requested. If there is a good
reception, I will look into drafting a formal proposal and the
official channels through which to submit it.
My impression is it's a step in the wrong direction. We already
have cases, too many cases, where the existence of undefined
behavior causes a code transformation that works in unexpected
ways and can manifest as hard-to-find bugs. Furthermore, the
underlying assumptions don't always apply in some circumstances,
as for example kernel programming.

What I think would be better is for a non-null specification to
require a check by the compiler, with a mandatory diagnostic in
the event that the compiler cannot deduce a particular call
supplies a non-null argument. Moreover, in such a case, the
compiler must either take the function call at face value (ie,
and produce code to call the function in the normal way), or
fail the compile completely. None of this spooky consequences
of "undefined behavior" nonsense.
a***@a3f.at
2016-10-23 17:10:05 UTC
Permalink
Post by Tim Rentsch
ISTM that it would be easier, and also more useful, simply to
allow array notation to be used with incomplete types.
Having something other than [static 1] for incomplete types doesn't really make sense. The proposed pointe notation is cleaner IMO.
Post by Tim Rentsch
Post by a***@a3f.at
Additionally, functions specified within the standard, for which
passing a null pointer invokes undefined behavior shall have their
pointer parameters revised to include the new static qualifier.
I'm opposed to this. The Standard leaves such cases as undefined
behavior, …
And undefined they shall remain. But if the standard were to add notation, that makes explicit the fact that passing a null parameters is UB, why not make use of it?
Post by Tim Rentsch
My impression is it's a step in the wrong direction. We already
have cases, too many cases, where the existence of undefined
behavior causes a code transformation that works in unexpected
ways and can manifest as hard-to-find bugs.
I don't see the connection. If anything at all, the proposed notation would ease catching bugs, as it makes function prototypes more self-documenting.
Post by Tim Rentsch
Furthermore, the
underlying assumptions don't always apply in some circumstances,
as for example kernel programming.
Could you elaborate on that? I fail to see what assumptions are made within the proposal that wouldn't apply.
Post by Tim Rentsch
What I think would be better is for a non-null specification to
require a check by the compiler, with a mandatory diagnostic in
the event that the compiler cannot deduce a particular call
supplies a non-null argument. Moreover, in such a case, the
compiler must either take the function call at face value (ie,
and produce code to call the function in the normal way), or
fail the compile completely. None of this spooky consequences
of "undefined behavior" nonsense.
It would indeed be nice to see compilers making better use of [static N], but I disagree with mandating any behavior besides diagnostic output.
Tim Rentsch
2016-10-23 23:20:45 UTC
Permalink
Post by a***@a3f.at
Post by Tim Rentsch
ISTM that it would be easier, and also more useful, simply to
allow array notation to be used with incomplete types.
Having something other than [static 1] for incomplete types doesn't
really make sense.
If you think that I expect it's because you haven't thought it
through far enough. Remember, a type may be incomplete at
one point in a program and complete at another point in a program.
Post by a***@a3f.at
The proposed pointe notation is cleaner IMO.
I see no compelling reason to add a new notation when an
existing notation can serve the same purpose, and others
besides.
Post by a***@a3f.at
Post by Tim Rentsch
Post by a***@a3f.at
Additionally, functions specified within the standard, for which
passing a null pointer invokes undefined behavior shall have their
pointer parameters revised to include the new static qualifier.
I'm opposed to this. The Standard leaves such cases as undefined
behavior, ?
And undefined they shall remain. But if the standard were to add
notation, that makes explicit the fact that passing a null parameters
is UB, why not make use of it?
I get the impression that you think if something is undefined
behavior that means the behavior is undefined. That isn't right.
The Standard does not define the behavior, but it may be defined
(and in fact, in some way it _will_ be defined) by some part of
the overall system. More specifically, the library may define
the behavior even though it is UB under the Standard. These days
it is more and more common for compilers and libraries to be
taken as independent components, one from supplier A and one from
supplier B. To insist that certain library functionality be
marked as "undefined behavior" when the library in question may
choose to actually define the behavior of said functionality is,
at the very least, overprescriptive.
Post by a***@a3f.at
Post by Tim Rentsch
Post by a***@a3f.at
[context restored]
Thanks for reading. Comments requested. If there is a good
reception, I will look into drafting a formal proposal and the
official channels through which to submit it.
My impression is it's a step in the wrong direction. We already
have cases, too many cases, where the existence of undefined
behavior causes a code transformation that works in unexpected
ways and can manifest as hard-to-find bugs.
I don't see the connection. If anything at all, the proposed
notation would ease catching bugs, as it makes function prototypes
more self-documenting.
It _might_ help catch bugs. It also might make things worse, by
giving compilers to more cases where dubious "optimizations" are
made. Considering recent trends, I believe the latter is just
as likely as the former, if not moreso.
Post by a***@a3f.at
Post by Tim Rentsch
Furthermore, the
underlying assumptions don't always apply in some circumstances,
as for example kernel programming.
Could you elaborate on that? I fail to see what assumptions
are made within the proposal that wouldn't apply.
In kernel programming, amongst other environments, a null pointer
is not necessarily an invalid value, because it represents
accessible memory, regardless of what the C standard says.
Post by a***@a3f.at
Post by Tim Rentsch
What I think would be better is for a non-null specification to
require a check by the compiler, with a mandatory diagnostic in
the event that the compiler cannot deduce a particular call
supplies a non-null argument. Moreover, in such a case, the
compiler must either take the function call at face value (ie,
and produce code to call the function in the normal way), or
fail the compile completely. None of this spooky consequences
of "undefined behavior" nonsense.
It would indeed be nice to see compilers making better use of [static
N], but I disagree with mandating any behavior besides diagnostic
output.
I suspect you don't yet appreciate the kinds of problems that
arise as a result of hyper-aggressive optimizers that reason
based on the presence of "undefined behavior". It's important to
do something to rein that in. You are of course welcome to
disagree, but if you are intent on presenting a proposal you
should work more on forging a consensus than simply dismissing
comments offered in response to your asking for some.
Jakob Bohm
2016-10-23 18:48:59 UTC
Permalink
Post by Tim Rentsch
Post by a***@a3f.at
I'd like to propose extending the syntax for pointer parameter
int f(int * static p);
Which should be equivalent to
int f(int p[static 1]);
For incomplete types, the static qualified pointer means that the
pointer argument shall not be null. [.. snip elaboration ..]
ISTM that it would be easier, and also more useful, simply to
allow array notation to be used with incomplete types.
Post by a***@a3f.at
Additionally, functions specified within the standard, for which
passing a null pointer invokes undefined behavior shall have their
pointer parameters revised to include the new static qualifier.
I'm opposed to this. The Standard leaves such cases as undefined
behavior, but an implementation might choose to define the
behavior in certain cases. Requiring prototypes in system
headers to label their parameters this way is misleading and
potentially dangerous. Remember, undefined behavior doesn't mean
something won't work - it means an implementation may choose to
define it any way at all, including in some useful way.
Post by a***@a3f.at
Thanks for reading. Comments requested. If there is a good
reception, I will look into drafting a formal proposal and the
official channels through which to submit it.
My impression is it's a step in the wrong direction. We already
have cases, too many cases, where the existence of undefined
behavior causes a code transformation that works in unexpected
ways and can manifest as hard-to-find bugs. Furthermore, the
underlying assumptions don't always apply in some circumstances,
as for example kernel programming.
What I think would be better is for a non-null specification to
require a check by the compiler, with a mandatory diagnostic in
the event that the compiler cannot deduce a particular call
supplies a non-null argument. Moreover, in such a case, the
compiler must either take the function call at face value (ie,
and produce code to call the function in the normal way), or
fail the compile completely. None of this spooky consequences
of "undefined behavior" nonsense.
What would often be more useful would be:

- A mandatory diagnostic and possible refusal to compile if the
compiler can deduce with certainty that the argument is sometimes
invalid (in this case null).
- An optional diagnostic, but no refusal to compile, if the compiler
fails to deduce whether or not the argument is sometimes invalid.
- In quality implementations, a vendor promise that the optional
diagnostic in the previous bullet will be issued.

Enjoy

Jakob
--
Jakob Bohm, CIO, Partner, WiseMo A/S. https://www.wisemo.com
Transformervej 29, 2860 Søborg, Denmark. Direct +45 31 13 16 10
This public discussion message is non-binding and may contain errors.
WiseMo - Remote Service Management for PCs, Phones and Embedded
Tim Rentsch
2016-10-23 22:44:06 UTC
Permalink
Post by Jakob Bohm
Post by Tim Rentsch
Post by a***@a3f.at
I'd like to propose extending the syntax for pointer parameter
int f(int * static p);
Which should be equivalent to
int f(int p[static 1]);
For incomplete types, the static qualified pointer means that the
pointer argument shall not be null. [.. snip elaboration ..]
ISTM that it would be easier, and also more useful, simply to
allow array notation to be used with incomplete types.
Post by a***@a3f.at
Additionally, functions specified within the standard, for which
passing a null pointer invokes undefined behavior shall have their
pointer parameters revised to include the new static qualifier.
I'm opposed to this. The Standard leaves such cases as undefined
behavior, but an implementation might choose to define the
behavior in certain cases. Requiring prototypes in system
headers to label their parameters this way is misleading and
potentially dangerous. Remember, undefined behavior doesn't mean
something won't work - it means an implementation may choose to
define it any way at all, including in some useful way.
Post by a***@a3f.at
Thanks for reading. Comments requested. If there is a good
reception, I will look into drafting a formal proposal and the
official channels through which to submit it.
My impression is it's a step in the wrong direction. We already
have cases, too many cases, where the existence of undefined
behavior causes a code transformation that works in unexpected
ways and can manifest as hard-to-find bugs. Furthermore, the
underlying assumptions don't always apply in some circumstances,
as for example kernel programming.
What I think would be better is for a non-null specification to
require a check by the compiler, with a mandatory diagnostic in
the event that the compiler cannot deduce a particular call
supplies a non-null argument. Moreover, in such a case, the
compiler must either take the function call at face value (ie,
and produce code to call the function in the normal way), or
fail the compile completely. None of this spooky consequences
of "undefined behavior" nonsense.
- A mandatory diagnostic and possible refusal to compile if the
compiler can deduce with certainty that the argument is sometimes
invalid (in this case null).
- An optional diagnostic, but no refusal to compile, if the compiler
fails to deduce whether or not the argument is sometimes invalid.
- In quality implementations, a vendor promise that the optional
diagnostic in the previous bullet will be issued.
This proposal requires nothing at all: an implementation can
conform simply by making no attempt to deduce whether a pointer
argument is (or isn't) null, and never issuing a diagnostic. It
guarantees nothing, and hence IMO offers no value.
Jakob Bohm
2016-10-24 01:48:09 UTC
Permalink
Post by Tim Rentsch
Post by Jakob Bohm
Post by Tim Rentsch
Post by a***@a3f.at
I'd like to propose extending the syntax for pointer parameter
int f(int * static p);
Which should be equivalent to
int f(int p[static 1]);
For incomplete types, the static qualified pointer means that the
pointer argument shall not be null. [.. snip elaboration ..]
ISTM that it would be easier, and also more useful, simply to
allow array notation to be used with incomplete types.
Post by a***@a3f.at
Additionally, functions specified within the standard, for which
passing a null pointer invokes undefined behavior shall have their
pointer parameters revised to include the new static qualifier.
I'm opposed to this. The Standard leaves such cases as undefined
behavior, but an implementation might choose to define the
behavior in certain cases. Requiring prototypes in system
headers to label their parameters this way is misleading and
potentially dangerous. Remember, undefined behavior doesn't mean
something won't work - it means an implementation may choose to
define it any way at all, including in some useful way.
Post by a***@a3f.at
Thanks for reading. Comments requested. If there is a good
reception, I will look into drafting a formal proposal and the
official channels through which to submit it.
My impression is it's a step in the wrong direction. We already
have cases, too many cases, where the existence of undefined
behavior causes a code transformation that works in unexpected
ways and can manifest as hard-to-find bugs. Furthermore, the
underlying assumptions don't always apply in some circumstances,
as for example kernel programming.
What I think would be better is for a non-null specification to
require a check by the compiler, with a mandatory diagnostic in
the event that the compiler cannot deduce a particular call
supplies a non-null argument. Moreover, in such a case, the
compiler must either take the function call at face value (ie,
and produce code to call the function in the normal way), or
fail the compile completely. None of this spooky consequences
of "undefined behavior" nonsense.
- A mandatory diagnostic and possible refusal to compile if the
compiler can deduce with certainty that the argument is sometimes
invalid (in this case null).
- An optional diagnostic, but no refusal to compile, if the compiler
fails to deduce whether or not the argument is sometimes invalid.
- In quality implementations, a vendor promise that the optional
diagnostic in the previous bullet will be issued.
This proposal requires nothing at all: an implementation can
conform simply by making no attempt to deduce whether a pointer
argument is (or isn't) null, and never issuing a diagnostic. It
guarantees nothing, and hence IMO offers no value.
I deliberately phrased it to allow no-op implementations but also
quality implementations. I was arguing against the bad idea of issuing
the drastic "foo might be null here" diagnostic in every case where the
only problem is that any particular compiler has no code to conclude
either way.

Enjoy

Jakob
--
Jakob Bohm, CIO, Partner, WiseMo A/S. https://www.wisemo.com
Transformervej 29, 2860 Søborg, Denmark. Direct +45 31 13 16 10
This public discussion message is non-binding and may contain errors.
WiseMo - Remote Service Management for PCs, Phones and Embedded
Tim Rentsch
2016-10-24 03:03:12 UTC
Permalink
Post by Jakob Bohm
Post by Tim Rentsch
Post by Jakob Bohm
Post by Tim Rentsch
Post by a***@a3f.at
I'd like to propose extending the syntax for pointer parameter
int f(int * static p);
Which should be equivalent to
int f(int p[static 1]);
For incomplete types, the static qualified pointer means that the
pointer argument shall not be null. [.. snip elaboration ..]
ISTM that it would be easier, and also more useful, simply to
allow array notation to be used with incomplete types.
Post by a***@a3f.at
Additionally, functions specified within the standard, for which
passing a null pointer invokes undefined behavior shall have their
pointer parameters revised to include the new static qualifier.
I'm opposed to this. The Standard leaves such cases as undefined
behavior, but an implementation might choose to define the
behavior in certain cases. Requiring prototypes in system
headers to label their parameters this way is misleading and
potentially dangerous. Remember, undefined behavior doesn't mean
something won't work - it means an implementation may choose to
define it any way at all, including in some useful way.
Post by a***@a3f.at
Thanks for reading. Comments requested. If there is a good
reception, I will look into drafting a formal proposal and the
official channels through which to submit it.
My impression is it's a step in the wrong direction. We already
have cases, too many cases, where the existence of undefined
behavior causes a code transformation that works in unexpected
ways and can manifest as hard-to-find bugs. Furthermore, the
underlying assumptions don't always apply in some circumstances,
as for example kernel programming.
What I think would be better is for a non-null specification to
require a check by the compiler, with a mandatory diagnostic in
the event that the compiler cannot deduce a particular call
supplies a non-null argument. Moreover, in such a case, the
compiler must either take the function call at face value (ie,
and produce code to call the function in the normal way), or
fail the compile completely. None of this spooky consequences
of "undefined behavior" nonsense.
- A mandatory diagnostic and possible refusal to compile if the
compiler can deduce with certainty that the argument is sometimes
invalid (in this case null).
- An optional diagnostic, but no refusal to compile, if the compiler
fails to deduce whether or not the argument is sometimes invalid.
- In quality implementations, a vendor promise that the optional
diagnostic in the previous bullet will be issued.
This proposal requires nothing at all: an implementation can
conform simply by making no attempt to deduce whether a pointer
argument is (or isn't) null, and never issuing a diagnostic. It
guarantees nothing, and hence IMO offers no value.
I deliberately phrased it to allow no-op implementations but also
quality implementations. I was arguing against the bad idea of issuing
the drastic "foo might be null here" diagnostic in every case where the
only problem is that any particular compiler has no code to conclude
either way.
Then there isn't any reason to change the Standard. Implementations
can do all that under the Standard as it is written now.
Keith Thompson
2016-10-23 19:30:09 UTC
Permalink
Tim Rentsch <***@alumni.caltech.edu> writes:
[...]
Post by Tim Rentsch
What I think would be better is for a non-null specification to
require a check by the compiler, with a mandatory diagnostic in
the event that the compiler cannot deduce a particular call
supplies a non-null argument. Moreover, in such a case, the
compiler must either take the function call at face value (ie,
and produce code to call the function in the normal way), or
fail the compile completely. None of this spooky consequences
of "undefined behavior" nonsense.
If I understand this correctly, it would be tricky. The standard does
not generally require compilers to infer the results of expressions at
compile time (apart from constant expressions, which are rigorously
defined). Making a run-time behavior (passing a null pointer)
effectively a constraint violation would require the standard to specify
just how compilers must perform data flow analysis. The alternative
would be for code to be valid or invalid depending on the cleverness of
the compiler.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Tim Rentsch
2016-10-23 22:18:20 UTC
Permalink
Post by Keith Thompson
[...]
Post by Tim Rentsch
What I think would be better is for a non-null specification to
require a check by the compiler, with a mandatory diagnostic in
the event that the compiler cannot deduce a particular call
supplies a non-null argument. Moreover, in such a case, the
compiler must either take the function call at face value (ie,
and produce code to call the function in the normal way), or
fail the compile completely. None of this spooky consequences
of "undefined behavior" nonsense.
If I understand this correctly, it would be tricky. The standard does
not generally require compilers to infer the results of expressions at
compile time (apart from constant expressions, which are rigorously
defined). Making a run-time behavior (passing a null pointer)
effectively a constraint violation would require the standard to specify
just how compilers must perform data flow analysis. The alternative
would be for code to be valid or invalid depending on the cleverness of
the compiler.
Maybe you haven't thought it through completely. The requirement
is to issue a diagnostic if the compiler cannot (ie, or does not)
deduce that a non-null pointer value is supplied for a parameter
that demands a non-null argument. This requirement can easily be
met simply by always issuing a diagnostic (low quality, but still
conforming). When such a case is encountered, there is an option
to fail the compile, but this option is allowed only if doing so
doesn't violate any other requirements. In particular, a program
translation is not allowed to reject any strictly conforming
program. So unless the compiler is _sure_ the program isn't
strictly conforming, it is obliged to accept it, which means the
function call in question must be treated as defined behavior,
even though the compiler isn't sure if it is or not.

I guess I should pause here and ask if that all makes sense?

The point is to ensure a diagnostic is issued if there is any
doubt about whether a "null values not allowed" stipulation
is violated. False positives are allowed, false negatives
are not. It's very easy to meet the requirement, just by
issuing a diagnostic and then proceeding on. Anything more
than that is a QoI concern.

Does that seem better now?

Note by the way it is very easy to give the compiler enough
information so that it can tell that a pointer value will
not be null. If the pointer argument in question is 'p',
simply precede the function call by

assert(p);

with of course assertions not turned off by NDEBUG. There are
other variations on this scheme that may be easier to implement
but I think you get the general idea.
Keith Thompson
2016-10-24 00:19:38 UTC
Permalink
Post by Tim Rentsch
Post by Keith Thompson
[...]
Post by Tim Rentsch
What I think would be better is for a non-null specification to
require a check by the compiler, with a mandatory diagnostic in
the event that the compiler cannot deduce a particular call
supplies a non-null argument. Moreover, in such a case, the
compiler must either take the function call at face value (ie,
and produce code to call the function in the normal way), or
fail the compile completely. None of this spooky consequences
of "undefined behavior" nonsense.
If I understand this correctly, it would be tricky. The standard does
not generally require compilers to infer the results of expressions at
compile time (apart from constant expressions, which are rigorously
defined). Making a run-time behavior (passing a null pointer)
effectively a constraint violation would require the standard to specify
just how compilers must perform data flow analysis. The alternative
would be for code to be valid or invalid depending on the cleverness of
the compiler.
Maybe you haven't thought it through completely. The requirement
is to issue a diagnostic if the compiler cannot (ie, or does not)
deduce that a non-null pointer value is supplied for a parameter
that demands a non-null argument. This requirement can easily be
met simply by always issuing a diagnostic (low quality, but still
conforming). When such a case is encountered, there is an option
to fail the compile, but this option is allowed only if doing so
doesn't violate any other requirements. In particular, a program
translation is not allowed to reject any strictly conforming
program. So unless the compiler is _sure_ the program isn't
strictly conforming, it is obliged to accept it, which means the
function call in question must be treated as defined behavior,
even though the compiler isn't sure if it is or not.
I guess I should pause here and ask if that all makes sense?
The point is to ensure a diagnostic is issued if there is any
doubt about whether a "null values not allowed" stipulation
is violated. False positives are allowed, false negatives
are not. It's very easy to meet the requirement, just by
issuing a diagnostic and then proceeding on. Anything more
than that is a QoI concern.
Does that seem better now?
Not really.

A compiler could conform by always issuing a diagnostic, but that would
be considered very poor quality. In practice, compiler writers would be
strongly pressured to perform compile-time analysis to prove that a
pointer value cannot be null. Many compilers already perform such
analysis (perhaps only if optimization is enabled), but requiring such
analysis for a compiler to be both useful and conforming would be
unprecedented.
Post by Tim Rentsch
Note by the way it is very easy to give the compiler enough
information so that it can tell that a pointer value will
not be null. If the pointer argument in question is 'p',
simply precede the function call by
assert(p);
with of course assertions not turned off by NDEBUG. There are
other variations on this scheme that may be easier to implement
but I think you get the general idea.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Tim Rentsch
2016-10-24 03:01:17 UTC
Permalink
Post by Keith Thompson
Post by Tim Rentsch
Post by Keith Thompson
[...]
Post by Tim Rentsch
What I think would be better is for a non-null specification to
require a check by the compiler, with a mandatory diagnostic in
the event that the compiler cannot deduce a particular call
supplies a non-null argument. Moreover, in such a case, the
compiler must either take the function call at face value (ie,
and produce code to call the function in the normal way), or
fail the compile completely. None of this spooky consequences
of "undefined behavior" nonsense.
If I understand this correctly, it would be tricky. The standard does
not generally require compilers to infer the results of expressions at
compile time (apart from constant expressions, which are rigorously
defined). Making a run-time behavior (passing a null pointer)
effectively a constraint violation would require the standard to specify
just how compilers must perform data flow analysis. The alternative
would be for code to be valid or invalid depending on the cleverness of
the compiler.
Maybe you haven't thought it through completely. The requirement
is to issue a diagnostic if the compiler cannot (ie, or does not)
deduce that a non-null pointer value is supplied for a parameter
that demands a non-null argument. This requirement can easily be
met simply by always issuing a diagnostic (low quality, but still
conforming). When such a case is encountered, there is an option
to fail the compile, but this option is allowed only if doing so
doesn't violate any other requirements. In particular, a program
translation is not allowed to reject any strictly conforming
program. So unless the compiler is _sure_ the program isn't
strictly conforming, it is obliged to accept it, which means the
function call in question must be treated as defined behavior,
even though the compiler isn't sure if it is or not.
I guess I should pause here and ask if that all makes sense?
The point is to ensure a diagnostic is issued if there is any
doubt about whether a "null values not allowed" stipulation
is violated. False positives are allowed, false negatives
are not. It's very easy to meet the requirement, just by
issuing a diagnostic and then proceeding on. Anything more
than that is a QoI concern.
Does that seem better now?
Not really.
A compiler could conform by always issuing a diagnostic, but that would
be considered very poor quality. In practice, compiler writers would be
strongly pressured to perform compile-time analysis to prove that a
pointer value cannot be null. Many compilers already perform such
analysis (perhaps only if optimization is enabled), but requiring such
analysis for a compiler to be both useful and conforming would be
unprecedented.
I agree, it is unprecedented in C. There is related precedent in
other languages, specifically Java. As long as what we're
talking about is a form that is put in specifically for this
purpose (so it won't be triggered by old code), I don't think it
would be a big deal. A minimal implementation should be quite
easy. Also I should add that this isn't something I mean to
advocate strongly, only that I consider it an improvement over
the earlier alternative.

Example minimal implementation - recognize a form such as

( !p ? exit(X), (void*)0 : p)

as never being null, and don't give a warning on that. Then
getting rid of spurious diagnostics would be quite easy.

Package a suitable form up as a standard macro definition, and it
would be easy for implementations to clear the low bar, quality
wise.

I admit this scheme isn't really very attractive. But I think
almost anything is better than introducing a construct that has
no semantic effect other than to INCREASE the potential for
undefined behavior, and hence the possible downstream mysterious
program behavior resulting from hyper-aggressive optimization.
Keith Thompson
2016-10-23 19:08:04 UTC
Permalink
***@a3f.at writes:
[...]
Post by a***@a3f.at
GNU C solves this with __attribute__((nonnull(...))). Examples of
usage can be found in both the GNU and BSD libc standard headers.
I suggest that adding a syntax for attributes would be a cleaner
solution. A recent C++ standard has already done this; C could easily
borrow it.

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
David Brown
2016-10-24 14:43:01 UTC
Permalink
Post by Keith Thompson
[...]
Post by a***@a3f.at
GNU C solves this with __attribute__((nonnull(...))). Examples of
usage can be found in both the GNU and BSD libc standard headers.
I suggest that adding a syntax for attributes would be a cleaner
solution. A recent C++ standard has already done this; C could easily
borrow it.
Yes, that seems a more obvious step. The two possibilities would be to
use the [[attribute]] syntax from C++, or the __attribute__((...))
syntax from gcc.

Given that several of the major C compilers (gcc, clang and icc) already
support this syntax, as do many other more target-specific compilers
(such as CodeWarrior and Arm/Keil armcc), it might make more pragmatic
sense to use the __attribute__ format.

And since self-documenting code is given as one of the benefits of this
proposal, surely __attribute__ is more "self-documenting" than yet
another overload of the "static" keyword? I wonder what percentage of C
programmers even know what the "static" means in:

int f(int p[static 1]);

So
int f(int * static p);

is not much better. But most programmers could make a solid guess as to
the meaning of:

int f(int * p) __attribute__((nonnull(1)));

(though they might feel there are more brackets than necessary!)

And if __attribute__ were to make it into the standards, then it opens a
clear path towards standardising a range of useful attributes that are
already widely implemented and used, but not part of the ISO standards.
Keith Thompson
2016-10-24 15:33:06 UTC
Permalink
Post by David Brown
Post by Keith Thompson
[...]
Post by a***@a3f.at
GNU C solves this with __attribute__((nonnull(...))). Examples of
usage can be found in both the GNU and BSD libc standard headers.
I suggest that adding a syntax for attributes would be a cleaner
solution. A recent C++ standard has already done this; C could easily
borrow it.
Yes, that seems a more obvious step. The two possibilities would be to
use the [[attribute]] syntax from C++, or the __attribute__((...))
syntax from gcc.
Given that several of the major C compilers (gcc, clang and icc) already
support this syntax, as do many other more target-specific compilers
(such as CodeWarrior and Arm/Keil armcc), it might make more pragmatic
sense to use the __attribute__ format.
Since the [[attribute]] syntax is standard in C++ (since C++11), C
should use the same syntax. I'm not sure why the C++ committee chose to
invent a new syntax rather than adopting the gcc syntax (perhaps they
didn't want to give an unfair advantage to gcc?), but whatever their
reasons, they should apply equally to C.

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Tim Rentsch
2016-10-25 21:52:53 UTC
Permalink
Post by Keith Thompson
Post by David Brown
Post by Keith Thompson
[...]
GNU C solves this with __attribute__((nonnull(...))). Examples of
usage can be found in both the GNU and BSD libc standard headers.
I suggest that adding a syntax for attributes would be a cleaner
solution. A recent C++ standard has already done this; C could easily
borrow it.
Yes, that seems a more obvious step. The two possibilities would be to
use the [[attribute]] syntax from C++, or the __attribute__((...))
syntax from gcc.
Given that several of the major C compilers (gcc, clang and icc) already
support this syntax, as do many other more target-specific compilers
(such as CodeWarrior and Arm/Keil armcc), it might make more pragmatic
sense to use the __attribute__ format.
Since the [[attribute]] syntax is standard in C++ (since C++11), C
should use the same syntax. I'm not sure why the C++ committee chose to
invent a new syntax rather than adopting the gcc syntax (perhaps they
didn't want to give an unfair advantage to gcc?), but whatever their
reasons, they should apply equally to C.
They may apply equally to C, or they may not. Without knowing
what the reasons are one can't be sure.

Besides, C already has a way that various code decorations can be
supplied in source code, if that is desired. In a word, _Pragma.
Keith Thompson
2016-10-25 22:18:32 UTC
Permalink
Post by Tim Rentsch
Post by Keith Thompson
Post by David Brown
Post by Keith Thompson
[...]
GNU C solves this with __attribute__((nonnull(...))). Examples of
usage can be found in both the GNU and BSD libc standard headers.
I suggest that adding a syntax for attributes would be a cleaner
solution. A recent C++ standard has already done this; C could easily
borrow it.
Yes, that seems a more obvious step. The two possibilities would be to
use the [[attribute]] syntax from C++, or the __attribute__((...))
syntax from gcc.
Given that several of the major C compilers (gcc, clang and icc) already
support this syntax, as do many other more target-specific compilers
(such as CodeWarrior and Arm/Keil armcc), it might make more pragmatic
sense to use the __attribute__ format.
Since the [[attribute]] syntax is standard in C++ (since C++11), C
should use the same syntax. I'm not sure why the C++ committee chose to
invent a new syntax rather than adopting the gcc syntax (perhaps they
didn't want to give an unfair advantage to gcc?), but whatever their
reasons, they should apply equally to C.
They may apply equally to C, or they may not. Without knowing
what the reasons are one can't be sure.
Agreed.
Post by Tim Rentsch
Besides, C already has a way that various code decorations can be
supplied in source code, if that is desired. In a word, _Pragma.
Yes, but _Pragma is referred to as a unary operator, which presumably
means that it must appear in a context that requires an expression.
And it's processed in translation phase 4; I haven't given it much
thought, but I can imagine that causing problems.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Tim Rentsch
2016-10-26 14:06:45 UTC
Permalink
Post by Keith Thompson
Post by Tim Rentsch
Post by Keith Thompson
Post by David Brown
Post by Keith Thompson
[...]
GNU C solves this with __attribute__((nonnull(...))). Examples of
usage can be found in both the GNU and BSD libc standard headers.
I suggest that adding a syntax for attributes would be a cleaner
solution. A recent C++ standard has already done this; C could easily
borrow it.
Yes, that seems a more obvious step. The two possibilities would be to
use the [[attribute]] syntax from C++, or the __attribute__((...))
syntax from gcc.
Given that several of the major C compilers (gcc, clang and icc) already
support this syntax, as do many other more target-specific compilers
(such as CodeWarrior and Arm/Keil armcc), it might make more pragmatic
sense to use the __attribute__ format.
Since the [[attribute]] syntax is standard in C++ (since C++11), C
should use the same syntax. I'm not sure why the C++ committee chose to
invent a new syntax rather than adopting the gcc syntax (perhaps they
didn't want to give an unfair advantage to gcc?), but whatever their
reasons, they should apply equally to C.
They may apply equally to C, or they may not. Without knowing
what the reasons are one can't be sure.
Agreed.
Post by Tim Rentsch
Besides, C already has a way that various code decorations can be
supplied in source code, if that is desired. In a word, _Pragma.
Yes, but _Pragma is referred to as a unary operator, which presumably
means that it must appear in a context that requires an expression.
AFAIK _Pragma can appear at any point in a program source that any
other token could. I see nothing that requires it to be in or near
any other expression, either another preprocessor expression or an
expresson of the post-preprocessor variety.
Post by Keith Thompson
And it's processed in translation phase 4; I haven't given it much
thought, but I can imagine that causing problems.
ISTM that it would make things easier, because it doesn't interfere
with regular language syntax. And it seems like it should be easy to
have _Pragma decorate the previous or next token in the token stream,
which decoration could then be picked up in later translation phases.
To my way of thinking that simplifies the task of processing the
supplied meta-information, because it's all taken care of even before
syntax analysis.
Jakob Bohm
2016-10-26 14:46:15 UTC
Permalink
Post by Tim Rentsch
Post by Keith Thompson
Post by Tim Rentsch
Post by Keith Thompson
Post by David Brown
Post by Keith Thompson
[...]
GNU C solves this with __attribute__((nonnull(...))). Examples of
usage can be found in both the GNU and BSD libc standard headers.
I suggest that adding a syntax for attributes would be a cleaner
solution. A recent C++ standard has already done this; C could easily
borrow it.
Yes, that seems a more obvious step. The two possibilities would be to
use the [[attribute]] syntax from C++, or the __attribute__((...))
syntax from gcc.
Given that several of the major C compilers (gcc, clang and icc) already
support this syntax, as do many other more target-specific compilers
(such as CodeWarrior and Arm/Keil armcc), it might make more pragmatic
sense to use the __attribute__ format.
Since the [[attribute]] syntax is standard in C++ (since C++11), C
should use the same syntax. I'm not sure why the C++ committee chose to
invent a new syntax rather than adopting the gcc syntax (perhaps they
didn't want to give an unfair advantage to gcc?), but whatever their
reasons, they should apply equally to C.
They may apply equally to C, or they may not. Without knowing
what the reasons are one can't be sure.
Agreed.
Post by Tim Rentsch
Besides, C already has a way that various code decorations can be
supplied in source code, if that is desired. In a word, _Pragma.
Yes, but _Pragma is referred to as a unary operator, which presumably
means that it must appear in a context that requires an expression.
AFAIK _Pragma can appear at any point in a program source that any
other token could. I see nothing that requires it to be in or near
any other expression, either another preprocessor expression or an
expresson of the post-preprocessor variety.
Post by Keith Thompson
And it's processed in translation phase 4; I haven't given it much
thought, but I can imagine that causing problems.
ISTM that it would make things easier, because it doesn't interfere
with regular language syntax. And it seems like it should be easy to
have _Pragma decorate the previous or next token in the token stream,
which decoration could then be picked up in later translation phases.
To my way of thinking that simplifies the task of processing the
supplied meta-information, because it's all taken care of even before
syntax analysis.
Except that it would be a very bad idea to evaluate any expressions in
there in preprocessor rather than actual scope context. So at least
some of that parsing should be done at regular compile time when
scoping etc. has been resolved. This may not matter for simple
properties such as nonnull (always), but it will matter once developers
want to make e.g. argument-dependent annotations such as "nonnull if
that other argument is >= 1", to take a real simple example. Or "In
the range sizeof(short) to sizeof(struct foo)"

Enjoy

Jakob
--
Jakob Bohm, CIO, Partner, WiseMo A/S. https://www.wisemo.com
Transformervej 29, 2860 Søborg, Denmark. Direct +45 31 13 16 10
This public discussion message is non-binding and may contain errors.
WiseMo - Remote Service Management for PCs, Phones and Embedded
Tim Rentsch
2016-10-26 23:13:25 UTC
Permalink
Post by Jakob Bohm
Post by Tim Rentsch
Post by Keith Thompson
Post by Tim Rentsch
Post by Keith Thompson
Post by David Brown
Post by Keith Thompson
[...]
GNU C solves this with __attribute__((nonnull(...))). Examples of
usage can be found in both the GNU and BSD libc standard headers.
I suggest that adding a syntax for attributes would be a cleaner
solution. A recent C++ standard has already done this; C could easily
borrow it.
Yes, that seems a more obvious step. The two possibilities would be to
use the [[attribute]] syntax from C++, or the __attribute__((...))
syntax from gcc.
Given that several of the major C compilers (gcc, clang and icc) already
support this syntax, as do many other more target-specific compilers
(such as CodeWarrior and Arm/Keil armcc), it might make more pragmatic
sense to use the __attribute__ format.
Since the [[attribute]] syntax is standard in C++ (since C++11), C
should use the same syntax. I'm not sure why the C++ committee chose to
invent a new syntax rather than adopting the gcc syntax (perhaps they
didn't want to give an unfair advantage to gcc?), but whatever their
reasons, they should apply equally to C.
They may apply equally to C, or they may not. Without knowing
what the reasons are one can't be sure.
Agreed.
Post by Tim Rentsch
Besides, C already has a way that various code decorations can be
supplied in source code, if that is desired. In a word, _Pragma.
Yes, but _Pragma is referred to as a unary operator, which presumably
means that it must appear in a context that requires an expression.
AFAIK _Pragma can appear at any point in a program source that any
other token could. I see nothing that requires it to be in or near
any other expression, either another preprocessor expression or an
expresson of the post-preprocessor variety.
Post by Keith Thompson
And it's processed in translation phase 4; I haven't given it much
thought, but I can imagine that causing problems.
ISTM that it would make things easier, because it doesn't interfere
with regular language syntax. And it seems like it should be easy to
have _Pragma decorate the previous or next token in the token stream,
which decoration could then be picked up in later translation phases.
To my way of thinking that simplifies the task of processing the
supplied meta-information, because it's all taken care of even before
syntax analysis.
Except that it would be a very bad idea to evaluate any expressions in
there in preprocessor rather than actual scope context. So at least
some of that parsing should be done at regular compile time when
scoping etc. has been resolved. This may not matter for simple
properties such as nonnull (always), but it will matter once developers
want to make e.g. argument-dependent annotations such as "nonnull if
that other argument is >= 1", to take a real simple example. Or "In
the range sizeof(short) to sizeof(struct foo)"
If not-yet-available information is needed when the _Pragma is
first seen, just defer evaluation until the necessary information
is available. There is nothing that says that attaching the
decoration and evaluating the decoration have to happen at the
same time.
Keith Thompson
2016-10-26 15:40:29 UTC
Permalink
[...]
Post by Tim Rentsch
Post by Keith Thompson
Yes, but _Pragma is referred to as a unary operator, which presumably
means that it must appear in a context that requires an expression.
AFAIK _Pragma can appear at any point in a program source that any
other token could. I see nothing that requires it to be in or near
any other expression, either another preprocessor expression or an
expresson of the post-preprocessor variety.
I think you're right, and gcc agrees with you.

I was probably reading to much into the fact that the standard refers to

_Pragma ( string-literal )

as a "unary operator expression". That phrase (as opposed to "unary
expression") is used only for _Pragma and the "defined" operator; the
latter can appear only in a directive, and actually is treated more or
less like an expression.

Which begs^H^H^H^H raises the question: *why* is it referred to as a
"unary operator expression"? It's really just a sequence of
preprocessor tokens that are effectively translated to a #pragma
directive. (gcc -E actually performs this transformation.)
Post by Tim Rentsch
Post by Keith Thompson
And it's processed in translation phase 4; I haven't given it much
thought, but I can imagine that causing problems.
ISTM that it would make things easier, because it doesn't interfere
with regular language syntax. And it seems like it should be easy to
have _Pragma decorate the previous or next token in the token stream,
which decoration could then be picked up in later translation phases.
To my way of thinking that simplifies the task of processing the
supplied meta-information, because it's all taken care of even before
syntax analysis.
I can imagine wanting to have an attribute that refers to something that
isn't meaningful until after phase 4. (I have no specific examples.)
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Tim Rentsch
2016-10-26 23:34:26 UTC
Permalink
Post by Keith Thompson
[...]
Post by Tim Rentsch
Post by Keith Thompson
Yes, but _Pragma is referred to as a unary operator, which presumably
means that it must appear in a context that requires an expression.
AFAIK _Pragma can appear at any point in a program source that any
other token could. I see nothing that requires it to be in or near
any other expression, either another preprocessor expression or an
expresson of the post-preprocessor variety.
I think you're right, and gcc agrees with you.
I was probably reading to much into the fact that the standard refers to
_Pragma ( string-literal )
as a "unary operator expression". That phrase (as opposed to "unary
expression") is used only for _Pragma and the "defined" operator; the
latter can appear only in a directive, and actually is treated more or
less like an expression.
Which begs^H^H^H^H raises the question: *why* is it referred to as a
"unary operator expression"?
I can't think of any reasons besides obvious ones. It is a bit
funny but it's never really bothered me.
Post by Keith Thompson
It's really just a sequence of
preprocessor tokens that are effectively translated to a #pragma
directive. (gcc -E actually performs this transformation.)
That's interesting, I didn't know that.
Post by Keith Thompson
Post by Tim Rentsch
Post by Keith Thompson
And it's processed in translation phase 4; I haven't given it much
thought, but I can imagine that causing problems.
ISTM that it would make things easier, because it doesn't interfere
with regular language syntax. And it seems like it should be easy to
have _Pragma decorate the previous or next token in the token stream,
which decoration could then be picked up in later translation phases.
To my way of thinking that simplifies the task of processing the
supplied meta-information, because it's all taken care of even before
syntax analysis.
I can imagine wanting to have an attribute that refers to something that
isn't meaningful until after phase 4. (I have no specific examples.)
Oh, for sure. But like I explained in my reply to Jakob Bohm,
resolving such a reference could be deferred until any needed
information is available. The _Pragma could still pick up
the decoration and attach it to the appropriate point in the
input; there will always be such a point, since otherwise
the decoration would be meant for the translation unit as a
whole, and a regular #pragma would suffice.
s***@casperkitty.com
2016-10-26 15:08:25 UTC
Permalink
Post by Tim Rentsch
Besides, C already has a way that various code decorations can be
supplied in source code, if that is desired. In a word, _Pragma.
The _Pragma directive is underspecified. While it is useful to have a
directive which can be used in open-ended fashion, there is no means by
which code can say "I want to use XX directive on compilers that support
it with the intended meaning, but do not wish to interfere with use of
this code on compilers that don't support it". If the Standard specified
a macro that would indicate whether a particular Standard-defined _Pragma
was supported, code could say:

#ifdef _STDC_supportsWoozle
#define woozle(x) _Pragma("woozle",x)
#else
#define woozle(x)
#endif

but at that point I see no real advantage to using a _Pragma rather than
a pre-defined macro which would do whatever a compiler would need to do
to support the construct, especially in cases where a construct would not
*require* a compiler to do anything but merely invite it to do so if
convenient [e.g. a directive applied to a "union" directive which would
invite compilers to ignore aliasing of structures therein with common
initial sequences, thus eliminating gcc's excuse for requiring the
-fno-strict-aliasing flag with code that makes use of the CIS rule].
Tim Rentsch
2016-11-01 16:42:48 UTC
Permalink
Post by s***@casperkitty.com
Post by Tim Rentsch
Besides, C already has a way that various code decorations can be
supplied in source code, if that is desired. In a word, _Pragma.
The _Pragma directive is underspecified. While it is useful to have a
directive which can be used in open-ended fashion, there is no means by
which code can say "I want to use XX directive on compilers that support
it with the intended meaning, but do not wish to interfere with use of
this code on compilers that don't support it". If the Standard specified
a macro that would indicate whether a particular Standard-defined _Pragma
#ifdef _STDC_supportsWoozle
#define woozle(x) _Pragma("woozle",x)
#else
#define woozle(x)
#endif
but at that point I see no real advantage to using a _Pragma rather than
a pre-defined macro which would do whatever a compiler would need to do
to support the construct, especially in cases where a construct would not
*require* a compiler to do anything but merely invite it to do so if
convenient [e.g. a directive applied to a "union" directive which would
invite compilers to ignore aliasing of structures therein with common
initial sequences, thus eliminating gcc's excuse for requiring the
-fno-strict-aliasing flag with code that makes use of the CIS rule].
Write more clearly. Start by limiting your sentences to no more
than 25 words each.
s***@casperkitty.com
2016-11-01 17:40:21 UTC
Permalink
Post by Tim Rentsch
Post by s***@casperkitty.com
Post by Tim Rentsch
Besides, C already has a way that various code decorations can be
supplied in source code, if that is desired. In a word, _Pragma.
The _Pragma directive is underspecified. While it is useful to have a
directive which can be used in open-ended fashion, there is no means by
which code can say "I want to use XX directive on compilers that support
it with the intended meaning, but do not wish to interfere with use of
this code on compilers that don't support it". If the Standard specified
a macro that would indicate whether a particular Standard-defined _Pragma
#ifdef _STDC_supportsWoozle
#define woozle(x) _Pragma("woozle",x)
#else
#define woozle(x)
#endif
but at that point I see no real advantage to using a _Pragma rather than
a pre-defined macro which would do whatever a compiler would need to do
to support the construct, especially in cases where a construct would not
*require* a compiler to do anything but merely invite it to do so if
convenient [e.g. a directive applied to a "union" directive which would
invite compilers to ignore aliasing of structures therein with common
initial sequences, thus eliminating gcc's excuse for requiring the
-fno-strict-aliasing flag with code that makes use of the CIS rule].
Write more clearly. Start by limiting your sentences to no more
than 25 words each.
At present, it is generally impossible to safely use #pragma or _Pragma
without targeting specific compilers. Many such directives serve to
improve optimization, but have no other necessary effect. Code which uses
such directives should be compatible with compilers that don't support them.
Predefining standardized macros would make that possible. If such macros
are defined, they can perform the effects that _Pragma would. I don't see
any advantage of _Pragma over such macros.
Keith Thompson
2016-11-01 18:26:33 UTC
Permalink
***@casperkitty.com writes:
[...]
Post by s***@casperkitty.com
At present, it is generally impossible to safely use #pragma or _Pragma
without targeting specific compilers.
Not entirely true. There are three language-defined #pragma directives:

#pragma STDC FP_CONTRACT on-off-switch
#pragma STDC FENV_ACCESS on-off-switch
#pragma STDC CX_LIMITED_RANGE on-off-switch

where on-off-switch is one of ON, OFF, or DEFAULT. Pragmas starting
with STDC are reserved for future standardization.
Post by s***@casperkitty.com
Many such directives serve to
improve optimization, but have no other necessary effect. Code which uses
such directives should be compatible with compilers that don't support them.
Predefining standardized macros would make that possible. If such macros
are defined, they can perform the effects that _Pragma would. I don't see
any advantage of _Pragma over such macros.
Implementations are required to ignore #pragmas that they do not
recognize.

N1570 6.10.6.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
s***@casperkitty.com
2016-11-01 20:19:36 UTC
Permalink
Post by Keith Thompson
[...]
Post by s***@casperkitty.com
At present, it is generally impossible to safely use #pragma or _Pragma
without targeting specific compilers.
I should have clarified: any pragma directives other than those defined
by the Standard and marked with STDC.
Post by Keith Thompson
Implementations are required to ignore #pragmas that they do not
recognize.
Unless a pragma is marked with STDC, there is no guarantee that an
implementation which doesn't recognize its intended meaning will not
recognize it as having some other entirely different meaning.
Keith Thompson
2016-11-01 21:08:54 UTC
Permalink
Post by s***@casperkitty.com
Post by Keith Thompson
[...]
Post by s***@casperkitty.com
At present, it is generally impossible to safely use #pragma or _Pragma
without targeting specific compilers.
I should have clarified: any pragma directives other than those defined
by the Standard and marked with STDC.
Post by Keith Thompson
Implementations are required to ignore #pragmas that they do not
recognize.
Unless a pragma is marked with STDC, there is no guarantee that an
implementation which doesn't recognize its intended meaning will not
recognize it as having some other entirely different meaning.
True, but it shoulnd't be a problem in practice. Compiler vendors have
an interest in avoiding conflicts.

For example, gcc uses `#pragma GCC` for at least some of its
implementation-defined pragmas. Microsoft's compiler, unfortunately,
does not use a similar scheme; for example, it has `#pragma once` et al.

I wouldn't mind seeing the standard add some implementation advice
suggesting that the first argument to a #pragma should be an identifier
(preferably all-caps, I supppose) specifying the implementation.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Tim Rentsch
2016-11-02 19:38:34 UTC
Permalink
Post by s***@casperkitty.com
Post by Tim Rentsch
Post by s***@casperkitty.com
Post by Tim Rentsch
Besides, C already has a way that various code decorations can be
supplied in source code, if that is desired. In a word, _Pragma.
The _Pragma directive is underspecified. While it is useful to have a
directive which can be used in open-ended fashion, there is no means by
which code can say "I want to use XX directive on compilers that support
it with the intended meaning, but do not wish to interfere with use of
this code on compilers that don't support it". If the Standard specified
a macro that would indicate whether a particular Standard-defined _Pragma
#ifdef _STDC_supportsWoozle
#define woozle(x) _Pragma("woozle",x)
#else
#define woozle(x)
#endif
but at that point I see no real advantage to using a _Pragma rather than
a pre-defined macro which would do whatever a compiler would need to do
to support the construct, especially in cases where a construct would not
*require* a compiler to do anything but merely invite it to do so if
convenient [e.g. a directive applied to a "union" directive which would
invite compilers to ignore aliasing of structures therein with common
initial sequences, thus eliminating gcc's excuse for requiring the
-fno-strict-aliasing flag with code that makes use of the CIS rule].
Write more clearly. Start by limiting your sentences to no more
than 25 words each.
At present, it is generally impossible to safely use #pragma or
_Pragma without targeting specific compilers. Many such
directives serve to improve optimization, but have no other
necessary effect. Code which uses such directives should be
compatible with compilers that don't support them. Predefining
standardized macros would make that possible. [...]
So would defining more STDC pragma cases. I like the _Pragma
approach better.

Jakob Bohm
2016-10-24 15:37:25 UTC
Permalink
Post by David Brown
Post by Keith Thompson
[...]
Post by a***@a3f.at
GNU C solves this with __attribute__((nonnull(...))). Examples of
usage can be found in both the GNU and BSD libc standard headers.
I suggest that adding a syntax for attributes would be a cleaner
solution. A recent C++ standard has already done this; C could easily
borrow it.
Yes, that seems a more obvious step. The two possibilities would be to
use the [[attribute]] syntax from C++, or the __attribute__((...))
syntax from gcc.
Given that several of the major C compilers (gcc, clang and icc) already
support this syntax, as do many other more target-specific compilers
(such as CodeWarrior and Arm/Keil armcc), it might make more pragmatic
sense to use the __attribute__ format.
And since self-documenting code is given as one of the benefits of this
proposal, surely __attribute__ is more "self-documenting" than yet
another overload of the "static" keyword? I wonder what percentage of C
int f(int p[static 1]);
So
int f(int * static p);
is not much better. But most programmers could make a solid guess as to
int f(int * p) __attribute__((nonnull(1)));
(though they might feel there are more brackets than necessary!)
And if __attribute__ were to make it into the standards, then it opens a
clear path towards standardising a range of useful attributes that are
already widely implemented and used, but not part of the ISO standards.
If looking at standardizing a previous vendor extension such as this,
another option is the somewhat cleaner Microsoft __declspec notation,
which has the following benefits:

1. It is syntactically placed as just another declaration modifier such
as const and volatile, not in the somewhat random locations required
by gcc quirks.

2. There is only one set of parenthesises, but multiple __declspec
modifiers can be placed in the same const/volatile syntactic position.

For example (if MS had used this one for nonnull, they actually use a
different more ad-hoc PREfast notations):

__declspec(dllexport) int
f(const int * __declspec(nonnull) __declspec(nonretained) restrict p);

(dllexport is an attribute that indicates that the function should be
exposed in the dynamic symbol table after build time linking (similar
to one of the values for the GNU visibility attribute), the
contrary dllimport attribute specifies that an extern function or
object should be accessed via the GOT at runtime, without the overhead
of going through stubs etc.)

Enjoy

Jakob
--
Jakob Bohm, CIO, Partner, WiseMo A/S. https://www.wisemo.com
Transformervej 29, 2860 Søborg, Denmark. Direct +45 31 13 16 10
This public discussion message is non-binding and may contain errors.
WiseMo - Remote Service Management for PCs, Phones and Embedded
David Brown
2016-10-25 08:27:50 UTC
Permalink
Post by Jakob Bohm
Post by David Brown
Post by Keith Thompson
[...]
Post by a***@a3f.at
GNU C solves this with __attribute__((nonnull(...))). Examples of
usage can be found in both the GNU and BSD libc standard headers.
I suggest that adding a syntax for attributes would be a cleaner
solution. A recent C++ standard has already done this; C could easily
borrow it.
Yes, that seems a more obvious step. The two possibilities would be to
use the [[attribute]] syntax from C++, or the __attribute__((...))
syntax from gcc.
Given that several of the major C compilers (gcc, clang and icc) already
support this syntax, as do many other more target-specific compilers
(such as CodeWarrior and Arm/Keil armcc), it might make more pragmatic
sense to use the __attribute__ format.
And since self-documenting code is given as one of the benefits of this
proposal, surely __attribute__ is more "self-documenting" than yet
another overload of the "static" keyword? I wonder what percentage of C
int f(int p[static 1]);
So
int f(int * static p);
is not much better. But most programmers could make a solid guess as to
int f(int * p) __attribute__((nonnull(1)));
(though they might feel there are more brackets than necessary!)
And if __attribute__ were to make it into the standards, then it opens a
clear path towards standardising a range of useful attributes that are
already widely implemented and used, but not part of the ISO standards.
If looking at standardizing a previous vendor extension such as this,
another option is the somewhat cleaner Microsoft __declspec notation,
1. It is syntactically placed as just another declaration modifier such
as const and volatile, not in the somewhat random locations required
by gcc quirks.
2. There is only one set of parenthesises, but multiple __declspec
modifiers can be placed in the same const/volatile syntactic position.
For example (if MS had used this one for nonnull, they actually use a
__declspec(dllexport) int
f(const int * __declspec(nonnull) __declspec(nonretained) restrict p);
(dllexport is an attribute that indicates that the function should be
exposed in the dynamic symbol table after build time linking (similar
to one of the values for the GNU visibility attribute), the
contrary dllimport attribute specifies that an extern function or
object should be accessed via the GOT at runtime, without the overhead
of going through stubs etc.)
Enjoy
Jakob
I agree that gcc's __attribute__ placement is not always logical or
consistent. But it has the key advantage of being widely supported
amongst modern C compilers (MS's C support is old and limited - and
since they are moving to clang as a C front-end, they get __attribute__
from clang).

The alternative is C++'s [[...]] attribute format. That has the
advantage of being standardised as well as being logically placed. So
attributes that make sense in both languages could be identical. C
compilers don't support these attributes at the moment, but the "big" C
compilers (gcc, clang, icc) support them in C++ so implementation should
be a relatively small task.

The __declspec syntax may be more consistent, but it is the worst of
both worlds - it is not implemented in C compilers, and it is not
consistent with related (C++) standards.
s***@casperkitty.com
2016-10-25 14:31:40 UTC
Permalink
Post by David Brown
I agree that gcc's __attribute__ placement is not always logical or
consistent. But it has the key advantage of being widely supported
amongst modern C compilers (MS's C support is old and limited - and
since they are moving to clang as a C front-end, they get __attribute__
from clang).
The alternative is C++'s [[...]] attribute format. That has the
advantage of being standardised as well as being logically placed. So
attributes that make sense in both languages could be identical. C
compilers don't support these attributes at the moment, but the "big" C
compilers (gcc, clang, icc) support them in C++ so implementation should
be a relatively small task.
An important consideration with attributes is how they should interact with
past and future compiler versions. If an attribute specifies a behavior
which some implementations would do naturally and other won't, I would think
it would be desirable to define the attributes in such a way as to allow
code using them to be compatible with existing compilers that naturally abide
the requirements in question, merely by including a suitable header file.

Further, I think there should be a distinction between attributes which
impose requirements upon a compiler(*) and those that don't, in such a
fashion that compilers will know that they can safely ignore unrecognized
directives of the latter form.

(*) E.g. a directive, applied to a union declaration, which would waive the
common-initial-sequence guarantee for its members even in cases where
the complete union type declaration is visible, i.e. make the declaration
behave like gcc illegitimately treats all union declarations. Since
waiving the guarantee would not require the compiler to do anything,
the correctness of a program could not be affected by a compiler's
failure to recognize it.

Even if a new syntax like [[ ]] were added, code that wanted to work with
old compilers might still be able to define a macro that would expand to
a [[ ]] form on compilers that support it, or to nothing on compilers that
don't, but I think it would be better to have the Standard itself define
such a macro than to have different programmers develop different ad-hoc
solutions.
Keith Thompson
2016-10-23 22:05:04 UTC
Permalink
Post by a***@a3f.at
I'd like to propose extending the syntax for pointer parameter
int f(int * static p);
Which should be equivalent to
int f(int p[static 1]);
FYI, a link to this thread has been posted on reddit.

https://www.reddit.com/r/programming/comments/58yfxb/compstdc_proposal_to_allow_static_qualifier_for/
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Thiago Adams
2016-10-28 12:36:58 UTC
Permalink
Post by a***@a3f.at
Hello,
int f(int * static p);
Which should be equivalent to
int f(int p[static 1]);
For incomplete types, the static qualified pointer means that the pointer argument shall not be null.
I think annotations should be ignored by C compilers (unless the compiler uses for optimization like restrict, or any kind of code generation) and they should be used optionally by static analyzers. Before to create any mechanism to express annotations in C standard, and in this case C++ [[annotations]] is a candidate for syntax, I think its necessary to find the most important and common cases.

For this particular one (non-null), the problem I see , is that 95% of cases the argument is non-null and this would require to much annotations for the case that is common. To minimize annotations I think the static analyzer should consider all arguments non-null and check callers and annotate just the ones that can be null (optional). This decision was made for instance in TypeScript - nullable types. Note that in typescript, the type-system was changed and it's not only annotations form.

Another important annotation is if a pointer points to one or many objects, both function arguments or member of struct.

I am very interested in this subject because I start to implement one static analyzer.
Thiago Adams
2016-10-28 12:44:46 UTC
Permalink
On Sunday, October 23, 2016 at 10:18:20 AM UTC-2, ah... a3f.at wrote:

...
Post by a***@a3f.at
And no standard way of specifying that the pointers in the previous listing are non-null exists.
GNU C solves this with __attribute__((nonnull(...))). Examples of usage can be found in both the GNU and BSD libc standard headers.
The advantage of __attribute__((nonnull(...))) is that if you have a new code (annotated) and want to use with a compiler that doesn't support annotations then you can create a macro __attribute__.
In the other hand with [[ ]] you need to write code with macros to simulate annotations and them remove if necessary.
Loading...