Re: [PATCH] c++: Fix wrong error with constexpr destructor [PR97427]

2020-11-20 Thread Jason Merrill via Gcc-patches

On 11/19/20 8:21 PM, Marek Polacek wrote:

When I implemented the code to detect modifying const objects in
constexpr contexts, we couldn't have constexpr destructors, so I didn't
consider them.  But now we can and that caused a bogus error in this
testcase: [class.dtor]p5 says that "const and volatile semantics are not
applied on an object under destruction.  They stop being in effect when
the destructor for the most derived object starts." so we have to clear
the TREE_READONLY flag we set on the object after the constructors have
been called to mark it as no-longer-under-construction.  In the ~Foo
call it's now an object under destruction, so don't report those errors.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10?


OK.


gcc/cp/ChangeLog:

PR c++/97427
* constexpr.c (cxx_set_object_constness): New function.
(cxx_eval_call_expression): Set new_obj for destructors too.
Call cxx_set_object_constness to set/unset TREE_READONLY of
the object under construction/destruction.

gcc/testsuite/ChangeLog:

PR c++/97427
* g++.dg/cpp2a/constexpr-dtor10.C: New test.
---
  gcc/cp/constexpr.c| 49 +--
  gcc/testsuite/g++.dg/cpp2a/constexpr-dtor10.C | 16 ++
  2 files changed, 49 insertions(+), 16 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-dtor10.C

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 625410327b8..ef37b3043a5 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -2187,6 +2187,27 @@ cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, 
tree thunk_fndecl,
   non_constant_p, overflow_p);
  }
  
+/* If OBJECT is of const class type, evaluate it to a CONSTRUCTOR and set

+   its TREE_READONLY flag according to READONLY_P.  Used for constexpr
+   'tors to detect modifying const objects in a constexpr context.  */
+
+static void
+cxx_set_object_constness (const constexpr_ctx *ctx, tree object,
+ bool readonly_p, bool *non_constant_p,
+ bool *overflow_p)
+{
+  if (CLASS_TYPE_P (TREE_TYPE (object))
+  && CP_TYPE_CONST_P (TREE_TYPE (object)))
+{
+  /* Subobjects might not be stored in ctx->global->values but we
+can get its CONSTRUCTOR by evaluating *this.  */
+  tree e = cxx_eval_constant_expression (ctx, object, /*lval*/false,
+non_constant_p, overflow_p);
+  if (TREE_CODE (e) == CONSTRUCTOR && !*non_constant_p)
+   TREE_READONLY (e) = readonly_p;
+}
+}
+
  /* Subroutine of cxx_eval_constant_expression.
 Evaluate the call expression tree T in the context of OLD_CALL expression
 evaluation.  */
@@ -2515,11 +2536,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, 
tree t,
  
depth_ok = push_cx_call_context (t);
  
-  /* Remember the object we are constructing.  */

