5

The following program...

int main()
{
    int{1}.~int();
}

does not compile on (see conformance viewer):

  • clang++ trunk, with -std=c++1z

  • g++ trunk, with -std=c++1z

  • CL 19 2017


Introducing a type alias for int...

int main()
{
    using X = int;
    int{1}.~X();
}

...makes the program valid on all previously mentioned compilers, without warnings (see conformance viewer).

Why is a type alias required when invoking int's destructor? Is this because int is not a valid grammar element for a destruction invocation?

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • 1
    Why would you ever want to invoke an int destructor? –  Sep 26 '17 at 14:52
  • Int is a native type, do you need a destructor for it? – Girauder Sep 26 '17 at 14:53
  • 3
    @manni66: it makes sense in generic contexts *(e.g. implementing `std::optional`)*, but this question was created purely out of curiosity. – Vittorio Romeo Sep 26 '17 at 14:53
  • 1
    Looks like someone has been watching [C++ WAT](https://youtu.be/rNNnPrMHsAA?t=4m). – nwp Sep 26 '17 at 14:53
  • @nwp: oh wow, I actually attended that talk back in 2015. It was a ton of fun. This question has nothing to do with it, it originated from some discussion on my internal corporate C++ chat :) – Vittorio Romeo Sep 26 '17 at 14:56
  • It looks like it should work (see [bullet 7 here](http://en.cppreference.com/w/cpp/language/operator_member_access#Built-in_member_access_operators))... – Quentin Sep 26 '17 at 14:58
  • 1
    I'm pretty sure `t.~T()` works in a template, taking care of generic contexts. Can't say I can think of a situation where I'd want to use `int` directly. – chris Sep 26 '17 at 15:00
  • 1
    Why the downvote? @chris: me neither, this is mostly a "language-lawyer" curiosity question. – Vittorio Romeo Sep 26 '17 at 15:03
  • 2
    I marked as duplicate because Columbo nailed it in his answer. "You can't actually call a destructor for scalars, because they don't have one (see §12.4). The statement is solely allowed for template code in which you call the destructor of an object whose type you don't know - it removes the necessity of writing a specialization for scalar types." -- I should note that 12.4 should be replaced with [class.dtor] for accuracy. – AndyG Sep 26 '17 at 15:11

1 Answers1

10

It works because the grammar didn't make provisions for built-in types, but it did make provisions for aliases:

[expr.post]/1:

postfix-expression:
    postfix-expression . pseudo-destructor-name
    postfix-expression -> pseudo-destructor-name

pseudo-destructor-name:
    ~ type-name
    ~ decltype-specifier

And [dcl.type.simple]/1:

type-name:
  class-name
  enum-name
  typedef-name
  simple-template-id

You can imagine what each variable under type-name stands for. For the case at hand [expr.pseudo]/1 specifies that it is just a void expression:

The use of a pseudo-destructor-name after a dot . or arrow -> operator represents the destructor for the non-class type denoted by type-name or decltype-specifier. The result shall only be used as the operand for the function call operator (), and the result of such a call has type void. The only effect is the evaluation of the postfix-expression before the dot or arrow.

The interesting thing to note, is that you should be able do that without an alias (if you have a named object), because the pseudo destructor call also works with a decltype specifier:

auto a = int{1};
a.~decltype(a)();
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • The last snippet doesn't compile for gcc (_"expected identifier before 'decltype'"_), but does for clang. Based on you rationale, is this a bug/limitation in gcc trunk? Related: for the specific case of this example (`int`), we can use the (apparent) fact that the `decltype` specifier applied to an integer literal yields type `int`, to construct `int{1}.~decltype(0)();` which compiles with clang. Moreover, peculiarly, `int{1}.~decltype(auto)();` crashes clang prompting us to file a bug report. For e.g. a custom POD `Foo`, `Foo{1}.~decltype(auto)();` does not crash, but yields an error. – dfrib Sep 26 '17 at 20:05
  • @dfri - The dry letter of the standard indicates that as a bug in GCC, yes. And it should be fixed since the construct is legal. As for the crash in Clang... this is so much of an edge case I'm not sure it's worth the bug report. – StoryTeller - Unslander Monica Sep 27 '17 at 05:05
  • Thanks. As for the clang crash, I agree, and would feel silly if posting a bug report for it. – dfrib Sep 27 '17 at 15:07