Bug 96765 - Base class constructor cast to derived should cause a warning
Summary: Base class constructor cast to derived should cause a warning
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 10.2.1
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: new-warning, new_warning
  Show dependency treegraph
 
Reported: 2020-08-24 11:43 UTC by John Zwinck
Modified: 2023-07-01 21:14 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-12-16 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description John Zwinck 2020-08-24 11:43:57 UTC
If I cast "this" in a base class constructor to a derived class type, there is no warning even with -Wall -Wextra.  Such a cast is undefined behavior, and seems like it should be diagnosed at compile time.

For example:

    struct Base
    {
      Base();
      int num;
    };

    struct Derived : Base
    {
      int calc() const { return 42; }
    };

    Base::Base()
      // UB: Derived not yet constructed
      : num(static_cast<Derived*>(this)->calc())
    {
    }

    int main()
    {
      Derived d;
      return d.num;
    }

It compiles cleanly with "-Wall -Wextra -Werror" in GCC 8 and 10, with and without optimization.  I think it should produce a diagnostic such as "invalid static_cast from type ‘Base*’ to type ‘Derived*’ before the latter is constructed".

UBSan reports the undefined behavior if Base has a virtual method (e.g. if you add "virtual ~Base() = default;"), but not with the code as written, making it even more advantageous to diagnose at compile time.

Live demo: https://godbolt.org/z/x3fa4Y
Comment 1 Jonathan Wakely 2020-08-24 13:10:27 UTC
I agree a diagnostic makes sense.
Comment 2 Jason Merrill 2022-05-04 16:11:09 UTC
Hmm, is the cast undefined, actually?  I thought you were right, but now can't find any wording to that effect.  I see

[expr.static.cast] If the prvalue of type “pointer to cv1 B” points to a B that is actually a base class subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the behavior is undefined.

But this B is a base of a D.  Then

[class.cdtor] For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior.

but D() has begun execution.  Then

[class.cdtor] During the construction of an object, if the value of the object or any of its subobjects is accessed through a glvalue that is not obtained, directly or indirectly, from the constructor’s this pointer, the value of the
object or subobject thus obtained is unspecified.

but 'this' in the Base ctor seems to count as obtained indirectly from 'this' in the Derived ctor.

Then [class.cdtor] paragraph 4 talks about virtual functions, which this is not.

What rule makes this undefined?