Home > Software design >  Does IFNDR take precedence over diagnosable rule violations?
Does IFNDR take precedence over diagnosable rule violations?

Time:08-22

[intro.compliance.general]/2 specifies how a compiler should handle a program given to it.

In particular it has two points dealing with ill-formed programs. (2.2) requires the compiler to issue at least one diagnostic for a violation of a diagnosable rule. (2.3) states that there are no requirements imposed on the compiler for a program which violates a rule for which no diagnostic is required.

Unfortunately I don't think the paragraph makes a precedence between the two requirements clear. If a program contains a violation of a diagnosable rule for which a diagnostic is required and a violation of a rule for which no diagnostic is required, is the compiler required to issue a diagnostic?

As an example (considered as a whole one-translation-unit program):

// ill-formed, diagnostic required
int main() { using T = void&; }

// IFNDR according to [temp.res.general]/8.1 and [temp.res.general]/8.4
void f(auto) { using T = void&; }

Moreover, if IFNDR takes precedence, the same presumably applies to undefined behavior that is typically considered runtime UB, e.g. does

// always runtime undefined behavior
int main() { return *(int*)0; }

// ill-formed, diagnostic required
using T = void&;

then technically also not require a diagnostic (considered as a whole one-translation-unit program)?


From a quality-of-implementation standpoint it seems clear to me that the compiler should issue a diagnostic whenever possible in such a situation.

But my impression is that the standard does not actually require one and this is also what I have read/heard before. For example the qualification of "and the template is not instantiated" in [temp.res.general]/8.1 would not make much sense otherwise. However at other times the standard doesn't use such inverting qualifications where it seems that they should be required, e.g. [dcl.constexpr]/6.

CodePudding user response:

The wording is precise. The wording in question says:

... this document places no requirement ...

This would obviously include a requirement that this clause supercedes all other clauses, and specifically 2.2

Clause 2.2 still applies. It is still effective. The applicability of 2.3 has no effect on 2.2 by the plain wording of 2.3.

Since the program is still diagnosable as ill-formed with respect to 2.2, then a diagnostic, with respect to what 2.2 applies to, is still required.

It goes without saying that this is the intuitive interpretation. It would make no practical sense for some non-diagnosable condition in some function will make the compiler not complain about some completely different function attempting to return an int, when it should return a void.

CodePudding user response:

Section 2.3 is clear – "this document places no requirement on implementations". Not "this document except for 2.2", but "this document". If an IFNDR situation exists, then the implementation is free to do anything.

Necessary

Overriding 2.2 is necessary. Hypothetically, an IFNDR situation could throw compilation off-track, resulting in it missing an ill-formed situation that does require a diagnostic. (Bugs hidden by other bugs is not a novel concept.) This does not make the implementation non-conforming. The existence of the IFNDR situation gives implementations the leeway they need to potentially miss a diagnostic in related code despite good-faith processing.

This does mean that implementations also have leeway to miss a diagnostic in unrelated code. Oh well. The standard could try to distinguish between "related code" and "unrelated code", but it would be wasted effort. At some point, it is better to trust that implementations work in good faith, rather than excessively regulate.

A "diagnostic not required" scenario is a valid reason for missing a diagnostic. If an implementation uses it as an excuse to actively omit a diagnostic, then it is compliant, but you should stay away. Just like you should stay far away from a compliant implementation that detects undefined behavior and uses that as an excuse to format your hard drive.

Practical

From a practical perspective, though, 2.3 does not override 2.2. While the official terminology is "no diagnostic required", a more practical view is "the situation does not need to be detected". Situations that require a diagnostic must be detected so that the diagnostic can be produced. Situations that do not require any particular action by the implementation do not need to be detected.

If an implementation does not detect an IFNDR situation, then it cannot make decisions based upon the IFNDR existing. That is, it must provide diagnostics for the ill-formedness that it does detect. This is not just "quality-of-implementation", nor is it just "good faith", but rather it is necessary to ensure compliance in the face of an unknown.

If an implementation does detect an IFNDR situation, then we fall back on good faith.

  • Related