noexcept-Operator gibt Compilation Error mit GCC aber nicht mit Clang



  • Hallo

    Folgender Code generiert einen Compilation Error mit GCC 7.2.0 aber nicht mit Clang 4.0.1:

    struct foo
    {
        void f() noexcept
        {
        }
        void g() noexcept( noexcept( f() ) )
        {
        }
    };
    

    Live: GCC, Clang
    Hier bin ich mir ziemlich sicher, dass Clang recht hat, denn der Operand des noexcept -Operators sollte nicht evaluiert werden.

    Ändert man nun foo zu einem Klassentemplate, dann kompiliert der Code lustigerweise fehlerfrei mit beiden Compilern.
    Live: GCC, Clang

    Und noch kurioser: Ändert man den noexcept -Operator zu noexcept( f ) , dann kompiliert der Code zwar mit GCC aber nicht mehr mit Clang.
    Live: GCC, Clang
    Hier verstehe ich nicht, wieso der Clang-Compiler einen Fehler generiert, denn f ist doch einfach der Member-Funktionszeiger und so etwas wie noexcept( nullptr ) ist ja auch erlaubt.

    Hat jemand den Durchblick, was hier geschieht? 🙂

    LG


  • Mod

    Fytch schrieb:

    Hier bin ich mir ziemlich sicher, dass Clang recht hat, denn der Operand des noexcept -Operators sollte nicht evaluiert werden.

    Das ist nicht der entscheidende Punkt, sondern dass die Transformation von Namen von Membern zu member access expressions auch auf Operanden von noexcept angewandt wird. Das war u.a. core issue 1207. GCC ist einfach verbuggt: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52869

    Fytch schrieb:

    Ändert man nun foo zu einem Klassentemplate, dann kompiliert der Code lustigerweise fehlerfrei mit beiden Compilern.
    Live: GCC, Clang

    Das ist ein Trugschluss. Du führst keine Instantiierung des noexcept -specifiers herbei, siehe [temp.inst]/2. Der GCC bug tritt weiterhin auf: http://coliru.stacked-crooked.com/a/5ffeadeeb18cfebe

    Fytch schrieb:

    Und noch kurioser: Ändert man den noexcept -Operator zu noexcept( f ) , dann kompiliert der Code zwar mit GCC aber nicht mehr mit Clang.
    Live: GCC, Clang
    Hier verstehe ich nicht, wieso der Clang-Compiler einen Fehler generiert, denn f ist doch einfach der Member-Funktionszeiger und so etwas wie noexcept( nullptr ) ist ja auch erlaubt.

    [except.spec]/2 schreibt vor, dass der Ausdruck eine *contextually converted constant expression of type bool *ist. Die Konvertierungen sind beschränkt wie in [expr.const]/5 beschrieben. Boolean conversions, die für die Konvertierung eines Funktions-lvalues zu einem bool nötig sind, werden nicht aufgezählt; somit hat Clang Recht. noexcept(nullptr) ist aus dem selben Grund ill-formed, obwohl alle Compiler es problemlos kompilieren.



  • Vielen Dank für die Aufklärung.

    Arcoth schrieb:

    [except.spec]/2 schreibt vor, dass der Ausdruck eine *contextually converted constant expression of type bool *ist. Die Konvertierungen sind beschränkt wie in [expr.const]/5 beschrieben. Boolean conversions, die für die Konvertierung eines Funktions-lvalues zu einem bool nötig sind, werden nicht aufgezählt; somit hat Clang Recht. noexcept(nullptr) ist aus dem selben Grund ill-formed, obwohl alle Compiler es problemlos kompilieren.

    Ich glaube, hierbei handelt es sich um den noexcept -Operator, nicht um den von dir verlinkten noexcept -Specifier. Folglich sollte noexcept(nullptr) sowie auch noexcept(f) well-formed sein.


  • Mod

    Sorry, ich war noch völlig dösig als ich das geschrieben habe. Ich dachte zuerst, du meintest

    void g() noexcept(f) {}
    

    Aber auch deine Variante ist ill-formed. f ist eine Memberfunktion (ich habe irgendwann einfach angenommen, sie sei es nicht... 😕 ), und der Ausdruck (*this).f , in den dein Operand überführt wird, darf nur auf der linken Seite eines Funktionsaufrufes stehen. Dahingegen ist nullptr natürlich ein wohlgeformter Ausdruck.



  • Okay, danke dir Arcoth. 👍

    Falls jemand dasselbe Problem hat, über den Thread stolpert und nach einem Workaround sucht: Ich habe einfach einen static constexpr bool x = ...; innerhalb der Klasse angelegt, der den noexcept -Wert hält. Danach habe ich f und g jeweils mit noexcept(x) deklariert. Funktioniert, solange nicht sowohl f ein Funktionstemplate ist und sein noexcept -Specifier von den Template-Argumenten abhängt.

    LG


Anmelden zum Antworten