9

The following code compiles with G++ 4.6.1, but not with Visual Studio 2008

return (m_something == 0) ? 
    throw std::logic_error("Something wrong happened") : m_something;

The fact is the Visual Studio compiler performs an internal crash.

I want to know if this is standard C++ and why it doesn't compile with Visual Studio, but does with G++?

fmorency
  • 764
  • 5
  • 11
  • 8
    Regardless of this being valid code or not according to the standard, when a compiler crashes with an internal compiler error (which is what VC does, IIUC), then that is an error in the compiler. A compiler is supposed to emit a meaningful message even for faulty code, not a crash report. – sbi Oct 31 '11 at 18:27
  • Keep in mind this is the *conditional operator*, which happens to be *a* ternary operator. – GManNickG Oct 31 '11 at 19:05
  • Yeah, got confused when "ternary" wasn't in the spec anywhere. – Mooing Duck Oct 31 '11 at 22:26
  • 1
    For a brief period (between c++11 and c++14) throwing from a ternary was the only way to write constexpr functions that could fail at compile-time. – alfC Dec 02 '20 at 19:33

4 Answers4

13

It is standard C++. Either (or both) of the then/else expressions in a conditional expression is allowed to be a throw-expression instead (C++98 5.16/2).

If Visual Studio crashes when compiling it... that would seem to be unfortunate!

John Marshall
  • 6,815
  • 1
  • 28
  • 38
4

Comeau compiles it without errors (here's my minimal compilable test case):

int main(void)
{
    int x = 17;
    return x ? throw "Something wrong happened" : 5;
}

which is pretty good evidence that it's allowed by the standard. So is the fact that MSVC crashes, rather than failing cleanly with an error.

Also, it appears to be fixed in VC++ 2010

R:\>cl ternarythrowtest.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

ternarythrowtest.cpp
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:ternarythrowtest.exe
ternarythrowtest.obj

and x64 version:

R:\>cl ternarythrowtest.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

ternarythrowtest.cpp
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:ternarythrowtest.exe
ternarythrowtest.obj

Upgrade your compiler if possible, this is far from the only bug fixed in 2010.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Indeed, this is probably because of C++11 compliance, see @MooingDuck's answer. – André Caron Oct 31 '11 at 18:15
  • 1
    @AndréCaron: That fails to explain an "Internal Compiler Error". And see John's answer, it's allowed in C++98 as well. – Ben Voigt Oct 31 '11 at 18:17
  • I'm on @fmorency's team, and I'm the one who encountered the Microsoft Compiler crash with his throw-in-a-ternary-operator expression. We were trying to figure out if it was standard, not if this is a bug in Microsoft's compiler (there is obviously *a* bug, since it crashes). – André Caron Oct 31 '11 at 18:21
  • @AndréCaron: Well, it's C++98, not a C++11 compliance issue, so it's definitely supposed to work. – Ben Voigt Oct 31 '11 at 18:22
  • Indeed :-). Unfortunately, we're stuck with Qt 4.7 at the moment and we support Windows, so we're stuck with VS2008's compiler. – André Caron Oct 31 '11 at 18:25
  • @AndréCaron: How does that prevent you from moving to 2010? – Ben Voigt Oct 31 '11 at 18:42
  • VS2010 is not officially supported by Qt 4.7, and someone higher up the food chain decided we were sticking to "officially supported" solutions. – André Caron Oct 31 '11 at 19:02
4

From the C++11 February Draft

§ 5.16/2 If either the second or the third operand has type (possibly cv-qualified) void, then the lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the second and third operands, and one of the following shall hold:
— The second or the third operand (but not both) is a throw-expression (15.1); the result is of the type of the other and is a prvalue.
— Both the second and the third operands have type void; the result is of type void and is a prvalue. [ Note: This includes the case where both operands are throw-expressions. —end note ]

It appears that throw counts as evaluating to a void, and that this is allowed.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • 1
    C++11 is scarcely relevant to VS2008 (except that this isn't a C++11 rule, it's unchanged since C++98, see John's answer). – Ben Voigt Oct 31 '11 at 18:19
  • I don't have a copy of the C++03 draft (for VS2008) to quote from, or I would have quoted from that instead. You're right that it didn't necessarily apply to VS2008 however. – Mooing Duck Oct 31 '11 at 18:26
2

The internal crash can be considered a bug of Visual Studio. A compiler should never crash because of the code being compiled.

This is a very strange usage of the ternary operator, a simple if before the return would be a much preferable idiom:

if(m_something == 0)
    throw std::logic_error("Something wrong happened");

return m_something;
lvella
  • 12,754
  • 11
  • 54
  • 106