Hi!

This patch adds a warning when casting "this" to Derived* in the Base
class constructor and destructor. I've added the warning under the
-Wextra flag as I can't find a more appropriate flag for it.

The patch has been bootstrapped and regression tested on x86_64-pc-linux-gnu.

Appreciate reviews and feedback. Thanks!
From c70e087c7ee9db7497da293f8a85891abe895d9a Mon Sep 17 00:00:00 2001
From: Zhao Wei Liew <zhaoweil...@gmail.com>
Date: Tue, 22 Feb 2022 16:03:17 +0800
Subject: [PATCH] c++: warn when casting "this" to Derived* in Base ctor/dtor
 [PR96765]

Casting "this" in a base class constructor to a derived class type is
undefined behaviour, but there is no warning when doing so.

Add a warning for this.

Signed-off-by: Zhao Wei Liew <zhaoweil...@gmail.com>

        PR c++/96765

gcc/cp/ChangeLog:

        * typeck.cc (build_static_cast_1): Add a warning when casting
          "this" to Derived * in Base constructor and destructor.

gcc/testsuite/ChangeLog:

        * g++.dg/warn/Wextra-5.C: New test.
---
 gcc/cp/typeck.cc                     |  9 ++++++++
 gcc/testsuite/g++.dg/warn/Wextra-5.C | 33 ++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/warn/Wextra-5.C

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 516fa574ef6..782f70b27e6 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -8079,6 +8079,15 @@ build_static_cast_1 (location_t loc, tree type, tree 
expr, bool c_cast_p,
     {
       tree base;
 
+      if (current_function_decl
+          && (DECL_CONSTRUCTOR_P (current_function_decl)
+              || DECL_DESTRUCTOR_P (current_function_decl))
+          && TREE_CODE (expr) == NOP_EXPR
+          && is_this_parameter (TREE_OPERAND (expr, 0)))
+        warning_at(loc, OPT_Wextra,
+                   "invalid %<static_cast%> from type %qT to type %qT before 
the latter is constructed",
+                   intype, type);
+
       if (processing_template_decl)
        return expr;
 
diff --git a/gcc/testsuite/g++.dg/warn/Wextra-5.C 
b/gcc/testsuite/g++.dg/warn/Wextra-5.C
new file mode 100644
index 00000000000..7e82c4c6121
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wextra-5.C
@@ -0,0 +1,33 @@
+// PR c++/96765
+// { dg-options "-Wextra" }
+
+struct Derived;
+struct Base {
+  Derived *x;
+  Derived *y;
+  Base();
+  ~Base();
+};
+
+struct Derived : Base {};
+
+Base::Base()
+    : x(static_cast<Derived *>(this)), // { dg-warning "invalid 'static_cast'" 
}
+      y((Derived *)this) // { dg-warning "invalid 'static_cast'" }
+{ 
+  static_cast<Derived *>(this); // { dg-warning "invalid 'static_cast'" }
+  (Derived *)this; // { dg-warning "invalid 'static_cast'" }
+}
+
+Base::~Base() {
+  static_cast<Derived *>(this); // { dg-warning "invalid 'static_cast'" }
+  (Derived *)this; // { dg-warning "invalid 'static_cast'" }
+}
+
+struct Other {
+  Other() {
+    Base b;
+    static_cast<Derived *>(&b);
+    (Derived *)(&b);
+  }
+};
-- 
2.25.1

Reply via email to