+  /* Remember the object we are constructing or destructing.  */
tree new_obj = NULL_TREE;
-  if (DECL_CONSTRUCTOR_P (fun))
+  if (DECL_CONSTRUCTOR_P (fun) || DECL_DESTRUCTOR_P (fun))
  {
-  /* In a constructor, it should be the first `this' argument.
+  /* In a cdtor, it should be the first `this' argument.
 At this point it has already been evaluated in the call
 to cxx_bind_parameters_in_call.  */
new_obj = TREE_VEC_ELT (new_call.bindings, 0);
@@ -2656,6 +2677,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree 
t,
  unsigned save_heap_alloc_count = ctx->global->heap_vars.length ();
  unsigned save_heap_dealloc_count = ctx->global->heap_dealloc_count;
  
+	  /* If this is a constexpr destructor, the object's const and volatile

+semantics are no longer in effect; see [class.dtor]p5.  */
+ if (new_obj && DECL_DESTRUCTOR_P (fun))
+   cxx_set_object_constness (ctx, new_obj, /*readonly_p=*/false,
+ non_constant_p, overflow_p);
+
  tree jump_target = NULL_TREE;
  cxx_eval_constant_expression (_with_save_exprs, body,
lval, non_constant_p, overflow_p,
@@ -2686,19 +2713,9 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree 
t,
 the object is no longer under construction, and its possible
 'const' semantics now apply.  Make a note of this fact by
 marking the CONSTRUCTOR TREE_READONLY.  */
- if (new_obj
- && CLASS_TYPE_P (TREE_TYPE (new_obj))
- && CP_TYPE_CONST_P (TREE_TYPE (new_obj)))
-   {
- /* Subobjects might not be stored in ctx->global->values but we
-can get its CONSTRUCTOR by evaluating *this.  */
- tree e = cxx_eval_constant_expression (ctx, new_obj,
-/*lval*/false,
-non_constant_p,
-  

[PATCH] c++: Fix wrong error with constexpr destructor [PR97427]

2020-11-19 Thread Marek Polacek via Gcc-patches
When I implemented the code to detect modifying const objects in
constexpr contexts, we couldn't have constexpr destructors, so I didn't
consider them.  But now we can and that caused a bogus error in this
testcase: [class.dtor]p5 says that "const and volatile semantics are not
applied on an object under destruction.  They stop being in effect when
the destructor for the most derived object starts." so we have to clear
the TREE_READONLY flag we set on the object after the constructors have
been called to mark it as no-longer-under-construction.  In the ~Foo
call it's now an object under destruction, so don't report those errors.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10?

gcc/cp/ChangeLog:

PR c++/97427
* constexpr.c (cxx_set_object_constness): New function.
(cxx_eval_call_expression): Set new_obj for destructors too.
Call cxx_set_object_constness to set/unset TREE_READONLY of
the object under construction/destruction.

gcc/testsuite/ChangeLog:

PR c++/97427
* g++.dg/cpp2a/constexpr-dtor10.C: New test.
---
 gcc/cp/constexpr.c| 49 +--
 gcc/testsuite/g++.dg/cpp2a/constexpr-dtor10.C | 16 ++
 2 files changed, 49 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-dtor10.C

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 625410327b8..ef37b3043a5 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -2187,6 +2187,27 @@ cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, 
tree thunk_fndecl,
   non_constant_p, overflow_p);
 }
 
+/* If OBJECT is of const class type, evaluate it to a CONSTRUCTOR and set
+   its TREE_READONLY flag according to READONLY_P.  Used for constexpr
+   'tors to detect modifying const objects in a constexpr context.  */
+
+static void
+cxx_set_object_constness (const constexpr_ctx *ctx, tree object,
+ bool readonly_p, bool *non_constant_p,
+ bool *overflow_p)
+{
+  if (CLASS_TYPE_P (TREE_TYPE (object))
+  && CP_TYPE_CONST_P (TREE_TYPE (object)))
+{
+  /* Subobjects might not be stored in ctx->global->values but we
+can get its CONSTRUCTOR by evaluating *this.  */
+  tree e = cxx_eval_constant_expression (ctx, object, /*lval*/false,
+non_constant_p, overflow_p);
+  if (TREE_CODE (e) == CONSTRUCTOR && !*non_constant_p)
+   TREE_READONLY (e) = readonly_p;
+}
+}
+
 /* Subroutine of cxx_eval_constant_expression.
Evaluate the call expression tree T in the context of OLD_CALL expression
evaluation.  */
@@ -2515,11 +2536,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, 
tree t,
 
   depth_ok = push_cx_call_context (t);
 
-  /* Remember the object we are constructing.  */
+  /* Remember the object we are constructing or destructing.  */
   tree new_obj = NULL_TREE;
-  if (DECL_CONSTRUCTOR_P (fun))
+  if (DECL_CONSTRUCTOR_P (fun) || DECL_DESTRUCTOR_P (fun))
 {
-  /* In a constructor, it should be the first `this' argument.
+  /* In a cdtor, it should be the first `this' argument.
 At this point it has already been evaluated in the call
 to cxx_bind_parameters_in_call.  */
   new_obj = TREE_VEC_ELT (new_call.bindings, 0);
@@ -2656,6 +2677,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree 
t,
  unsigned save_heap_alloc_count = ctx->global->heap_vars.length ();
  unsigned save_heap_dealloc_count = ctx->global->heap_dealloc_count;
 
+ /* If this is a constexpr destructor, the object's const and volatile
+semantics are no longer in effect; see [class.dtor]p5.  */
+ if (new_obj && DECL_DESTRUCTOR_P (fun))
+   cxx_set_object_constness (ctx, new_obj, /*readonly_p=*/false,
+ non_constant_p, overflow_p);
+
  tree jump_target = NULL_TREE;
  cxx_eval_constant_expression (_with_save_exprs, body,
lval, non_constant_p, overflow_p,
@@ -2686,19 +2713,9 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree 
t,
 the object is no longer under construction, and its possible
 'const' semantics now apply.  Make a note of this fact by
 marking the CONSTRUCTOR TREE_READONLY.  */
- if (new_obj
- && CLASS_TYPE_P (TREE_TYPE (new_obj))
- && CP_TYPE_CONST_P (TREE_TYPE (new_obj)))
-   {
- /* Subobjects might not be stored in ctx->global->values but we
-can get its CONSTRUCTOR by evaluating *this.  */
- tree e = cxx_eval_constant_expression (ctx, new_obj,
-/*lval*/false,
-non_constant_p,
-overflow_p);
- if