Ill-Formed, No Diagnostic Required (NDR): ConstExpr Function Throw in C++14
Asked Answered
D

1

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?

Dispirit answered 31/1, 2017 at 15:21 Comment(6)
What do you think "no diagnostic required" means?Coranto
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.Leucoderma
You can find the answer in the "interesting discussions" you linked to.Kellen
@Coranto 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.Dispirit
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.Rimola
@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.Dispirit
B
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.

Bilek answered 31/1, 2017 at 15:42 Comment(3)
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.Question
@Yakk-AdamNevraumont How can I find out when was a compiler error introduced to the compiler?Demurrage
@saju I'd use godbolt and binary search myself. Or grep compiler source code and use git blame.Question

© 2022 - 2024 — McMap. All rights reserved.