Hi! This patch aims to add a warning when casting "this" in a base class constructor to a derived class type. It works on the test cases provided, but I'm still running regression tests.
However, I have a few doubts: 1. Am I missing out any cases? Right now, I'm identifying the casts by checking that TREE_CODE (expr) == NOP_EXPR && is_this_parameter (TREE_OPERAND (expr, 0)). It seems fine to me but perhaps there is a function that I can use to express this more concisely? 2. -Wcast-qual doesn't seem to be the right flag for this warning. However, I can't seem to find an appropriate flag. Maybe I should place it under -Wextra or -Wall? Appreciate any feedback on the aforementioned doubts or otherwise. Thanks, and have a great day!
From 8a1f352f3db06faf264bc823387714a4a9e638b6 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 on Base* to Derived* cast 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 Base * to Derived * in Base constructor and destructor. gcc/testsuite/ChangeLog: * g++.dg/warn/Wcast-qual3.C: New test. --- gcc/cp/typeck.cc | 8 ++++++ gcc/testsuite/g++.dg/warn/Wcast-qual3.C | 33 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 gcc/testsuite/g++.dg/warn/Wcast-qual3.C diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index f796337f73c..bbc40b25547 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -8080,6 +8080,14 @@ build_static_cast_1 (location_t loc, tree type, tree expr, bool c_cast_p, { tree base; + if ((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_Wcast_qual, + "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/Wcast-qual3.C b/gcc/testsuite/g++.dg/warn/Wcast-qual3.C new file mode 100644 index 00000000000..8c44a23bd68 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wcast-qual3.C @@ -0,0 +1,33 @@ +// PR c++/96765 +// { dg-options "-Wcast-qual" } + +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.35.1