4

Why does the following code give the following error?

Why does the type need to be complete in order to be casted to void?

struct Incomplete;
class Class
{
    virtual void foo(Incomplete &incomplete)
    {
        (void) incomplete;
        throw std::logic_error("not implemented");
    }
};

Error:

error C2027: use of undefined type 'Incomplete'  
    see declaration of 'Incomplete'
user541686
  • 205,094
  • 128
  • 528
  • 886
  • 2
    Why could it would be the more interesting question. Simply use `(void)&incomplete` instead. – Hans Passant Mar 21 '15 at 09:05
  • 1
    FWIW, GCC and clang don't have any problems with it. –  Mar 21 '15 at 09:08
  • It doesn't compile in VS2013, but compiles in [Microsoft's online compiler](http://webcompiler.cloudapp.net/). So it's probably just a bug. –  Mar 21 '15 at 09:10
  • @HansPassant: That makes me ask another question... http://stackoverflow.com/q/29181013/541686 – user541686 Mar 21 '15 at 09:11
  • @remyabel: Oh. Please post this as an answer! – user541686 Mar 21 '15 at 09:12
  • 1
    Interesting. You don't even need a cast to `void`. Try `void foo(Incomplete &incomplete) { incomplete; }` and it will give you the exact same error. – Christian Hackl Mar 21 '15 at 09:12
  • 1
    Further indication that this seems to a buggy area of the compiler: try to declare an array of `Incomplete`, e.g. `Incomplete x[1];` It says `error C2148: total size of array must not exceed 0x7fffffff bytes`, which is a pretty strange message for what GCC calls `elements of array 'Incomplete x [1]' have incomplete type`. – Christian Hackl Mar 21 '15 at 09:28

2 Answers2

6

It's a change between C and C++, where Microsoft previously implemented the C rules. As noted in remyabel's answer, that has since been fixed.

In C, a cast to void, or simply using an expression as a statement by itself (as in incomplete;), still involves the lvalue-to-rvalue conversion. C calls it slightly differently, but it's the same conversion.

In C++, a cast to void, or simply using an expression as a statement by itself doesn't involve the lvalue-to-rvalue conversion. This is needed because C++ makes assignment operators return lvalues, so if the lvalue-to-rvalue conversion were applied, then

volatile int i;
i = 1;

would not merely store, it would also immediately load afterwards.

The lvalue-to-rvalue conversion requires a complete type, even if the value is then discarded, since otherwise, it's impossible to know how many bytes should be read.

3

I don't see anything prohibiting this, quoting N4140:

§5.4/4 The conversions performed by

[...]

— a static_cast (5.2.9),

[...]

can be performed using the cast notation of explicit type conversion.

§5.2.9/5 Otherwise, the static_cast shall perform one of the conversions listed below. No other conversion shall be performed explicitly using a static_cast.

§5.2.9/6 Any expression can be explicitly converted to type cv void, in which case it becomes a discarded-value expression (Clause 5). [...]

It's most likely a bug as tested on Rextester, an online VS2013 compiler, but compiles in rise4fun, Microsoft's online compiler which is bleeding edge.