c++: Consider addresses of heap artificial vars always non-NULL [PR98988, PR99031]

With -fno-delete-null-pointer-checks which is e.g. implied by
-fsanitize=undefined or default on some embedded targets, the middle-end
folder doesn't consider addresses of global VAR_DECLs to be non-NULL, as one
of them could have address 0.  Still, I think malloc/operator new (at least
the nonthrowing) relies on NULL returns meaning allocation failure rather
than success.  Furthermore, the artificial VAR_DECLs we create for
constexpr new never actually live in the address space of the program,
so we can pretend they will never be NULL too.

> I'm surprised that nonzero_address has such a limited set of things it will
> actually believe have non-zero addresses with
> -fno-delete-null-pointer-checks.  But it seems that we should be able to
> arrange to satisfy
>
> >   if (definition && !DECL_EXTERNAL (decl)
>
> since these "variables" are indeed defined within the current translation
> unit.

Doing that seems to work and as added benefit it fixes another PR that has
been filed recently.  I need to create the varpool node explicitly and call
a method that sets the definition member in there, but I can also unregister
those varpool nodes at the end of constexpr processing, as the processing
ensured they don't leak outside of the processing.

2021-02-10  Jakub Jelinek  <jakub@redhat.com>

	PR c++/98988
	PR c++/99031
	* constexpr.c: Include cgraph.h.
	(cxx_eval_call_expression): Call varpool_node::finalize_decl on
	heap artificial vars.
	(cxx_eval_outermost_constant_expr): Remove varpool nodes for
	heap artificial vars.

	* g++.dg/cpp2a/constexpr-new16.C: New test.
	* g++.dg/cpp2a/constexpr-new17.C: New test.
This commit is contained in:
Jakub Jelinek 2021-02-10 19:31:15 +01:00
parent 5874d15666
commit a8db7887df
3 changed files with 48 additions and 9 deletions

View File

@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "fold-const-call.h"
#include "stor-layout.h"
#include "cgraph.h"
static bool verify_constant (tree, bool, bool *, bool *);
#define VERIFY_CONSTANT(X) \
@ -2340,6 +2341,13 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
type);
DECL_ARTIFICIAL (var) = 1;
TREE_STATIC (var) = 1;
// Temporarily register the artificial var in varpool,
// so that comparisons of its address against NULL are folded
// through nonzero_address even with
// -fno-delete-null-pointer-checks or that comparison of
// addresses of different heap artificial vars is folded too.
// See PR98988 and PR99031.
varpool_node::finalize_decl (var);
ctx->global->heap_vars.safe_push (var);
ctx->global->values.put (var, NULL_TREE);
return fold_convert (ptr_type_node, build_address (var));
@ -7199,15 +7207,18 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
non_constant_p = true;
}
FOR_EACH_VEC_ELT (global_ctx.heap_vars, i, heap_var)
if (DECL_NAME (heap_var) != heap_deleted_identifier)
{
if (!allow_non_constant && !non_constant_p)
error_at (DECL_SOURCE_LOCATION (heap_var),
"%qE is not a constant expression because allocated "
"storage has not been deallocated", t);
r = t;
non_constant_p = true;
}
{
if (DECL_NAME (heap_var) != heap_deleted_identifier)
{
if (!allow_non_constant && !non_constant_p)
error_at (DECL_SOURCE_LOCATION (heap_var),
"%qE is not a constant expression because allocated "
"storage has not been deallocated", t);
r = t;
non_constant_p = true;
}
varpool_node::get (heap_var)->remove ();
}
}
/* Check that immediate invocation does not return an expression referencing

View File

@ -0,0 +1,13 @@
// PR c++/98988
// { dg-do compile { target c++20 } }
// { dg-options "-fno-delete-null-pointer-checks" }
constexpr bool
foo ()
{
auto ptr = new int();
delete ptr;
return true;
}
static_assert (foo ());

View File

@ -0,0 +1,15 @@
// PR c++/99031
// { dg-do compile { target c++20 } }
constexpr bool
foo ()
{
auto a = new int;
auto b = new int;
bool r = a == b;
delete b;
delete a;
return r;
}
static_assert (!foo ());