[Bug c++/91369] Implement P0784R7: constexpr new

2020-01-09 Thread lutztonineubert at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #34 from Toni Neubert  ---
Thank you both! Now everything works. :)

I'll keep that in mind.

[Bug c++/91369] Implement P0784R7: constexpr new

2020-01-08 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

Jakub Jelinek  changed:

   What|Removed |Added

 Status|REOPENED|RESOLVED
 Resolution|--- |FIXED

--- Comment #33 from Jakub Jelinek  ---
Should be fixed now.
If you have further issues, can you please file new bugreports instead of
reopening the same?  Thanks.

[Bug c++/91369] Implement P0784R7: constexpr new

2020-01-08 Thread jason at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #32 from Jason Merrill  ---
Author: jason
Date: Wed Jan  8 20:31:20 2020
New Revision: 280018

URL: https://gcc.gnu.org/viewcvs?rev=280018=gcc=rev
Log:
PR c++/91369 - constexpr destructor and member initializer.

Previously it didn't matter whether we looked through a TARGET_EXPR in
constexpr evaluation, but now that we have constexpr destructors it does.
On IRC I mentioned the idea of clearing TARGET_EXPR_CLEANUP in
digest_nsdmi_init, but since this initialization is expressed by an
INIT_EXPR, it's better to handle all INIT_EXPR, not just those for a member
initializer.

* constexpr.c (cxx_eval_store_expression): Look through TARGET_EXPR
when not preevaluating.

Added:
trunk/gcc/testsuite/g++.dg/cpp2a/constexpr-new10.C
Modified:
trunk/gcc/cp/ChangeLog
trunk/gcc/cp/constexpr.c

[Bug c++/91369] Implement P0784R7: constexpr new

2020-01-08 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

Jakub Jelinek  changed:

   What|Removed |Added

   Assignee|unassigned at gcc dot gnu.org  |jason at gcc dot gnu.org

--- Comment #31 from Jakub Jelinek  ---
Jason said this could be fixed by clearing TARGET_EXPR_CLEANUPS in
digest_nsdmi_init.

[Bug c++/91369] Implement P0784R7: constexpr new

2020-01-08 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #30 from Jakub Jelinek  ---
(In reply to Toni Neubert from comment #28)
> I have another test case which fails. (Maybe more..., I am sorry).

No need to be sorry, your input is very valuable.
Anyway, for the #c28 testcase (using
struct S {
  constexpr S (int* i) : s{i} {}
  constexpr ~S () { delete s; }
  int *s;
};

struct T { S t { new int }; };

constexpr auto
foo ()
{
  T b;
  return true;
}

static_assert (foo ());
variant of it), not really sure if it is a compiler bug or testcase bug, the S
class has defaulted copy ctor, so if it is ever copy constructed, there will be
UB because you try to delete the same pointer multiple times.
What I see happening is that in the T::T synthetized ctor, we have:
  >
  (int *) operator new (4) ) >;
and the TARGET_EXPR has as cleanup S::~S ().  So, when the constexpr
evaluation evaluates this, it constructs the D.2161 temporary and queues a
cleanup S::~S () until the CLEANUP_POINT_EXPR cleanup processing, then
copies the value to the t member and when T::~T () is invoked during constexpr
processing, S::~S (this->t) is invoked and that is the reason for the error,
delete is called on the same pointer twice.

Now, the reason why this doesn't fail when the foo function is invoked at
runtime rather than at compile time is that cp_gimplify_init_expr has code
to look through TARGET_EXPRs on the rhs of INIT_EXPR if their
TARGET_EXPR_INITIAL is AGGR_INIT_EXPR/VEC_INIT_EXPR or COMPOUND_EXPR with those
on the rightmost operand.
The question is if what cp_gimplify_init_expr is just an optimization (then the
testcase would be invalid), or if it is a mandatory C++ behavior, in that case
I think cxx_eval_store_expression (if INIT_EXPR rather than MODIFY_EXPR) needs
to detect this case and not sure if it can just look through the TARGET_EXPR
(i.e. essentially ignore the cleanup), or if it needs to turn the whole
INIT_EXPR into AGGR_INIT_EXPR or VEC_INIT_EXPR with different slot.

[Bug c++/91369] Implement P0784R7: constexpr new

2020-01-06 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #29 from Jakub Jelinek  ---
Author: jakub
Date: Tue Jan  7 07:13:50 2020
New Revision: 279943

URL: https://gcc.gnu.org/viewcvs?rev=279943=gcc=rev
Log:
PR c++/91369
* constexpr.c (struct constexpr_global_ctx): Add heap_alloc_count
member, initialize it to zero in ctor.
(cxx_eval_call_expression): Bump heap_dealloc_count when deleting
a heap object.  Don't cache calls to functions which allocate some
heap objects and don't deallocate them or deallocate some heap
objects they didn't allocate.

* g++.dg/cpp1y/constexpr-new.C: Expect an error explaining why
static_assert failed for C++2a.
* g++.dg/cpp2a/constexpr-new9.C: New test.

Added:
trunk/gcc/testsuite/g++.dg/cpp2a/constexpr-new9.C
Modified:
trunk/gcc/cp/ChangeLog
trunk/gcc/cp/constexpr.c
trunk/gcc/testsuite/ChangeLog
trunk/gcc/testsuite/g++.dg/cpp1y/constexpr-new.C

[Bug c++/91369] Implement P0784R7: constexpr new

