Thanks for the review. I've tested and uploaded a new patch v2 with
the requested changes.

On Thu, 17 Mar 2022 at 09:20, Jason Merrill <ja...@redhat.com> wrote:
>
> On 3/14/22 02:36, Zhao Wei Liew via Gcc-patches wrote:
>
> > 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.
>
> It's generally best to add a new warning flag if an existing one isn't a
> good match.  Maybe -Wderived-cast-undefined?  It seems like it could be
> part of -Wall.

Hmm, I agree. I've added a new -Wderived-cast-undefined flag for this.

> > +      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)))
>
> I think the resolves_to_fixed_type_p function would be useful here;
> you're testing for a subset of the cases it handles.

Does the new patch look like how you intended it to? The new patch
passes all regression tests and newly added tests. However, I don't
fully understand the code for resolves_to_fixed_type_p() and
fixed_type_or_null(), except that I see that they contain logic to
return -1 when within a ctor/dtor.

Thanks!
From a8bbd4158f3311372b67d32816ce40d5613ae0d8 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 Base* 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/c-family/ChangeLog:

        * c.opt (-Wderived-cast-undefined): New option.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

        * g++.dg/warn/Wderived-cast-undefined.C: New test.
---
 gcc/c-family/c.opt                            |  4 +++
 gcc/cp/typeck.cc                              |  6 ++++
 .../g++.dg/warn/Wderived-cast-undefined.C     | 33 +++++++++++++++++++
 3 files changed, 43 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/warn/Wderived-cast-undefined.C

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 9cfd2a6bc4e..1681395c529 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -598,6 +598,10 @@ C++ ObjC++ Var(warn_deprecated_enum_float_conv) Warning
 Warn about deprecated arithmetic conversions on operands where one is of 
enumeration
 type and the other is of a floating-point type.
 
+Wderived-cast-undefined
+C++ Var(warn_derived_cast_undefined) Warning LangEnabledBy(C++, Wall)
+Warn about undefined casts from Base* to Derived* in the Base constructor or 
destructor.
+
 Wdesignated-init
 C ObjC Var(warn_designated_init) Init(1) Warning
 Warn about positional initialization of structs requiring designated 
initializers.
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 516fa574ef6..0bbbc378806 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -8079,6 +8079,12 @@ build_static_cast_1 (location_t loc, tree type, tree 
expr, bool c_cast_p,
     {
       tree base;
 
+      if (TREE_CODE (expr) == NOP_EXPR
+          && resolves_to_fixed_type_p (TREE_OPERAND (expr, 0)) == -1)
+        warning_at (loc, OPT_Wderived_cast_undefined,
+                   "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/Wderived-cast-undefined.C 
b/gcc/testsuite/g++.dg/warn/Wderived-cast-undefined.C
new file mode 100644
index 00000000000..ea7388514dc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wderived-cast-undefined.C
@@ -0,0 +1,33 @@
+// PR c++/96765
+// { dg-options "-Wderived-cast-undefined" }
+
+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