3
#include <iostream>
using namespace std;

constexpr int f(bool b){ return b ? throw 0 : 0; } // OK 

constexpr int f() { return f(true); } // Ill-Formed, No Diagnostic Required

int main(){

    try{
        f();
    }catch( int x ){
        cout << "x = " << x << endl;
    }

    return 0;
}

This code is an example from the C++14 Standard (ISO/IEC 14882:2014), Section 7.1.5, Paragraph 5:

For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting constexpr constructor, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no diagnostic required.

It is described as "ill-formed, no diagnostic required" because a throw-expression is not a core constant expression (5.19/2). However, both Clang and GCC compile it successfully (Ideone).

  • Is this code correct (and there is a mistake in the Standard) or is it incorrect (and there is a bug in both Clang and GCC)?

I also found these interesting discussions about the Standard wording:

Is it possible that a/this program is "ill-formed, no diagnostic required" and that the compilers are allowed to compile it successfully?

Community
  • 1
  • 1
J L
  • 563
  • 3
  • 17
  • 11
    What do you think "no diagnostic required" means? – ildjarn Jan 31 '17 at 15:23
  • From memory, clang interprets the thrown exception as a compiler error and reports it nicely, at least if throw a standard exception. I thought that was a nice touch. – Richard Hodges Jan 31 '17 at 15:29
  • You can find the answer in the "interesting discussions" you linked to. – molbdnilo Jan 31 '17 at 15:33
  • @ildjarn I think "no diagnostic required" means that there is "no diagnostic required". In the same way, I think "Ill-formed" means that it is not well-formed. Hence, my question. If it is not well-formed, why does it compile correctly? Thanks for your help. – J L Jan 31 '17 at 15:33
  • 5
    *ill-formed, no diagnostic required* means that the standard makes no requirement on what compiler should do. That means that it is a compile time problem and the behaviour is undefined. A compiler can choose to raise a compilation error and it will be conformant, another can choose to remove the offending `throw`, compile and raise a warning and it will be conformant, a third one can choose to silently compile after removing the offending expression, or to compile the program in a run time error and all will be conformant. – Serge Ballesta Jan 31 '17 at 15:38
  • 1
    @SergeBallesta That is what I thought, I just didn't think it made sense to allow compilers to compile successfully a not well-formed program. Thank you very much for your comment, it has been very useful to understand everything. – J L Jan 31 '17 at 16:06

1 Answers1

8

Is this code correct (and there is a mistake in the Standard)

The standard is what decides if a program is "correct" i.e. well-formed. The standard explicitly says that the program is ill-formed.

or is it incorrect (and there is a bug in both Clang and GCC)?

The program is ill-formed (incorrect). Both clang and gcc are standard compliant in their observed behaviour.

Is it possible that a/this program is "ill-formed, no diagnostic required" and that the compilers are allowed to compile it successfully?

Yes. The standard doesn't require that an ill-formed program must fail to compile. It merely requires that the implementation issues at least one diagnostic message, if the program violates the rules. Some rules are not diagnosable, and diagnostic is not required if such rules are violated.

In fact, the rule is considered "not diagnosable" because it would be very difficult for the compiler to prove (in general) that the rule is violated. It is quite typical that "no diagnostic required" rule violations compile successfully.

If an ill-formed program does compile, the standard does not specify how such program should behave.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • As a standard design issue, ill-formed no diagnostic required means that programs that violate these rules may, in the future, fail to compile with an error message, *without any previously valid programs being impacted by this change*. A compiler could add diagnostics, or the standard could, and it would have zero impact on any standard-compliant code prior to that change. If you look at "ill-formed, no diagnostic required", they tend to occur in the standard where the standard writers would love to enforce a rule, but see no easy way to do it currently. – Yakk - Adam Nevraumont Jan 31 '17 at 20:35
  • @Yakk-AdamNevraumont How can I find out when was a compiler error introduced to the compiler? – Sajuuk May 23 '20 at 01:25
  • 1
    @saju I'd use godbolt and binary search myself. Or grep compiler source code and use git blame. – Yakk - Adam Nevraumont May 23 '20 at 01:47