2020-01-06 Thread lutztonineubert at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #28 from Toni Neubert  ---
Thank you very much again for your fast help. Your patch works for this test
case.

I have another test case which fails. (Maybe more..., I am sorry).

//main.cpp: in ‘constexpr’ expansion of ‘test3()’
//main.cpp: in ‘constexpr’ expansion of ‘(& b)->bar::~bar()’
//main.cpp: in ‘constexpr’ expansion of ‘(&((bar*)this)->bar::f)->foo::~foo()’
//main.cpp  error: deallocation of already deallocated storage
struct foo {
constexpr foo(int* i) : ptr{i} {}

constexpr ~foo() {
delete ptr;
}

int* ptr;
};

struct bar {
foo f{new int};
};

constexpr auto test3() {
bar b;
return true;
}

static_assert(test3());

[Bug c++/91369] Implement P0784R7: constexpr new

2020-01-04 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #27 from Jakub Jelinek  ---
Created attachment 47590
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=47590=edit
gcc10-pr91369-2.patch

Untested patch.

[Bug c++/91369] Implement P0784R7: constexpr new

2020-01-04 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

Jakub Jelinek  changed:

   What|Removed |Added

 Status|RESOLVED|REOPENED
 Resolution|FIXED   |---

--- Comment #26 from Jakub Jelinek  ---
The problem is the constexpr call cache we have, disabling it altogether like:
--- gcc/cp/constexpr.c  2020-01-04 11:19:50.585697766 +0100
+++ gcc/cp/constexpr.c  2020-01-04 11:18:42.0 +0100
@@ -2426,7 +2426,7 @@ cxx_eval_call_expression (const constexp
   else if (!result)
result = void_node;
   if (entry)
-   entry->result = result;
+   entry->result = /*result*/error_mark_node;
 }

   /* The result of a constexpr function must be completely initialized.
fixes it.
Before the introduction of constexpr new/delete it was just fine to cache calls
that way, a constexpr call of the same constexpr function with the same
constant arguments with the same state of manifestly constant evaluation could
be reused.
I'm afraid that is no longer the case with constexpr new/delete, so I think we
need to avoid the caching if the call allocates something and doesn't
deallocate it before returning, or if it deallocates something it hasn't
allocated, because the call in that case isn't really stateless for the
constexpr evaluation.
Checking for the former could be easy, remember before the call how the length
of ctx->global->heap_vars and after the call, for any newly added elts verify
if they were all deallocated.  To detect the deallocation without allocation
inside of the call we could perhaps add a counter for the deallocations and
compare that counter to the number of the allocations.

[Bug c++/91369] Implement P0784R7: constexpr new

2020-01-03 Thread lutztonineubert at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #25 from Toni Neubert  ---
I get: "deallocation of already deallocated storage" for test2() but compiling
just test1() or test2() is just fine.


struct a {
constexpr a(int* i) : i{i} {
}
constexpr ~a() {
delete[] i;
}
int* i;
};

constexpr a make_a(int size) {
return {new int[size]()};
}

constexpr bool test1() {
make_a(1);
return true;
}

constexpr bool test2() {
make_a(1);
return true;
}

static_assert(test1());
static_assert(test2());

[Bug c++/91369] Implement P0784R7: constexpr new

2019-12-04 Thread lutztonineubert at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #24 from Toni Neubert  ---
Great thank you.

[Bug c++/91369] Implement P0784R7: constexpr new

2019-12-03 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

Jakub Jelinek  changed:

   What|Removed |Added

 Status|REOPENED|RESOLVED
 Resolution|--- |FIXED

--- Comment #23 from Jakub Jelinek  ---
Should be fixed now.

[Bug c++/91369] Implement P0784R7: constexpr new

2019-12-03 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #22 from Jakub Jelinek  ---
Author: jakub
Date: Tue Dec  3 19:27:47 2019
New Revision: 278945

URL: https://gcc.gnu.org/viewcvs?rev=278945=gcc=rev
Log:
PR c++/91369
* constexpr.c (struct constexpr_global_ctx): Add cleanups member,
initialize it in the ctor.
(cxx_eval_constant_expression) : If TARGET_EXPR_SLOT
is already in the values hash_map, don't evaluate it again.  Put
TARGET_EXPR_SLOT into hash_map even if not lval, and push it into
save_exprs too.  If there is TARGET_EXPR_CLEANUP and not
CLEANUP_EH_ONLY, push the cleanup to cleanups vector.
: Save outer cleanups, set cleanups to
local auto_vec, after evaluating the body evaluate cleanups and
restore previous cleanups.
: Don't crash if the first operand is NULL_TREE.
(cxx_eval_outermost_constant_expr): Set cleanups to local auto_vec,
after evaluating the expression evaluate cleanups.

* g++.dg/cpp2a/constexpr-new8.C: New test.

Added:
trunk/gcc/testsuite/g++.dg/cpp2a/constexpr-new8.C
Modified:
trunk/gcc/cp/ChangeLog
trunk/gcc/cp/constexpr.c
trunk/gcc/testsuite/ChangeLog

[Bug c++/91369] Implement P0784R7: constexpr new

2019-12-01 Thread lutztonineubert at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

Toni Neubert  changed:

   What|Removed |Added

 CC||lutztonineubert at gmail dot 
com

--- Comment #21 from Toni Neubert  ---
I get: 'allocated storage has not been deallocated' when using
prvalues/xvalues:

struct A {
constexpr A() : p{new int} {}
constexpr ~A() {
delete p;
}
int* p;
};

constexpr bool test() {
A{};
return true;
}

constexpr auto res = test();
static_assert(res);

[Bug c++/91369] Implement P0784R7: constexpr new

2019-11-01 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #20 from Jakub Jelinek  ---
Author: jakub
Date: Fri Nov  1 23:26:17 2019
New Revision: 277732

URL: https://gcc.gnu.org/viewcvs?rev=277732=gcc=rev
Log:
PR c++/91369 - Implement P0784R7: constexpr new
* cp-tree.h (CALL_FROM_NEW_OR_DELETE_P): Define.
* init.c (build_new_1, build_vec_delete_1, build_delete): Set
CALL_FROM_NEW_OR_DELETE_P on the CALL_EXPR to allocator functions.
* constexpr.c (is_std_allocator_allocate): Only allow
global replaceable allocator functions if CALL_FROM_NEW_OR_DELETE_P
or in std::allocate::{,de}allocate.
(potential_constant_expression_1): Likewise.

* g++.dg/cpp2a/constexpr-new6.C: New test.
* g++.dg/cpp2a/constexpr-new7.C: New test.

Added:
trunk/gcc/testsuite/g++.dg/cpp2a/constexpr-new6.C
trunk/gcc/testsuite/g++.dg/cpp2a/constexpr-new7.C
Modified:
trunk/gcc/cp/ChangeLog
trunk/gcc/cp/constexpr.c
trunk/gcc/cp/cp-tree.h
trunk/gcc/cp/init.c
trunk/gcc/testsuite/ChangeLog

[Bug c++/91369] Implement P0784R7: constexpr new

2019-10-30 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #19 from Jakub Jelinek  ---
Author: jakub
Date: Wed Oct 30 21:55:12 2019
New Revision: 277649

URL: https://gcc.gnu.org/viewcvs?rev=277649=gcc=rev
Log:
PR c++/91369 - Implement P0784R7: constexpr new
* constexpr.c (cxx_replaceable_global_alloc_fn): Don't return true
for placement new.
(cxx_placement_new_fn, is_std_construct_at): New functions.
(cxx_eval_call_expression): Allow placement new in std::construct_at.
(potential_constant_expression_1): Likewise.

* g++.dg/cpp2a/constexpr-new5.C: New test.

Added:
trunk/gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C
Modified:
trunk/gcc/cp/ChangeLog
trunk/gcc/cp/constexpr.c
trunk/gcc/testsuite/ChangeLog

[Bug c++/91369] Implement P0784R7: constexpr new

2019-10-23 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #18 from Jonathan Wakely  ---
Author: redi
Date: Wed Oct 23 17:42:11 2019
New Revision: 277342

URL: https://gcc.gnu.org/viewcvs?rev=277342=gcc=rev
Log:
PR c++/91369 Implement P0784R7 changes to allocation and construction

This patch is the first part of library support for constexpr
std::vector and std::string. This only includes the changes to
std::allocator, std::allocator_traits, std::construct_at,
std::destroy_at, std::destroy and std::destroy_n.

std::allocator::allocate and std::allocator::deallocate need to be
added so that they can be intercepted by the compiler during constant
evaluation. Outside of constant evaluation those new member functions
just forward to the existing implementation in the base class.

PR c++/91369 Implement P0784R7 changes to allocation and construction
* include/bits/alloc_traits.h: Include .
(allocator_traits::_S_allocate, allocator_traits::_S_construct)
(allocator_traits::_S_destroy, allocator_traits::_S_max_size)
(allocator_traits::_S_select, allocator_traits::allocate)
(allocator_traits::deallocate, allocator_traits::construct)
(allocator_traits::destroy, allocator_traits::max_size)
(allocator_traits::select_on_container_copy_construction)
(allocator_traits>): Add constexpr specifier for C++20.
(allocator_traits>::construct): Use construct_at.
(allocator_traits>::destroy): Use destroy_at.
(__alloc_on_copy, __alloc_on_move, __alloc_on_swap): Add constexpr
specifier.
(_Destroy(ForwardIterator, ForwardIterator, Alloc&))
(_Destroy(ForwardIterator, ForwardIterator, allocator&)): Move here
from .
* include/bits/allocator.h (allocator::~allocator): Remove for C++20.
(allocator::allocate, allocate::deallocate): Define for C++20 and up.
(operator==, operator!=): Add constexpr specifier for C++20.
* include/bits/stl_construct.h: Don't include .
(destroy_at): For C++20 add constexpr specifier and support for
destroying arrays.
(construct_at): Define new function for C++20.
(_Construct): Return result of placement new-expression. For C++11 and
up add constexpr. For C++20 dispatch to std::construct_at during
constant evaluation.
(_Destroy(pointer)): Add constexpr specifier. For C++20 dispatch to
std::destroy_at during constant evaluation.
(_Destroy_aux::__destroy, _Destroy_n_aux::__destroy_n): Add constexpr
specifier for C++20.
(_Destroy(ForwardIterator, ForwardIterator))
(_Destroy(ForwardIterator, Size)): Likewise. Do not elide trivial
destructors during constant evaluation.
(destroy, destroy_n): Add constexpr specifier for C++20.
(_Destroy(ForwardIterator, ForwardIterator, Alloc&))
(_Destroy(ForwardIterator, ForwardIterator, allocator&)): Move to
, to remove dependency on allocators.
* include/bits/stl_uninitialized.h: Include .
Include  instead of .
* include/ext/alloc_traits.h: Always include .
(__alloc_traits::construct, __alloc_traits::destroy)
(__alloc_traits::_S_select_on_copy, __alloc_traits::_S_on_swap): Add
constexpr specifier.
* include/ext/malloc_allocator.h  (operator==, operator!=): Add
constexpr specifier for C++20.
* include/ext/new_allocator.h (operator==, operator!=): Likewise.
* testsuite/20_util/headers/memory/synopsis.cc: Add constexpr.
* testsuite/20_util/scoped_allocator/69293_neg.cc: Ignore additional
errors due to constexpr function called after failed static_assert.
* testsuite/20_util/specialized_algorithms/construct_at/1.cc: New test.
* testsuite/23_containers/vector/cons/destructible_debug_neg.cc:
Ignore additional errors due to constexpr function called after failed
static_assert.
* testsuite/23_containers/vector/cons/destructible_neg.cc: Likewise.

Added:
trunk/libstdc++-v3/testsuite/20_util/specialized_algorithms/construct_at/
   
trunk/libstdc++-v3/testsuite/20_util/specialized_algorithms/construct_at/1.cc
Modified:
trunk/libstdc++-v3/ChangeLog
trunk/libstdc++-v3/include/bits/alloc_traits.h
trunk/libstdc++-v3/include/bits/allocator.h
trunk/libstdc++-v3/include/bits/stl_construct.h
trunk/libstdc++-v3/include/bits/stl_uninitialized.h
trunk/libstdc++-v3/include/ext/alloc_traits.h
trunk/libstdc++-v3/include/ext/malloc_allocator.h
trunk/libstdc++-v3/include/ext/new_allocator.h
trunk/libstdc++-v3/testsuite/20_util/headers/memory/synopsis.cc
trunk/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc
   
trunk/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
trunk/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc

[Bug c++/91369] Implement P0784R7: constexpr new

2019-10-17 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #17 from Jakub Jelinek  ---
Ok, so do I need to somehow mark the CALL_EXPR created from new/delete lowering
and only treat calls to global replaceable allocator/deallocator functions
specially if they either have this flag or are in allocate//deallocate method
of std::allocator template?  And similarly perhaps do something for the
placement new in std::construct_at etc.?

[Bug c++/91369] Implement P0784R7: constexpr new

2019-10-16 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #16 from Jonathan Wakely  ---
I'll commit a patch to add std::construct_at today or tomorrow.

[Bug c++/91369] Implement P0784R7: constexpr new

2019-10-16 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #15 from Jonathan Wakely  ---
That's not valid, because operator new is not a constexpr function.

You have to use a new-expression (that resolves to one of the standard operator
new allocation functions), or std::allocator::allocate, or
std::allocator_traits>::allocate.

The result of std::allocator::allocate can't be dereferenced until you've
constructed an object there (and attempting to do so in a constexpr function
should be ill-formed).

This should work:

constexpr int
bar ()
{
  auto a = new int; // obtain storage for an int and begin its lifetime
  *a = 1;
  *a = *a + 2;
  int r = *a;
  delete a; // end lifetime and release storage
  return r;
}

constexpr auto p = bar ();

And this:

constexpr int
baz ()
{
  auto a = std::allocator::allocate(1); // obtain storage for an int
  std::construct_at(a);  // begin lifetime of an int
  *a = 1;
  *a = *a + 2;
  int r = *a;
  std::destroy_at(a);// end lifetime
  std::allocator::deallocate(a, 1); // release storage
  return r;
}

constexpr auto q = baz ();

And the equivalent using std::allocator_traits:

constexpr int
baz2 ()
{
  std::allocator alloc;
  using A = std::allocator_traits>;
  auto a = A::allocate(alloc, 1);// obtain storage for an int
  A::construct(a);   // calls std::construct_at
  *a = 1;
  *a = *a + 2;
  int r = *a;
  A::destroy(alloc, a);  // calls std::destroy_at
  A::deallocate(alloc, a, 1);// release storage
  return r;
}

constexpr auto q = baz2 ();

[Bug c++/91369] Implement P0784R7: constexpr new

2019-10-16 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #14 from Jakub Jelinek  ---
Another question is whether:
constexpr int
bar ()
{
  auto a = static_cast (::operator new (sizeof (int)));
  *a = 1;
  *a = *a + 2;
  int r = *a;
  ::operator delete (a);
  return r;
}

constexpr auto p = bar ();

is valid or not (i.e. when there is no placement new at all, just static_cast
and dereferencing of the pointer.  Or if it is required to use
std::allocator::allocate for that, and in that case, does one need to use
placement new or can it be dereferenced without it?

[Bug c++/91369] Implement P0784R7: constexpr new

2019-10-15 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #13 from Jonathan Wakely  ---
(In reply to Jakub Jelinek from comment #12)
> Well, not fully.  The paper has additions of constexpr keywords on the
> library side, but more importantly, we'll probably need some hacks in the
> compiler for the library side, but waiting for Jonathan with that.

Yes, I have the library parts coded up but not committed.

> My understanding is that right now (perhaps that might change) placement new
> should not be treated as constexpr function, but it needs to be in certain
> STL templates (at least std::construct_at, something else?)

The way EDG does it is not to allow placement new in constant expressions, but
to intercept calls to std::construct_at and std::destroy_at and replace them
with equivalent code that does the construction/destruction.

If allowing the body of std::construct_at to be valid is easier, that's fine
too.


> Also, I was afraid that in std::allocator::allocate, the cast would be
> reinterpret_cast, but apparently it isn't:
> 
> template 
> constexpr T *
> foo ()
> {
>   return static_cast (::operator new (sizeof (T)));
> }
> 
> constexpr int
> bar ()
> {
>   auto a = foo  ();
>   ::operator delete (a);
>   return 0;
> }
> 
> constexpr auto p = bar ();
> 
> (this doesn't actually use placement new, because that does and should ATM
> fail).  So, maybe it is just the placement new that needs to be handled.
> But, if one can cast the global replaceable allocator function result to
> anything in constexpr and our implementation triggers on the cast rather
> than on some spot coming from the new operator, shouldn't we use some new
> C++ expression kind or say an internal function as an explicit cast in new
> expression (placement or not) rather than any cast of the pointer?

Again, instead of trying to allow whatever the body of std::allocator::allocate
does, EDG just intercepts call to std::allocator::allocate and replaces it
with something else that works for the constexpr case.

That means it doesn't matter what the body of std::allocator::allocate does,
and it doesn't matter whether operator new has been replaced by the program,
because that code is never evaluated in constant expressions.

> Note, clang++ rejects the above testcase with
> /tmp/6.C:16:16: error: constexpr variable 'p' must be initialized by a
> constant expression
> constexpr auto p = bar ();
>^   ~~
> /tmp/6.C:5:28: note: cannot allocate untyped memory in a constant
> expression; use 'std::allocator::allocate' to allocate memory of type 'T'
>   return static_cast (::operator new (sizeof (T)));
>^
> /tmp/6.C:11:12: note: in call to 'foo()'
>   auto a = foo  ();
>^
> /tmp/6.C:16:20: note: in call to 'bar()'
> constexpr auto p = bar ();
>^
> 1 error generated.
> 
> Is it correct or not?  The allocation function itself is not constexpr, on
> the other side the wording says that the allocations should be elided in
> constexpr contexts.

I don't think Clang implements this feature yet, so I'd expect it to fail.

[Bug c++/91369] Implement P0784R7: constexpr new

2019-10-15 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

Jakub Jelinek  changed:

   What|Removed |Added

 Status|RESOLVED|REOPENED
 Resolution|FIXED   |---

--- Comment #12 from Jakub Jelinek  ---
Well, not fully.  The paper has additions of constexpr keywords on the library
side, but more importantly, we'll probably need some hacks in the compiler for
the library side, but waiting for Jonathan with that.

My understanding is that right now (perhaps that might change) placement new
should not be treated as constexpr function, but it needs to be in certain STL
templates (at least std::construct_at, something else?)

Also, I was afraid that in std::allocator::allocate, the cast would be
reinterpret_cast, but apparently it isn't:

template 
constexpr T *
foo ()
{
  return static_cast (::operator new (sizeof (T)));
}

constexpr int
bar ()
{
  auto a = foo  ();
  ::operator delete (a);
  return 0;
}

constexpr auto p = bar ();

(this doesn't actually use placement new, because that does and should ATM
fail).  So, maybe it is just the placement new that needs to be handled.
But, if one can cast the global replaceable allocator function result to
anything in constexpr and our implementation triggers on the cast rather than
on some spot coming from the new operator, shouldn't we use some new C++
expression kind or say an internal function as an explicit cast in new
expression (placement or not) rather than any cast of the pointer?

Note, clang++ rejects the above testcase with
/tmp/6.C:16:16: error: constexpr variable 'p' must be initialized by a constant
expression
constexpr auto p = bar ();
   ^   ~~
/tmp/6.C:5:28: note: cannot allocate untyped memory in a constant expression;
use 'std::allocator::allocate' to allocate memory of type 'T'
  return static_cast (::operator new (sizeof (T)));
   ^
/tmp/6.C:11:12: note: in call to 'foo()'
  auto a = foo  ();
   ^
/tmp/6.C:16:20: note: in call to 'bar()'
constexpr auto p = bar ();
   ^
1 error generated.

Is it correct or not?  The allocation function itself is not constexpr, on the
other side the wording says that the allocations should be elided in constexpr
contexts.

[Bug c++/91369] Implement P0784R7: constexpr new

2019-10-14 Thread jason at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

Jason Merrill  changed:

   What|Removed |Added

 Status|NEW |RESOLVED
 Resolution|--- |FIXED
   Target Milestone|--- |10.0

--- Comment #11 from Jason Merrill  ---
Implemented.

[Bug c++/91369] Implement P0784R7: constexpr new

2019-10-05 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #10 from Jakub Jelinek  ---
Author: jakub
Date: Sat Oct  5 07:38:21 2019
New Revision: 276622

URL: https://gcc.gnu.org/viewcvs?rev=276622=gcc=rev
Log:
PR c++/91369 - Implement P0784R7: constexpr new
c-family/
* c-cppbuiltin.c (c_cpp_builtins): Predefine
__cpp_constexpr_dynamic_alloc=201907 for -std=c++2a.
cp/
* cp-tree.h (enum cp_tree_index): Add CPTI_HEAP_UNINIT_IDENTIFIER,
CPTI_HEAP_IDENTIFIER and CPTI_HEAP_DELETED_IDENTIFIER.
(heap_uninit_identifier, heap_identifier, heap_deleted_identifier):
Define.
(type_has_constexpr_destructor, build_new_constexpr_heap_type,
cxx_constant_dtor): Declare.
* class.c (type_maybe_constexpr_default_constructor): Make static.
(type_maybe_constexpr_destructor, type_has_constexpr_destructor): New
functions.
(finalize_literal_type_property): For c++2a, don't clear
CLASSTYPE_LITERAL_P for types without trivial destructors unless they
have non-constexpr destructors.
(explain_non_literal_class): For c++2a, complain about non-constexpr
destructors rather than about non-trivial destructors.
* constexpr.c: Include stor-layout.h.
(struct constexpr_global_ctx): New type.
(struct constexpr_ctx): Add global field, remove values and
constexpr_ops_count.
(cxx_replaceable_global_alloc_fn): New inline function.
(cxx_eval_call_expression): For c++2a allow calls to replaceable
global allocation functions, for new return address of a heap uninit
var, for delete record its deletion.  Change ctx->values->{get,put} to
ctx->global->values.{get,put}.
(non_const_var_error): Add auto_diagnostic_group sentinel.  Emit
special diagnostics for heap variables.
(cxx_eval_store_expression): Change ctx->values->{get,put} to
ctx->global->values.{get,put}.
(cxx_eval_loop_expr): Initialize jump_target if NULL.  Change
new_ctx.values->remove to ctx->global->values.remove.
(cxx_eval_constant_expression): Change *ctx->constexpr_ops_count
to ctx->global->constexpr_ops_count.  Change ctx->values->{get,put} to
ctx->global->values.{get,put}.
: Formatting fix.  On cast of replaceable global
allocation function to some pointer type, adjust the type of
the heap variable and change name from heap_uninit_identifier
to heap_identifier.
(find_heap_var_refs): New function.
(cxx_eval_outermost_constant_expr): Add constexpr_dtor argument,
handle evaluation of constexpr dtors and add tracking of heap
variables.  Use tf_no_cleanup for get_target_expr_with_sfinae.
(cxx_constant_value): Adjust cxx_eval_outermost_constant_expr caller.
(cxx_constant_dtor): New function.
(maybe_constant_value, fold_non_dependent_expr_template,
maybe_constant_init_1): Adjust cxx_eval_outermost_constant_expr
callers.
(potential_constant_expression_1): Ignore clobbers.  Allow
COND_EXPR_IS_VEC_DELETE for c++2a.
* decl.c (initialize_predefined_identifiers): Add heap identifiers.
(decl_maybe_constant_destruction): New function.
(cp_finish_decl): Don't clear TREE_READONLY for constexpr variables
with non-trivial, but constexpr destructors.
(register_dtor_fn): For constexpr variables with constexpr non-trivial
destructors call cxx_maybe_build_cleanup instead of adding destructor
calls at runtime.
(expand_static_init): For constexpr variables with constexpr
non-trivial destructors call cxx_maybe_build_cleanup.
(grokdeclarator): Allow constexpr destructors for c++2a.  Formatting
fix.
(cxx_maybe_build_cleanup): For constexpr variables with constexpr
non-trivial destructors call cxx_constant_dtor instead of adding
destructor calls at runtime.
* init.c: Include stor-layout.h.
(build_new_constexpr_heap_type, maybe_wrap_new_for_constexpr): New
functions.
(build_new_1): For c++2a and new[], add cast around the alloc call
to help constexpr evaluation figure out the type of the heap storage.
(build_vec_delete_1): Set DECL_INITIAL of tbase and emit a DECL_EXPR
for it instead of initializing an uninitialized variable.
* method.c: Include intl.h.
(SFK_CTOR_P, SFK_DTOR_P, SFK_ASSIGN_P, SFK_COPY_P, SFK_MOVE_P): Move
definitions earlier.
(process_subob_fn): Add sfk argument, adjust non-constexpr call
diagnostics based on it.
(walk_field_subobs): Formatting fixes.  Adjust process_subob_fn caller.
(synthesized_method_base_walk): Likewise.
(synthesized_method_walk): Set *constexpr_p to true for dtors in c++2a.
Fix up DR number in comment.
(implicitly_declare_fn): Formatting 

[Bug c++/91369] Implement P0784R7: constexpr new

2019-09-27 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

Jakub Jelinek  changed:

   What|Removed |Added

  Attachment #46956|0   |1
is obsolete||

--- Comment #9 from Jakub Jelinek  ---
Created attachment 46967
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=46967=edit
gcc10-pr91369.patch

Updated patch.

[Bug c++/91369] Implement P0784R7: constexpr new

2019-09-26 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

Jakub Jelinek  changed:

   What|Removed |Added

  Attachment #46946|0   |1
is obsolete||

--- Comment #8 from Jakub Jelinek  ---
Created attachment 46956
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=46956=edit
gcc10-pr91369.patch

Updated patch.
This patch implements the state if C++ drops the note that trivial destructors
are constexpr destructors.  If on the core reflector you agree on something
else, please let me know and I'll change it.
Other than that, I need to finish up the cookie_size support for array new
(trying to represent that heap object as record with two fields, sizetype array
covering cookie and class_type array covering the rest, but seems indirect ref
folding isn't still happy about that, otherwise I'm out of ideas what else to
test.

[Bug c++/91369] Implement P0784R7: constexpr new

2019-09-26 Thread jason at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #7 from Jason Merrill  ---
(In reply to Jakub Jelinek from comment #6)
> So, is the [class.dtor]/9 note just incorrect and should be removed, or
> clarified somehow?  I believe it shouldn't affect what actually is a literal
> type or not, because the constructor of a class without virtual bases which
> has a non-static data member that has virtual bases can't be constexpr either.

I think a virtual base just shouldn't make the destructor non-constexpr, which
would make the note correct.  I've emailed CWG to that effect.

[Bug c++/91369] Implement P0784R7: constexpr new

2019-09-26 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #6 from Jakub Jelinek  ---
Still need to add further testcase coverage and finish cookie support, but I
ran into something that looks like a bug in the C++ standard.

[dcl.constexpr]/3 says:
if the function is a constructor or destructor, its class shall not have any
virtual base classes;
[dcl.constexpr]/5 says:
The definition of a constexpr destructor whose function-body is not = delete
shall additionally satisfy the following requirement:
- for every subobject of class type or (possibly multi-dimensional) array
thereof, that class type shall have a constexpr destructor.
[class.dtor]/8 says:
A destructor is trivial if it is not user-provided and if:
- the destructor is not virtual,
- all of the direct base classes of its class have trivial destructors, and
- for all of the non-static data members of its class that are of class type
(or array thereof), each such class has a trivial destructor.
[class.dtor]/9 says:
A defaulted destructor is a constexpr destructor if it satisfies the
requirements for a constexpr destructor ([dcl.constexpr]).
[ Note: In particular, a trivial destructor is a constexpr destructor.
— end note ]

Now, consider the g++.old-deja/g++.mike/p12306a.C or g++.dg/abi/empty7.C
testcases in -std=c++2a modes, let's say the first one:

class a {
public:
int i;
};

class g : virtual public a {
};

class b : virtual public a {
int j;
};

class c : public g, public b {
};

class d {
public:
virtual class b* get() {return 0;}
};

class f : public d {
public:
virtual class b* get() {return &_c;}
c _c;
};

int main(void) {
f D;
b* bp=D.get();
D._c.i = 42;
return _c.i != >i;
}

The patch ICEs on this, because the implicit f::~f () is considered trivial
(there are no virtual destructors in the testcase, nor any user-provided
destructors),
but it isn't a constexpr destructor, because while f doesn't have virtual
bases, a non-static data member of f (_c) has virtual bases and thus c::~c ()
is not a constexpr destructor and because of that f::~f () can't be a constexpr
destructor either.

So, is the [class.dtor]/9 note just incorrect and should be removed, or
clarified somehow?  I believe it shouldn't affect what actually is a literal
type or not, because
the constructor of a class without virtual bases which has a non-static data
member that has virtual bases can't be constexpr either.

On the compiler side, it would mean the trivial destructor quick bail-out
checks wouldn't actually work for when we ask whether the destructor is
constexpr, though we could keep it perhaps in the literal_type_p checking, at
least as long as a subobject with virtual bases really always forces
non-constexpr constructors.

[Bug c++/91369] Implement P0784R7: constexpr new

2019-09-26 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #5 from Jakub Jelinek  ---
Created attachment 46946
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=46946=edit
gcc10-pr91369.patch

Current WIP patch.

[Bug c++/91369] Implement P0784R7: constexpr new

2019-09-10 Thread jason at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #4 from Jason Merrill  ---
(In reply to Jakub Jelinek from comment #3)
> (In reply to Jason Merrill from comment #2)
> > > should we mark them some way and either allow the first
> > > cxx_fold_indirect_ref or the above code to change their type the first 
> > > time
> > > they are stored?
> > 
> > This would work, but wouldn't distinguish between a new-expression and the
> > equivalent written by hand.  I suppose a flag could make that distinction.
> 
> Wouldn't user written code have REINTERPRET_CAST_P set on the cast and thus
> be rejected?
> Can user call the replaceable new operator directly in constexpr contexts in
> some valid way?

Ah, good point.  They could call it directly, but couldn't do anything with the
memory without a reinterpret_cast.

[Bug c++/91369] Implement P0784R7: constexpr new

2019-09-10 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #3 from Jakub Jelinek  ---
(In reply to Jason Merrill from comment #2)
> > should we mark them some way and either allow the first
> > cxx_fold_indirect_ref or the above code to change their type the first time
> > they are stored?
> 
> This would work, but wouldn't distinguish between a new-expression and the
> equivalent written by hand.  I suppose a flag could make that distinction.

Wouldn't user written code have REINTERPRET_CAST_P set on the cast and thus be
rejected?
Can user call the replaceable new operator directly in constexpr contexts in
some valid way?

[Bug c++/91369] Implement P0784R7: constexpr new

2019-09-09 Thread jason at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #2 from Jason Merrill  ---
(In reply to Jakub Jelinek from comment #1)
> So, first of all, is it a good idea to represent the HEAP variables through
> artifical VAR_DECLs?

That makes sense to me.

> I guess in the outermost constexpr evaluation context we'd need to track
> which of those we have allocated and deallocated and do the checking that at
> the end of outermost constexpr evaluation no allocations are left around,

Sounds right.

> and that we don't deallocate something that hasn't been allocated.

I'd expect that to be detected during evaluation when we try to deallocate
something that isn't constant or isn't the address of one of these artificial
VAR_DECLs.

> As we don't have the actual dynamic type they will have at the end of new
> expression

We should really fix that.  Perhaps we should delay lowering new-expressions
until genericization time?

> should we mark them some way and either allow the first
> cxx_fold_indirect_ref or the above code to change their type the first time
> they are stored?

This would work, but wouldn't distinguish between a new-expression and the
equivalent written by hand.  I suppose a flag could make that distinction.

> Is placement new ok in constexpr contexts or not?

No, placement new is not replaceable.

> Can the global replaceable allocation functions be marked constexpr by the
> user?

No.

> For the constexpr dtors, we need to make sure to mark trivial dtors as
> constexpr, and default dtors as constexpr if they satisfy the rules, verify
> the restrictions for user defined constexpr dtors, and check for constexpr
> dtor in literal type check.  Plus guess for constexpr variables we need to
> at some point verify they are constexpr destructible (but on a copy of the
> variable value, such that changes to the value during destruction don't
> modify the actual value of the variable we use normally).

Right.  I think that's implied by the passage "An object a is said to have
constant destruction if ... for a hypothetical expression e whose only effect
is to destroy a, e would be a core constant expression if the lifetime of a and
its non-mutable subobjects (but not its mutable subobjects) were considered to
start within e."

[Bug c++/91369] Implement P0784R7: constexpr new

2019-08-30 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

Jakub Jelinek  changed:

   What|Removed |Added

 CC||jakub at gcc dot gnu.org,
   ||jason at gcc dot gnu.org,
   ||redi at gcc dot gnu.org

--- Comment #1 from Jakub Jelinek  ---
Just playing around a little bit, on:
struct S { constexpr S () : s (5) {}; int s; };
constexpr bool foo ()
{
  S *p = new S ();
  delete p;
  return true;
}
(so, trivial dtor rather than introducing constexpr dtors for now):

--- gcc/cp/constexpr.c.jj   2019-08-27 12:26:39.335884288 +0200
+++ gcc/cp/constexpr.c  2019-08-30 18:49:59.673689644 +0200
@@ -1666,6 +1666,34 @@ cxx_eval_call_expression (const constexp
   lval, non_constant_p, overflow_p);
   if (!DECL_DECLARED_CONSTEXPR_P (fun))
 {
+  if (cxx_dialect >= cxx2a
+  && IDENTIFIER_NEWDEL_OP_P (DECL_NAME (fun))
+ && CP_DECL_CONTEXT (fun) == global_namespace)
+   {
+ if (IDENTIFIER_NEW_OP_P (DECL_NAME (fun)))
+   {
+ const int nargs = call_expr_nargs (t);
+ tree sz = NULL_TREE;
+ for (int i = 0; i < nargs; ++i)
+   {
+ tree arg = CALL_EXPR_ARG (t, i);
+ arg = cxx_eval_constant_expression (ctx, arg, false,
+ non_constant_p,
+ overflow_p);
+ VERIFY_CONSTANT (arg);
+ if (i == 0)
+   sz = arg;
+   }
+ gcc_assert (sz);
+ tree type = build_array_type_nelts (char_type_node,
+ tree_to_uhwi (sz));
+ tree var = build_decl (loc, VAR_DECL, NULL_TREE, type);
+ DECL_ARTIFICIAL (var) = 1;
+ return fold_convert (ptr_type_node, build_address (var));
+   }
+ else
+   /* FIXME */;
+   }
   if (!ctx->quiet)
{
  if (!lambda_static_thunk_p (fun))
@@ -6243,7 +6271,12 @@ potential_constant_expression_1 (tree t,
if (!DECL_DECLARED_CONSTEXPR_P (fun)
/* Allow any built-in function; if the expansion
   isn't constant, we'll deal with that then.  */
-   && !fndecl_built_in_p (fun))
+   && !fndecl_built_in_p (fun)
+   /* In C++2a, replaceable global allocation functions
+  are constant expressions.  */
+   && (cxx_dialect < cxx2a
+   || !IDENTIFIER_NEWDEL_OP_P (DECL_NAME (fun))
+   || CP_DECL_CONTEXT (fun) != global_namespace))
  {
if (flags & tf_error)
  {

This fails because we represent the new expression as COMPOUND_EXPR which first
calls the allocation function (handled by the above code) and then constructs
the var (effectively through a reinterpret cast not marked as such), and fail
on that:
  r = cxx_fold_indirect_ref (EXPR_LOCATION (t), TREE_TYPE (t), op0,
 _base);
  if (r == NULL_TREE)
{
  /* We couldn't fold to a constant value.  Make sure it's not
 something we should have been able to fold.  */
  tree sub = op0;
  STRIP_NOPS (sub);
  if (TREE_CODE (sub) == ADDR_EXPR)
{
  gcc_assert (!same_type_ignoring_top_level_qualifiers_p
  (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t)));
  /* DR 1188 says we don't have to deal with this.  */
  if (!ctx->quiet)
error ("accessing value of %qE through a %qT glvalue in a "
   "constant expression", build_fold_indirect_ref (sub),
   TREE_TYPE (t));
  *non_constant_p = true;
  return t;
}

  if (lval && op0 != orig_op0)
return build1 (INDIRECT_REF, TREE_TYPE (t), op0);
  if (!lval)
VERIFY_CONSTANT (t);
  return t;
}

So, first of all, is it a good idea to represent the HEAP variables through
artifical VAR_DECLs?

I guess in the outermost constexpr evaluation context we'd need to track which
of those we have allocated and deallocated and do the checking that at the end
of outermost constexpr evaluation no allocations are left around, and that we
don't deallocate something that hasn't been allocated.

As we don't have the actual dynamic type they will have at the end of new
expression, should we mark them some way and either allow the first
cxx_fold_indirect_ref or the above code to change their type the first time
they are stored?

Is placement new ok in 

[Bug c++/91369] Implement P0784R7: constexpr new

2019-08-05 Thread mpolacek at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

Marek Polacek  changed:

   What|Removed |Added

 Status|UNCONFIRMED |NEW
   Last reconfirmed||2019-08-05
 Ever confirmed|0   |1