[RFC] c++/96765: warn when casting Base* to Derived* in Base ctor/dtor
Commit Message
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 <zhaoweiliew@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 <zhaoweiliew@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
@@ -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;
new file mode 100644
@@ -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);
+ }
+};