Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-14 Thread Patrick Palka via Gcc-patches
On Tue, 14 Apr 2020, Jason Merrill wrote:

> On 4/14/20 9:01 AM, Patrick Palka wrote:
> > On Tue, 14 Apr 2020, Patrick Palka wrote:
> > 
> > > On Mon, 13 Apr 2020, Jason Merrill wrote:
> > > 
> > > > On 4/13/20 2:49 PM, Patrick Palka wrote:
> > > > > On Mon, 13 Apr 2020, Jason Merrill wrote:
> > > > > 
> > > > > > On 4/12/20 9:43 AM, Patrick Palka wrote:
> > > > > > > On Sat, 11 Apr 2020, Jason Merrill wrote:
> > > > > > > 
> > > > > > > > On 4/10/20 5:47 PM, Patrick Palka wrote:
> > > > > > > > > On Fri, 10 Apr 2020, Jason Merrill wrote:
> > > > > > > > > > On 4/10/20 2:15 PM, Patrick Palka wrote:
> > > > > > > > > > > On Fri, 10 Apr 2020, Patrick Palka wrote:
> > > > > > > > > > > 
> > > > > > > > > > > > On Fri, 10 Apr 2020, Jason Merrill wrote:
> > > > > > > > > > > > 
> > > > > > > > > > > > > On 4/10/20 1:04 PM, Patrick Palka wrote:
> > > > > > > > > > > > > > On Thu, 9 Apr 2020, Patrick Palka wrote:
> > > > > > > > > > > > > > > On Thu, 9 Apr 2020, Jason Merrill wrote:
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > On 4/8/20 7:49 PM, Patrick Palka wrote:
> > > > > > > > > > > > > > > > > When evaluating the initializer of 'a' in the
> > > > > > > > > > > > > > > > > following
> > > > > > > > > > > > > > > > > example
> > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > >  struct A { A *p = this; };
> > > > > > > > > > > > > > > > >  constexpr A foo() { return {}; }
> > > > > > > > > > > > > > > > >  constexpr A a = foo();
> > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > the PLACEHOLDER_EXPR for 'this' in the
> > > > > > > > > > > > > > > > > aggregate
> > > > > > > > > > > > > > > > > initializer
> > > > > > > > > > > > > > > > > returned
> > > > > > > > > > > > > > > > > by foo
> > > > > > > > > > > > > > > > > gets resolved to the RESULT_DECL of foo.  But
> > > > > > > > > > > > > > > > > due to
> > > > > > > > > > > > > > > > > guaranteed
> > > > > > > > > > > > > > > > > RVO,
> > > > > > > > > > > > > > > > > the
> > > > > > > > > > > > > > > > > 'this'
> > > > > > > > > > > > > > > > > should really be resolved to '&a'.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > It seems to me that the right approach would
> > > > > > > > > > > > > > > > > be to
> > > > > > > > > > > > > > > > > immediately
> > > > > > > > > > > > > > > > > resolve
> > > > > > > > > > > > > > > > > the
> > > > > > > > > > > > > > > > > PLACEHOLDER_EXPR to the correct target object
> > > > > > > > > > > > > > > > > during
> > > > > > > > > > > > > > > > > evaluation
> > > > > > > > > > > > > > > > > of
> > > > > > > > > > > > > > > > > 'foo()',
> > > > > > > > > > > > > > > > > so
> > > > > > > > > > > > > > > > > that we could use 'this' to access objects
> > > > > > > > > > > > > > > > > adjacent
> > > > > > > > > > > > > > > > > to
> > > > > > > > > > > > > > > > > the
> > > > > > > > > > > > > > > > > current
> > > > > > > > > > > > > > > > > object in
> > > > > > > > > > > > > > > > > the
> > > > > > > > > > > > > > > > > ultimate storage location.  (I think #c2 of PR
> > > > > > > > > > > > > > > > > c++/94537
> > > > > > > > > > > > > > > > > is
> > > > > > > > > > > > > > > > > an
> > > > > > > > > > > > > > > > > example
> > > > > > > > > > > > > > > > > of
> > > > > > > > > > > > > > > > > such
> > > > > > > > > > > > > > > > > usage of 'this', which currently doesn't work.
> > > > > > > > > > > > > > > > > But
> > > > > > > > > > > > > > > > > as
> > > > > > > > > > > > > > > > > #c1
> > > > > > > > > > > > > > > > > shows
> > > > > > > > > > > > > > > > > we
> > > > > > > > > > > > > > > > > don't
> > > > > > > > > > > > > > > > > seem
> > > > > > > > > > > > > > > > > to handle this case correctly in non-constexpr
> > > > > > > > > > > > > > > > > initialization
> > > > > > > > > > > > > > > > > either.)
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > As I commented in the PR, the standard doesn't
> > > > > > > > > > > > > > > > require
> > > > > > > > > > > > > > > > this to
> > > > > > > > > > > > > > > > work
> > > > > > > > > > > > > > > > because A
> > > > > > > > > > > > > > > > is trivially copyable, and our ABI makes it
> > > > > > > > > > > > > > > > impossible.
> > > > > > > > > > > > > > > > But
> > > > > > > > > > > > > > > > there's
> > > > > > > > > > > > > > > > still a
> > > > > > > > > > > > > > > > constexpr bug when we add
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > A() = default; A(const A&);
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > clang doesn't require the constructors to make
> > > > > > > > > > > > > > > > this
> > > > > > > > > > > > > > > > work
> > > > > > > > > > > > > > > > for
> > > > > > > > > > > > > > > > constant
> > > > > > > > > > > > > > > > initialization, but similarly can't make it work
> > > > > > > > > > > > > > > > for
> > > > > > > > > > > > > > > > non-constant
> > > > > > > > > > > > > > > > initialization.
> > > 

Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-14 Thread Jason Merrill via Gcc-patches

On 4/14/20 9:01 AM, Patrick Palka wrote:

On Tue, 14 Apr 2020, Patrick Palka wrote:


On Mon, 13 Apr 2020, Jason Merrill wrote:


On 4/13/20 2:49 PM, Patrick Palka wrote:

On Mon, 13 Apr 2020, Jason Merrill wrote:


On 4/12/20 9:43 AM, Patrick Palka wrote:

On Sat, 11 Apr 2020, Jason Merrill wrote:


On 4/10/20 5:47 PM, Patrick Palka wrote:

On Fri, 10 Apr 2020, Jason Merrill wrote:

On 4/10/20 2:15 PM, Patrick Palka wrote:

On Fri, 10 Apr 2020, Patrick Palka wrote:


On Fri, 10 Apr 2020, Jason Merrill wrote:


On 4/10/20 1:04 PM, Patrick Palka wrote:

On Thu, 9 Apr 2020, Patrick Palka wrote:

On Thu, 9 Apr 2020, Jason Merrill wrote:


On 4/8/20 7:49 PM, Patrick Palka wrote:

When evaluating the initializer of 'a' in the
following
example

 struct A { A *p = this; };
 constexpr A foo() { return {}; }
 constexpr A a = foo();

the PLACEHOLDER_EXPR for 'this' in the aggregate
initializer
returned
by foo
gets resolved to the RESULT_DECL of foo.  But due to
guaranteed
RVO,
the
'this'
should really be resolved to '&a'.



It seems to me that the right approach would be to
immediately
resolve
the
PLACEHOLDER_EXPR to the correct target object during
evaluation
of
'foo()',
so
that we could use 'this' to access objects adjacent
to
the
current
object in
the
ultimate storage location.  (I think #c2 of PR
c++/94537
is
an
example
of
such
usage of 'this', which currently doesn't work.  But
as
#c1
shows
we
don't
seem
to handle this case correctly in non-constexpr
initialization
either.)


As I commented in the PR, the standard doesn't require
this to
work
because A
is trivially copyable, and our ABI makes it
impossible.
But
there's
still a
constexpr bug when we add

A() = default; A(const A&);

clang doesn't require the constructors to make this
work
for
constant
initialization, but similarly can't make it work for
non-constant
initialization.


That makes a lot of sense, thanks for the detailed
explanation.




I haven't yet been able to make a solution using the
above
approach
work --
making sure we use the ultimate object instead of
the
RESULT_DECL
whenever
we
access ctx->global->values is proving to be tricky
and
subtle.


Do we need to go through ctx->global->values?  Would
it
work
for
the
RESULT_DECL case in cxx_eval_constant_expression to go
to
straight
to
ctx->object or ctx->ctor instead?


I attempted that at some point, but IIRC we still end up
not
resolving
some RESULT_DECLs because not all of them get processed
through
cxx_eval_constant_expression before we manipulate
ctx->global->values
with them.  I'll try this approach more carefully and
report
back
with
more specifics.


It turns out that immediately resolving
RESULT_DECLs/'this' to
the
ultimate ctx->object would not interact well with
constexpr_call
caching:

struct A { A() = default; A(const A&); A *ap =
this; };
constexpr A foo() { return {}; }
constexpr A a = foo();
constexpr A b = foo();
static_assert(b.ap == &b); // fails

Evaluation of the first call to foo() returns {&a}, since
we
resolve
'this' to &a due to guaranteed RVO, and we cache this
result.
Evaluation of the second call to foo() just returns the
cached
result
from the constexpr_call cache, and so we get {&a} again.

So it seems we would have to mark the result of a
constexpr
call
as
not
cacheable whenever this RVO applies during its evaluation,
even
when
doing the RVO has no observable difference in the final
result
(i.e.
the
constructor does not try to save the 'this' pointer).

Would the performance impact of disabling caching whenever
RVO
applies
during constexpr call evaluation be worth it, or should we
go
with
something like my first patch which "almost works," and
which
marks a
constexpr call as not cacheable only when we replace a
RESULT_DECL
in
the result of the call?


Could we search through the result of the call for
ctx->object
and
cache
if we
don't find it?


Hmm, I think the result of the call could still depend on
ctx->object
without ctx->object explicitly appearing in the result.
Consider
the
following testcase:

   struct A {
 A() = default; A(const A&);
 constexpr A(const A *q) : d{this - p} { }


Oops sorry, that 'q' should be a 'p'.


 long d = 0;
   };

   constexpr A baz(const A *q) { return A(p); };


And same here.


   constexpr A a = baz(&a);
   constexpr A b = baz(&a); // no error

The initialization of 'b' should be ill-formed, but the result
of
the
first call to baz(&a) would be {0}, so we would cache it and
then
reuse
the result when initializing 'b'.


Ah, true.  Can we still cache if we're initializing something that
isn't
TREE_STATIC?


Hmm, we correctly compile the analogous non-TREE_STATIC testcase

struct A {
  A() = default; A(const A&);
  constexpr A(const A *p) : d{this == p} { }
  bool d;
};

constexpr A baz(const A *p) { return A(p); }

void foo() {
  constexpr A x = baz(&x);
   

Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-14 Thread Jason Merrill via Gcc-patches

On 4/14/20 12:29 AM, Patrick Palka wrote:

On Mon, 13 Apr 2020, Jason Merrill wrote:


On 4/13/20 2:49 PM, Patrick Palka wrote:

On Mon, 13 Apr 2020, Jason Merrill wrote:


On 4/12/20 9:43 AM, Patrick Palka wrote:

On Sat, 11 Apr 2020, Jason Merrill wrote:


On 4/10/20 5:47 PM, Patrick Palka wrote:

On Fri, 10 Apr 2020, Jason Merrill wrote:

On 4/10/20 2:15 PM, Patrick Palka wrote:

On Fri, 10 Apr 2020, Patrick Palka wrote:


On Fri, 10 Apr 2020, Jason Merrill wrote:


On 4/10/20 1:04 PM, Patrick Palka wrote:

On Thu, 9 Apr 2020, Patrick Palka wrote:

On Thu, 9 Apr 2020, Jason Merrill wrote:


On 4/8/20 7:49 PM, Patrick Palka wrote:

When evaluating the initializer of 'a' in the
following
example

 struct A { A *p = this; };
 constexpr A foo() { return {}; }
 constexpr A a = foo();

the PLACEHOLDER_EXPR for 'this' in the aggregate
initializer
returned
by foo
gets resolved to the RESULT_DECL of foo.  But due to
guaranteed
RVO,
the
'this'
should really be resolved to '&a'.



It seems to me that the right approach would be to
immediately
resolve
the
PLACEHOLDER_EXPR to the correct target object during
evaluation
of
'foo()',
so
that we could use 'this' to access objects adjacent
to
the
current
object in
the
ultimate storage location.  (I think #c2 of PR
c++/94537
is
an
example
of
such
usage of 'this', which currently doesn't work.  But
as
#c1
shows
we
don't
seem
to handle this case correctly in non-constexpr
initialization
either.)


As I commented in the PR, the standard doesn't require
this to
work
because A
is trivially copyable, and our ABI makes it
impossible.
But
there's
still a
constexpr bug when we add

A() = default; A(const A&);

clang doesn't require the constructors to make this
work
for
constant
initialization, but similarly can't make it work for
non-constant
initialization.


That makes a lot of sense, thanks for the detailed
explanation.




I haven't yet been able to make a solution using the
above
approach
work --
making sure we use the ultimate object instead of
the
RESULT_DECL
whenever
we
access ctx->global->values is proving to be tricky
and
subtle.


Do we need to go through ctx->global->values?  Would
it
work
for
the
RESULT_DECL case in cxx_eval_constant_expression to go
to
straight
to
ctx->object or ctx->ctor instead?


I attempted that at some point, but IIRC we still end up
not
resolving
some RESULT_DECLs because not all of them get processed
through
cxx_eval_constant_expression before we manipulate
ctx->global->values
with them.  I'll try this approach more carefully and
report
back
with
more specifics.


It turns out that immediately resolving
RESULT_DECLs/'this' to
the
ultimate ctx->object would not interact well with
constexpr_call
caching:

struct A { A() = default; A(const A&); A *ap =
this; };
constexpr A foo() { return {}; }
constexpr A a = foo();
constexpr A b = foo();
static_assert(b.ap == &b); // fails

Evaluation of the first call to foo() returns {&a}, since
we
resolve
'this' to &a due to guaranteed RVO, and we cache this
result.
Evaluation of the second call to foo() just returns the
cached
result
from the constexpr_call cache, and so we get {&a} again.

So it seems we would have to mark the result of a
constexpr
call
as
not
cacheable whenever this RVO applies during its evaluation,
even
when
doing the RVO has no observable difference in the final
result
(i.e.
the
constructor does not try to save the 'this' pointer).

Would the performance impact of disabling caching whenever
RVO
applies
during constexpr call evaluation be worth it, or should we
go
with
something like my first patch which "almost works," and
which
marks a
constexpr call as not cacheable only when we replace a
RESULT_DECL
in
the result of the call?


Could we search through the result of the call for
ctx->object
and
cache
if we
don't find it?


Hmm, I think the result of the call could still depend on
ctx->object
without ctx->object explicitly appearing in the result.
Consider
the
following testcase:

   struct A {
 A() = default; A(const A&);
 constexpr A(const A *q) : d{this - p} { }


Oops sorry, that 'q' should be a 'p'.


 long d = 0;
   };

   constexpr A baz(const A *q) { return A(p); };


And same here.


   constexpr A a = baz(&a);
   constexpr A b = baz(&a); // no error

The initialization of 'b' should be ill-formed, but the result
of
the
first call to baz(&a) would be {0}, so we would cache it and
then
reuse
the result when initializing 'b'.


Ah, true.  Can we still cache if we're initializing something that
isn't
TREE_STATIC?


Hmm, we correctly compile the analogous non-TREE_STATIC testcase

struct A {
  A() = default; A(const A&);
  constexpr A(const A *p) : d{this == p} { }
  bool d;
};

constexpr A baz(const A *p) { return A(p); }

void foo() {
  constexpr A x = baz(&x);
  constexpr A y = baz(&x);
  s

Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-14 Thread Patrick Palka via Gcc-patches
On Tue, 14 Apr 2020, Patrick Palka wrote:

> On Mon, 13 Apr 2020, Jason Merrill wrote:
> 
> > On 4/13/20 2:49 PM, Patrick Palka wrote:
> > > On Mon, 13 Apr 2020, Jason Merrill wrote:
> > > 
> > > > On 4/12/20 9:43 AM, Patrick Palka wrote:
> > > > > On Sat, 11 Apr 2020, Jason Merrill wrote:
> > > > > 
> > > > > > On 4/10/20 5:47 PM, Patrick Palka wrote:
> > > > > > > On Fri, 10 Apr 2020, Jason Merrill wrote:
> > > > > > > > On 4/10/20 2:15 PM, Patrick Palka wrote:
> > > > > > > > > On Fri, 10 Apr 2020, Patrick Palka wrote:
> > > > > > > > > 
> > > > > > > > > > On Fri, 10 Apr 2020, Jason Merrill wrote:
> > > > > > > > > > 
> > > > > > > > > > > On 4/10/20 1:04 PM, Patrick Palka wrote:
> > > > > > > > > > > > On Thu, 9 Apr 2020, Patrick Palka wrote:
> > > > > > > > > > > > > On Thu, 9 Apr 2020, Jason Merrill wrote:
> > > > > > > > > > > > > 
> > > > > > > > > > > > > > On 4/8/20 7:49 PM, Patrick Palka wrote:
> > > > > > > > > > > > > > > When evaluating the initializer of 'a' in the
> > > > > > > > > > > > > > > following
> > > > > > > > > > > > > > > example
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > struct A { A *p = this; };
> > > > > > > > > > > > > > > constexpr A foo() { return {}; }
> > > > > > > > > > > > > > > constexpr A a = foo();
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > the PLACEHOLDER_EXPR for 'this' in the aggregate
> > > > > > > > > > > > > > > initializer
> > > > > > > > > > > > > > > returned
> > > > > > > > > > > > > > > by foo
> > > > > > > > > > > > > > > gets resolved to the RESULT_DECL of foo.  But due 
> > > > > > > > > > > > > > > to
> > > > > > > > > > > > > > > guaranteed
> > > > > > > > > > > > > > > RVO,
> > > > > > > > > > > > > > > the
> > > > > > > > > > > > > > > 'this'
> > > > > > > > > > > > > > > should really be resolved to '&a'.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > It seems to me that the right approach would be to
> > > > > > > > > > > > > > > immediately
> > > > > > > > > > > > > > > resolve
> > > > > > > > > > > > > > > the
> > > > > > > > > > > > > > > PLACEHOLDER_EXPR to the correct target object 
> > > > > > > > > > > > > > > during
> > > > > > > > > > > > > > > evaluation
> > > > > > > > > > > > > > > of
> > > > > > > > > > > > > > > 'foo()',
> > > > > > > > > > > > > > > so
> > > > > > > > > > > > > > > that we could use 'this' to access objects 
> > > > > > > > > > > > > > > adjacent
> > > > > > > > > > > > > > > to
> > > > > > > > > > > > > > > the
> > > > > > > > > > > > > > > current
> > > > > > > > > > > > > > > object in
> > > > > > > > > > > > > > > the
> > > > > > > > > > > > > > > ultimate storage location.  (I think #c2 of PR
> > > > > > > > > > > > > > > c++/94537
> > > > > > > > > > > > > > > is
> > > > > > > > > > > > > > > an
> > > > > > > > > > > > > > > example
> > > > > > > > > > > > > > > of
> > > > > > > > > > > > > > > such
> > > > > > > > > > > > > > > usage of 'this', which currently doesn't work.  
> > > > > > > > > > > > > > > But
> > > > > > > > > > > > > > > as
> > > > > > > > > > > > > > > #c1
> > > > > > > > > > > > > > > shows
> > > > > > > > > > > > > > > we
> > > > > > > > > > > > > > > don't
> > > > > > > > > > > > > > > seem
> > > > > > > > > > > > > > > to handle this case correctly in non-constexpr
> > > > > > > > > > > > > > > initialization
> > > > > > > > > > > > > > > either.)
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > As I commented in the PR, the standard doesn't 
> > > > > > > > > > > > > > require
> > > > > > > > > > > > > > this to
> > > > > > > > > > > > > > work
> > > > > > > > > > > > > > because A
> > > > > > > > > > > > > > is trivially copyable, and our ABI makes it
> > > > > > > > > > > > > > impossible.
> > > > > > > > > > > > > > But
> > > > > > > > > > > > > > there's
> > > > > > > > > > > > > > still a
> > > > > > > > > > > > > > constexpr bug when we add
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > A() = default; A(const A&);
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > clang doesn't require the constructors to make this
> > > > > > > > > > > > > > work
> > > > > > > > > > > > > > for
> > > > > > > > > > > > > > constant
> > > > > > > > > > > > > > initialization, but similarly can't make it work for
> > > > > > > > > > > > > > non-constant
> > > > > > > > > > > > > > initialization.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > That makes a lot of sense, thanks for the detailed
> > > > > > > > > > > > > explanation.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > I haven't yet been able to make a solution using 
> > > > > > > > > > > > > > > the
> > > > > > > > > > > > > > > above
> > > > > > > > > > > > > > > approach
> > > > > > > > > > > > > > > work --
> > > > > > > > > > > > > > > making sure we use the ultimate object instead of
> > > > > > > > > > > > > > > the
> > > > > > > > > > > > > > > RESULT_DECL
> > > > > > > > > > > > > > > whene

Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-13 Thread Patrick Palka via Gcc-patches
On Mon, 13 Apr 2020, Jason Merrill wrote:

> On 4/13/20 2:49 PM, Patrick Palka wrote:
> > On Mon, 13 Apr 2020, Jason Merrill wrote:
> > 
> > > On 4/12/20 9:43 AM, Patrick Palka wrote:
> > > > On Sat, 11 Apr 2020, Jason Merrill wrote:
> > > > 
> > > > > On 4/10/20 5:47 PM, Patrick Palka wrote:
> > > > > > On Fri, 10 Apr 2020, Jason Merrill wrote:
> > > > > > > On 4/10/20 2:15 PM, Patrick Palka wrote:
> > > > > > > > On Fri, 10 Apr 2020, Patrick Palka wrote:
> > > > > > > > 
> > > > > > > > > On Fri, 10 Apr 2020, Jason Merrill wrote:
> > > > > > > > > 
> > > > > > > > > > On 4/10/20 1:04 PM, Patrick Palka wrote:
> > > > > > > > > > > On Thu, 9 Apr 2020, Patrick Palka wrote:
> > > > > > > > > > > > On Thu, 9 Apr 2020, Jason Merrill wrote:
> > > > > > > > > > > > 
> > > > > > > > > > > > > On 4/8/20 7:49 PM, Patrick Palka wrote:
> > > > > > > > > > > > > > When evaluating the initializer of 'a' in the
> > > > > > > > > > > > > > following
> > > > > > > > > > > > > > example
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > struct A { A *p = this; };
> > > > > > > > > > > > > > constexpr A foo() { return {}; }
> > > > > > > > > > > > > > constexpr A a = foo();
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > the PLACEHOLDER_EXPR for 'this' in the aggregate
> > > > > > > > > > > > > > initializer
> > > > > > > > > > > > > > returned
> > > > > > > > > > > > > > by foo
> > > > > > > > > > > > > > gets resolved to the RESULT_DECL of foo.  But due to
> > > > > > > > > > > > > > guaranteed
> > > > > > > > > > > > > > RVO,
> > > > > > > > > > > > > > the
> > > > > > > > > > > > > > 'this'
> > > > > > > > > > > > > > should really be resolved to '&a'.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > > It seems to me that the right approach would be to
> > > > > > > > > > > > > > immediately
> > > > > > > > > > > > > > resolve
> > > > > > > > > > > > > > the
> > > > > > > > > > > > > > PLACEHOLDER_EXPR to the correct target object during
> > > > > > > > > > > > > > evaluation
> > > > > > > > > > > > > > of
> > > > > > > > > > > > > > 'foo()',
> > > > > > > > > > > > > > so
> > > > > > > > > > > > > > that we could use 'this' to access objects adjacent
> > > > > > > > > > > > > > to
> > > > > > > > > > > > > > the
> > > > > > > > > > > > > > current
> > > > > > > > > > > > > > object in
> > > > > > > > > > > > > > the
> > > > > > > > > > > > > > ultimate storage location.  (I think #c2 of PR
> > > > > > > > > > > > > > c++/94537
> > > > > > > > > > > > > > is
> > > > > > > > > > > > > > an
> > > > > > > > > > > > > > example
> > > > > > > > > > > > > > of
> > > > > > > > > > > > > > such
> > > > > > > > > > > > > > usage of 'this', which currently doesn't work.  But
> > > > > > > > > > > > > > as
> > > > > > > > > > > > > > #c1
> > > > > > > > > > > > > > shows
> > > > > > > > > > > > > > we
> > > > > > > > > > > > > > don't
> > > > > > > > > > > > > > seem
> > > > > > > > > > > > > > to handle this case correctly in non-constexpr
> > > > > > > > > > > > > > initialization
> > > > > > > > > > > > > > either.)
> > > > > > > > > > > > > 
> > > > > > > > > > > > > As I commented in the PR, the standard doesn't require
> > > > > > > > > > > > > this to
> > > > > > > > > > > > > work
> > > > > > > > > > > > > because A
> > > > > > > > > > > > > is trivially copyable, and our ABI makes it
> > > > > > > > > > > > > impossible.
> > > > > > > > > > > > > But
> > > > > > > > > > > > > there's
> > > > > > > > > > > > > still a
> > > > > > > > > > > > > constexpr bug when we add
> > > > > > > > > > > > > 
> > > > > > > > > > > > > A() = default; A(const A&);
> > > > > > > > > > > > > 
> > > > > > > > > > > > > clang doesn't require the constructors to make this
> > > > > > > > > > > > > work
> > > > > > > > > > > > > for
> > > > > > > > > > > > > constant
> > > > > > > > > > > > > initialization, but similarly can't make it work for
> > > > > > > > > > > > > non-constant
> > > > > > > > > > > > > initialization.
> > > > > > > > > > > > 
> > > > > > > > > > > > That makes a lot of sense, thanks for the detailed
> > > > > > > > > > > > explanation.
> > > > > > > > > > > > 
> > > > > > > > > > > > > 
> > > > > > > > > > > > > > I haven't yet been able to make a solution using the
> > > > > > > > > > > > > > above
> > > > > > > > > > > > > > approach
> > > > > > > > > > > > > > work --
> > > > > > > > > > > > > > making sure we use the ultimate object instead of
> > > > > > > > > > > > > > the
> > > > > > > > > > > > > > RESULT_DECL
> > > > > > > > > > > > > > whenever
> > > > > > > > > > > > > > we
> > > > > > > > > > > > > > access ctx->global->values is proving to be tricky
> > > > > > > > > > > > > > and
> > > > > > > > > > > > > > subtle.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > Do we need to go through ctx->global->values?  Would
> > > > > > > > > > > > > it
> > > > > > > > > > > > > work
> > > > > > > > > > > > > for
> > > > > > > > > > > > > the
> > > > > > > > > > > > > RES

Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-13 Thread Jason Merrill via Gcc-patches

On 4/13/20 2:49 PM, Patrick Palka wrote:

On Mon, 13 Apr 2020, Jason Merrill wrote:


On 4/12/20 9:43 AM, Patrick Palka wrote:

On Sat, 11 Apr 2020, Jason Merrill wrote:


On 4/10/20 5:47 PM, Patrick Palka wrote:

On Fri, 10 Apr 2020, Jason Merrill wrote:

On 4/10/20 2:15 PM, Patrick Palka wrote:

On Fri, 10 Apr 2020, Patrick Palka wrote:


On Fri, 10 Apr 2020, Jason Merrill wrote:


On 4/10/20 1:04 PM, Patrick Palka wrote:

On Thu, 9 Apr 2020, Patrick Palka wrote:

On Thu, 9 Apr 2020, Jason Merrill wrote:


On 4/8/20 7:49 PM, Patrick Palka wrote:

When evaluating the initializer of 'a' in the following
example

struct A { A *p = this; };
constexpr A foo() { return {}; }
constexpr A a = foo();

the PLACEHOLDER_EXPR for 'this' in the aggregate
initializer
returned
by foo
gets resolved to the RESULT_DECL of foo.  But due to
guaranteed
RVO,
the
'this'
should really be resolved to '&a'.



It seems to me that the right approach would be to
immediately
resolve
the
PLACEHOLDER_EXPR to the correct target object during
evaluation
of
'foo()',
so
that we could use 'this' to access objects adjacent to
the
current
object in
the
ultimate storage location.  (I think #c2 of PR c++/94537
is
an
example
of
such
usage of 'this', which currently doesn't work.  But as
#c1
shows
we
don't
seem
to handle this case correctly in non-constexpr
initialization
either.)


As I commented in the PR, the standard doesn't require
this to
work
because A
is trivially copyable, and our ABI makes it impossible.
But
there's
still a
constexpr bug when we add

A() = default; A(const A&);

clang doesn't require the constructors to make this work
for
constant
initialization, but similarly can't make it work for
non-constant
initialization.


That makes a lot of sense, thanks for the detailed
explanation.




I haven't yet been able to make a solution using the
above
approach
work --
making sure we use the ultimate object instead of the
RESULT_DECL
whenever
we
access ctx->global->values is proving to be tricky and
subtle.


Do we need to go through ctx->global->values?  Would it
work
for
the
RESULT_DECL case in cxx_eval_constant_expression to go to
straight
to
ctx->object or ctx->ctor instead?


I attempted that at some point, but IIRC we still end up not
resolving
some RESULT_DECLs because not all of them get processed
through
cxx_eval_constant_expression before we manipulate
ctx->global->values
with them.  I'll try this approach more carefully and report
back
with
more specifics.


It turns out that immediately resolving RESULT_DECLs/'this' to
the
ultimate ctx->object would not interact well with
constexpr_call
caching:

   struct A { A() = default; A(const A&); A *ap = this; };
   constexpr A foo() { return {}; }
   constexpr A a = foo();
   constexpr A b = foo();
   static_assert(b.ap == &b); // fails

Evaluation of the first call to foo() returns {&a}, since we
resolve
'this' to &a due to guaranteed RVO, and we cache this result.
Evaluation of the second call to foo() just returns the cached
result
from the constexpr_call cache, and so we get {&a} again.

So it seems we would have to mark the result of a constexpr
call
as
not
cacheable whenever this RVO applies during its evaluation,
even
when
doing the RVO has no observable difference in the final result
(i.e.
the
constructor does not try to save the 'this' pointer).

Would the performance impact of disabling caching whenever RVO
applies
during constexpr call evaluation be worth it, or should we go
with
something like my first patch which "almost works," and which
marks a
constexpr call as not cacheable only when we replace a
RESULT_DECL
in
the result of the call?


Could we search through the result of the call for ctx->object
and
cache
if we
don't find it?


Hmm, I think the result of the call could still depend on
ctx->object
without ctx->object explicitly appearing in the result.  Consider
the
following testcase:

  struct A {
A() = default; A(const A&);
constexpr A(const A *q) : d{this - p} { }


Oops sorry, that 'q' should be a 'p'.


long d = 0;
  };

  constexpr A baz(const A *q) { return A(p); };


And same here.


  constexpr A a = baz(&a);
  constexpr A b = baz(&a); // no error

The initialization of 'b' should be ill-formed, but the result of
the
first call to baz(&a) would be {0}, so we would cache it and then
reuse
the result when initializing 'b'.


Ah, true.  Can we still cache if we're initializing something that
isn't
TREE_STATIC?


Hmm, we correctly compile the analogous non-TREE_STATIC testcase

   struct A {
 A() = default; A(const A&);
 constexpr A(const A *p) : d{this == p} { }
 bool d;
   };

   constexpr A baz(const A *p) { return A(p); }

   void foo() {
 constexpr A x = baz(&x);
 constexpr A y = baz(&x);
 static_assert(!y.d);
   }

because the calls 'baz(&x)' are considered to have non-constant
arguments.


Unfor

Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-13 Thread Patrick Palka via Gcc-patches
On Mon, 13 Apr 2020, Jason Merrill wrote:

> On 4/12/20 9:43 AM, Patrick Palka wrote:
> > On Sat, 11 Apr 2020, Jason Merrill wrote:
> > 
> > > On 4/10/20 5:47 PM, Patrick Palka wrote:
> > > > On Fri, 10 Apr 2020, Jason Merrill wrote:
> > > > > On 4/10/20 2:15 PM, Patrick Palka wrote:
> > > > > > On Fri, 10 Apr 2020, Patrick Palka wrote:
> > > > > > 
> > > > > > > On Fri, 10 Apr 2020, Jason Merrill wrote:
> > > > > > > 
> > > > > > > > On 4/10/20 1:04 PM, Patrick Palka wrote:
> > > > > > > > > On Thu, 9 Apr 2020, Patrick Palka wrote:
> > > > > > > > > > On Thu, 9 Apr 2020, Jason Merrill wrote:
> > > > > > > > > > 
> > > > > > > > > > > On 4/8/20 7:49 PM, Patrick Palka wrote:
> > > > > > > > > > > > When evaluating the initializer of 'a' in the following
> > > > > > > > > > > > example
> > > > > > > > > > > > 
> > > > > > > > > > > >struct A { A *p = this; };
> > > > > > > > > > > >constexpr A foo() { return {}; }
> > > > > > > > > > > >constexpr A a = foo();
> > > > > > > > > > > > 
> > > > > > > > > > > > the PLACEHOLDER_EXPR for 'this' in the aggregate
> > > > > > > > > > > > initializer
> > > > > > > > > > > > returned
> > > > > > > > > > > > by foo
> > > > > > > > > > > > gets resolved to the RESULT_DECL of foo.  But due to
> > > > > > > > > > > > guaranteed
> > > > > > > > > > > > RVO,
> > > > > > > > > > > > the
> > > > > > > > > > > > 'this'
> > > > > > > > > > > > should really be resolved to '&a'.
> > > > > > > > > > > 
> > > > > > > > > > > > It seems to me that the right approach would be to
> > > > > > > > > > > > immediately
> > > > > > > > > > > > resolve
> > > > > > > > > > > > the
> > > > > > > > > > > > PLACEHOLDER_EXPR to the correct target object during
> > > > > > > > > > > > evaluation
> > > > > > > > > > > > of
> > > > > > > > > > > > 'foo()',
> > > > > > > > > > > > so
> > > > > > > > > > > > that we could use 'this' to access objects adjacent to
> > > > > > > > > > > > the
> > > > > > > > > > > > current
> > > > > > > > > > > > object in
> > > > > > > > > > > > the
> > > > > > > > > > > > ultimate storage location.  (I think #c2 of PR c++/94537
> > > > > > > > > > > > is
> > > > > > > > > > > > an
> > > > > > > > > > > > example
> > > > > > > > > > > > of
> > > > > > > > > > > > such
> > > > > > > > > > > > usage of 'this', which currently doesn't work.  But as
> > > > > > > > > > > > #c1
> > > > > > > > > > > > shows
> > > > > > > > > > > > we
> > > > > > > > > > > > don't
> > > > > > > > > > > > seem
> > > > > > > > > > > > to handle this case correctly in non-constexpr
> > > > > > > > > > > > initialization
> > > > > > > > > > > > either.)
> > > > > > > > > > > 
> > > > > > > > > > > As I commented in the PR, the standard doesn't require
> > > > > > > > > > > this to
> > > > > > > > > > > work
> > > > > > > > > > > because A
> > > > > > > > > > > is trivially copyable, and our ABI makes it impossible.
> > > > > > > > > > > But
> > > > > > > > > > > there's
> > > > > > > > > > > still a
> > > > > > > > > > > constexpr bug when we add
> > > > > > > > > > > 
> > > > > > > > > > > A() = default; A(const A&);
> > > > > > > > > > > 
> > > > > > > > > > > clang doesn't require the constructors to make this work
> > > > > > > > > > > for
> > > > > > > > > > > constant
> > > > > > > > > > > initialization, but similarly can't make it work for
> > > > > > > > > > > non-constant
> > > > > > > > > > > initialization.
> > > > > > > > > > 
> > > > > > > > > > That makes a lot of sense, thanks for the detailed
> > > > > > > > > > explanation.
> > > > > > > > > > 
> > > > > > > > > > > 
> > > > > > > > > > > > I haven't yet been able to make a solution using the
> > > > > > > > > > > > above
> > > > > > > > > > > > approach
> > > > > > > > > > > > work --
> > > > > > > > > > > > making sure we use the ultimate object instead of the
> > > > > > > > > > > > RESULT_DECL
> > > > > > > > > > > > whenever
> > > > > > > > > > > > we
> > > > > > > > > > > > access ctx->global->values is proving to be tricky and
> > > > > > > > > > > > subtle.
> > > > > > > > > > > 
> > > > > > > > > > > Do we need to go through ctx->global->values?  Would it
> > > > > > > > > > > work
> > > > > > > > > > > for
> > > > > > > > > > > the
> > > > > > > > > > > RESULT_DECL case in cxx_eval_constant_expression to go to
> > > > > > > > > > > straight
> > > > > > > > > > > to
> > > > > > > > > > > ctx->object or ctx->ctor instead?
> > > > > > > > > > 
> > > > > > > > > > I attempted that at some point, but IIRC we still end up not
> > > > > > > > > > resolving
> > > > > > > > > > some RESULT_DECLs because not all of them get processed
> > > > > > > > > > through
> > > > > > > > > > cxx_eval_constant_expression before we manipulate
> > > > > > > > > > ctx->global->values
> > > > > > > > > > with them.  I'll try this approach more carefully and report
> > > > > > > > > > back
> > > > > > > > > > with
> > > > > > > > > > more specifics.
> > > > > > > > > 
> > > > > > > > > It turns out that immediately reso

Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-13 Thread Jason Merrill via Gcc-patches

On 4/12/20 9:43 AM, Patrick Palka wrote:

On Sat, 11 Apr 2020, Jason Merrill wrote:


On 4/10/20 5:47 PM, Patrick Palka wrote:

On Fri, 10 Apr 2020, Jason Merrill wrote:

On 4/10/20 2:15 PM, Patrick Palka wrote:

On Fri, 10 Apr 2020, Patrick Palka wrote:


On Fri, 10 Apr 2020, Jason Merrill wrote:


On 4/10/20 1:04 PM, Patrick Palka wrote:

On Thu, 9 Apr 2020, Patrick Palka wrote:

On Thu, 9 Apr 2020, Jason Merrill wrote:


On 4/8/20 7:49 PM, Patrick Palka wrote:

When evaluating the initializer of 'a' in the following
example

   struct A { A *p = this; };
   constexpr A foo() { return {}; }
   constexpr A a = foo();

the PLACEHOLDER_EXPR for 'this' in the aggregate initializer
returned
by foo
gets resolved to the RESULT_DECL of foo.  But due to
guaranteed
RVO,
the
'this'
should really be resolved to '&a'.



It seems to me that the right approach would be to
immediately
resolve
the
PLACEHOLDER_EXPR to the correct target object during
evaluation
of
'foo()',
so
that we could use 'this' to access objects adjacent to the
current
object in
the
ultimate storage location.  (I think #c2 of PR c++/94537 is
an
example
of
such
usage of 'this', which currently doesn't work.  But as #c1
shows
we
don't
seem
to handle this case correctly in non-constexpr
initialization
either.)


As I commented in the PR, the standard doesn't require this to
work
because A
is trivially copyable, and our ABI makes it impossible.  But
there's
still a
constexpr bug when we add

A() = default; A(const A&);

clang doesn't require the constructors to make this work for
constant
initialization, but similarly can't make it work for
non-constant
initialization.


That makes a lot of sense, thanks for the detailed explanation.




I haven't yet been able to make a solution using the above
approach
work --
making sure we use the ultimate object instead of the
RESULT_DECL
whenever
we
access ctx->global->values is proving to be tricky and
subtle.


Do we need to go through ctx->global->values?  Would it work
for
the
RESULT_DECL case in cxx_eval_constant_expression to go to
straight
to
ctx->object or ctx->ctor instead?


I attempted that at some point, but IIRC we still end up not
resolving
some RESULT_DECLs because not all of them get processed through
cxx_eval_constant_expression before we manipulate
ctx->global->values
with them.  I'll try this approach more carefully and report
back
with
more specifics.


It turns out that immediately resolving RESULT_DECLs/'this' to the
ultimate ctx->object would not interact well with constexpr_call
caching:

  struct A { A() = default; A(const A&); A *ap = this; };
  constexpr A foo() { return {}; }
  constexpr A a = foo();
  constexpr A b = foo();
  static_assert(b.ap == &b); // fails

Evaluation of the first call to foo() returns {&a}, since we
resolve
'this' to &a due to guaranteed RVO, and we cache this result.
Evaluation of the second call to foo() just returns the cached
result
from the constexpr_call cache, and so we get {&a} again.

So it seems we would have to mark the result of a constexpr call
as
not
cacheable whenever this RVO applies during its evaluation, even
when
doing the RVO has no observable difference in the final result
(i.e.
the
constructor does not try to save the 'this' pointer).

Would the performance impact of disabling caching whenever RVO
applies
during constexpr call evaluation be worth it, or should we go with
something like my first patch which "almost works," and which
marks a
constexpr call as not cacheable only when we replace a RESULT_DECL
in
the result of the call?


Could we search through the result of the call for ctx->object and
cache
if we
don't find it?


Hmm, I think the result of the call could still depend on ctx->object
without ctx->object explicitly appearing in the result.  Consider the
following testcase:

 struct A {
   A() = default; A(const A&);
   constexpr A(const A *q) : d{this - p} { }


Oops sorry, that 'q' should be a 'p'.


   long d = 0;
 };

 constexpr A baz(const A *q) { return A(p); };


And same here.


 constexpr A a = baz(&a);
 constexpr A b = baz(&a); // no error

The initialization of 'b' should be ill-formed, but the result of the
first call to baz(&a) would be {0}, so we would cache it and then
reuse
the result when initializing 'b'.


Ah, true.  Can we still cache if we're initializing something that isn't
TREE_STATIC?


Hmm, we correctly compile the analogous non-TREE_STATIC testcase

  struct A {
A() = default; A(const A&);
constexpr A(const A *p) : d{this == p} { }
bool d;
  };

  constexpr A baz(const A *p) { return A(p); }

  void foo() {
constexpr A x = baz(&x);
constexpr A y = baz(&x);
static_assert(!y.d);
  }

because the calls 'baz(&x)' are considered to have non-constant arguments.


Unfortunately, we can come up with another trick to fool the constexpr_call
cache in the presence of RVO even in the 

Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-12 Thread Patrick Palka via Gcc-patches
On Sat, 11 Apr 2020, Jason Merrill wrote:

> On 4/10/20 5:47 PM, Patrick Palka wrote:
> > On Fri, 10 Apr 2020, Jason Merrill wrote:
> > > On 4/10/20 2:15 PM, Patrick Palka wrote:
> > > > On Fri, 10 Apr 2020, Patrick Palka wrote:
> > > > 
> > > > > On Fri, 10 Apr 2020, Jason Merrill wrote:
> > > > > 
> > > > > > On 4/10/20 1:04 PM, Patrick Palka wrote:
> > > > > > > On Thu, 9 Apr 2020, Patrick Palka wrote:
> > > > > > > > On Thu, 9 Apr 2020, Jason Merrill wrote:
> > > > > > > > 
> > > > > > > > > On 4/8/20 7:49 PM, Patrick Palka wrote:
> > > > > > > > > > When evaluating the initializer of 'a' in the following
> > > > > > > > > > example
> > > > > > > > > > 
> > > > > > > > > >   struct A { A *p = this; };
> > > > > > > > > >   constexpr A foo() { return {}; }
> > > > > > > > > >   constexpr A a = foo();
> > > > > > > > > > 
> > > > > > > > > > the PLACEHOLDER_EXPR for 'this' in the aggregate initializer
> > > > > > > > > > returned
> > > > > > > > > > by foo
> > > > > > > > > > gets resolved to the RESULT_DECL of foo.  But due to
> > > > > > > > > > guaranteed
> > > > > > > > > > RVO,
> > > > > > > > > > the
> > > > > > > > > > 'this'
> > > > > > > > > > should really be resolved to '&a'.
> > > > > > > > > 
> > > > > > > > > > It seems to me that the right approach would be to
> > > > > > > > > > immediately
> > > > > > > > > > resolve
> > > > > > > > > > the
> > > > > > > > > > PLACEHOLDER_EXPR to the correct target object during
> > > > > > > > > > evaluation
> > > > > > > > > > of
> > > > > > > > > > 'foo()',
> > > > > > > > > > so
> > > > > > > > > > that we could use 'this' to access objects adjacent to the
> > > > > > > > > > current
> > > > > > > > > > object in
> > > > > > > > > > the
> > > > > > > > > > ultimate storage location.  (I think #c2 of PR c++/94537 is
> > > > > > > > > > an
> > > > > > > > > > example
> > > > > > > > > > of
> > > > > > > > > > such
> > > > > > > > > > usage of 'this', which currently doesn't work.  But as #c1
> > > > > > > > > > shows
> > > > > > > > > > we
> > > > > > > > > > don't
> > > > > > > > > > seem
> > > > > > > > > > to handle this case correctly in non-constexpr
> > > > > > > > > > initialization
> > > > > > > > > > either.)
> > > > > > > > > 
> > > > > > > > > As I commented in the PR, the standard doesn't require this to
> > > > > > > > > work
> > > > > > > > > because A
> > > > > > > > > is trivially copyable, and our ABI makes it impossible.  But
> > > > > > > > > there's
> > > > > > > > > still a
> > > > > > > > > constexpr bug when we add
> > > > > > > > > 
> > > > > > > > > A() = default; A(const A&);
> > > > > > > > > 
> > > > > > > > > clang doesn't require the constructors to make this work for
> > > > > > > > > constant
> > > > > > > > > initialization, but similarly can't make it work for
> > > > > > > > > non-constant
> > > > > > > > > initialization.
> > > > > > > > 
> > > > > > > > That makes a lot of sense, thanks for the detailed explanation.
> > > > > > > > 
> > > > > > > > > 
> > > > > > > > > > I haven't yet been able to make a solution using the above
> > > > > > > > > > approach
> > > > > > > > > > work --
> > > > > > > > > > making sure we use the ultimate object instead of the
> > > > > > > > > > RESULT_DECL
> > > > > > > > > > whenever
> > > > > > > > > > we
> > > > > > > > > > access ctx->global->values is proving to be tricky and
> > > > > > > > > > subtle.
> > > > > > > > > 
> > > > > > > > > Do we need to go through ctx->global->values?  Would it work
> > > > > > > > > for
> > > > > > > > > the
> > > > > > > > > RESULT_DECL case in cxx_eval_constant_expression to go to
> > > > > > > > > straight
> > > > > > > > > to
> > > > > > > > > ctx->object or ctx->ctor instead?
> > > > > > > > 
> > > > > > > > I attempted that at some point, but IIRC we still end up not
> > > > > > > > resolving
> > > > > > > > some RESULT_DECLs because not all of them get processed through
> > > > > > > > cxx_eval_constant_expression before we manipulate
> > > > > > > > ctx->global->values
> > > > > > > > with them.  I'll try this approach more carefully and report
> > > > > > > > back
> > > > > > > > with
> > > > > > > > more specifics.
> > > > > > > 
> > > > > > > It turns out that immediately resolving RESULT_DECLs/'this' to the
> > > > > > > ultimate ctx->object would not interact well with constexpr_call
> > > > > > > caching:
> > > > > > > 
> > > > > > >  struct A { A() = default; A(const A&); A *ap = this; };
> > > > > > >  constexpr A foo() { return {}; }
> > > > > > >  constexpr A a = foo();
> > > > > > >  constexpr A b = foo();
> > > > > > >  static_assert(b.ap == &b); // fails
> > > > > > > 
> > > > > > > Evaluation of the first call to foo() returns {&a}, since we
> > > > > > > resolve
> > > > > > > 'this' to &a due to guaranteed RVO, and we cache this result.
> > > > > > > Evaluation of the second call to foo() just returns the cached
> > > > > > > result
> > > > > > > from the constexpr_call cache, and so we get

Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-10 Thread Jason Merrill via Gcc-patches

On 4/10/20 5:47 PM, Patrick Palka wrote:

On Fri, 10 Apr 2020, Jason Merrill wrote:

On 4/10/20 2:15 PM, Patrick Palka wrote:

On Fri, 10 Apr 2020, Patrick Palka wrote:


On Fri, 10 Apr 2020, Jason Merrill wrote:


On 4/10/20 1:04 PM, Patrick Palka wrote:

On Thu, 9 Apr 2020, Patrick Palka wrote:

On Thu, 9 Apr 2020, Jason Merrill wrote:


On 4/8/20 7:49 PM, Patrick Palka wrote:

When evaluating the initializer of 'a' in the following example

  struct A { A *p = this; };
  constexpr A foo() { return {}; }
  constexpr A a = foo();

the PLACEHOLDER_EXPR for 'this' in the aggregate initializer
returned
by foo
gets resolved to the RESULT_DECL of foo.  But due to guaranteed
RVO,
the
'this'
should really be resolved to '&a'.



It seems to me that the right approach would be to immediately
resolve
the
PLACEHOLDER_EXPR to the correct target object during evaluation
of
'foo()',
so
that we could use 'this' to access objects adjacent to the
current
object in
the
ultimate storage location.  (I think #c2 of PR c++/94537 is an
example
of
such
usage of 'this', which currently doesn't work.  But as #c1 shows
we
don't
seem
to handle this case correctly in non-constexpr initialization
either.)


As I commented in the PR, the standard doesn't require this to
work
because A
is trivially copyable, and our ABI makes it impossible.  But
there's
still a
constexpr bug when we add

A() = default; A(const A&);

clang doesn't require the constructors to make this work for
constant
initialization, but similarly can't make it work for non-constant
initialization.


That makes a lot of sense, thanks for the detailed explanation.




I haven't yet been able to make a solution using the above
approach
work --
making sure we use the ultimate object instead of the
RESULT_DECL
whenever
we
access ctx->global->values is proving to be tricky and subtle.


Do we need to go through ctx->global->values?  Would it work for
the
RESULT_DECL case in cxx_eval_constant_expression to go to straight
to
ctx->object or ctx->ctor instead?


I attempted that at some point, but IIRC we still end up not
resolving
some RESULT_DECLs because not all of them get processed through
cxx_eval_constant_expression before we manipulate
ctx->global->values
with them.  I'll try this approach more carefully and report back
with
more specifics.


It turns out that immediately resolving RESULT_DECLs/'this' to the
ultimate ctx->object would not interact well with constexpr_call
caching:

 struct A { A() = default; A(const A&); A *ap = this; };
 constexpr A foo() { return {}; }
 constexpr A a = foo();
 constexpr A b = foo();
 static_assert(b.ap == &b); // fails

Evaluation of the first call to foo() returns {&a}, since we resolve
'this' to &a due to guaranteed RVO, and we cache this result.
Evaluation of the second call to foo() just returns the cached result
from the constexpr_call cache, and so we get {&a} again.

So it seems we would have to mark the result of a constexpr call as
not
cacheable whenever this RVO applies during its evaluation, even when
doing the RVO has no observable difference in the final result (i.e.
the
constructor does not try to save the 'this' pointer).

Would the performance impact of disabling caching whenever RVO applies
during constexpr call evaluation be worth it, or should we go with
something like my first patch which "almost works," and which marks a
constexpr call as not cacheable only when we replace a RESULT_DECL in
the result of the call?


Could we search through the result of the call for ctx->object and cache
if we
don't find it?


Hmm, I think the result of the call could still depend on ctx->object
without ctx->object explicitly appearing in the result.  Consider the
following testcase:

struct A {
  A() = default; A(const A&);
  constexpr A(const A *q) : d{this - p} { }


Oops sorry, that 'q' should be a 'p'.


  long d = 0;
};

constexpr A baz(const A *q) { return A(p); };


And same here.


constexpr A a = baz(&a);
constexpr A b = baz(&a); // no error

The initialization of 'b' should be ill-formed, but the result of the
first call to baz(&a) would be {0}, so we would cache it and then reuse
the result when initializing 'b'.


Ah, true.  Can we still cache if we're initializing something that isn't
TREE_STATIC?


Hmm, we correctly compile the analogous non-TREE_STATIC testcase

 struct A {
   A() = default; A(const A&);
   constexpr A(const A *p) : d{this == p} { }
   bool d;
 };

 constexpr A baz(const A *p) { return A(p); }

 void foo() {
   constexpr A x = baz(&x);
   constexpr A y = baz(&x);
   static_assert(!y.d);
 }

because the calls 'baz(&x)' are considered to have non-constant arguments.


Unfortunately, we can come up with another trick to fool the constexpr_call
cache in the presence of RVO even in the !TREE_STATIC case:

 struct B {
   B() = default; B(const B&);
   constexpr B(int) : q{!this[-1].q} {

Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-10 Thread Patrick Palka via Gcc-patches
On Fri, 10 Apr 2020, Jason Merrill wrote:
> On 4/10/20 2:15 PM, Patrick Palka wrote:
> > On Fri, 10 Apr 2020, Patrick Palka wrote:
> > 
> > > On Fri, 10 Apr 2020, Jason Merrill wrote:
> > > 
> > > > On 4/10/20 1:04 PM, Patrick Palka wrote:
> > > > > On Thu, 9 Apr 2020, Patrick Palka wrote:
> > > > > > On Thu, 9 Apr 2020, Jason Merrill wrote:
> > > > > > 
> > > > > > > On 4/8/20 7:49 PM, Patrick Palka wrote:
> > > > > > > > When evaluating the initializer of 'a' in the following example
> > > > > > > > 
> > > > > > > >  struct A { A *p = this; };
> > > > > > > >  constexpr A foo() { return {}; }
> > > > > > > >  constexpr A a = foo();
> > > > > > > > 
> > > > > > > > the PLACEHOLDER_EXPR for 'this' in the aggregate initializer
> > > > > > > > returned
> > > > > > > > by foo
> > > > > > > > gets resolved to the RESULT_DECL of foo.  But due to guaranteed
> > > > > > > > RVO,
> > > > > > > > the
> > > > > > > > 'this'
> > > > > > > > should really be resolved to '&a'.
> > > > > > > 
> > > > > > > > It seems to me that the right approach would be to immediately
> > > > > > > > resolve
> > > > > > > > the
> > > > > > > > PLACEHOLDER_EXPR to the correct target object during evaluation
> > > > > > > > of
> > > > > > > > 'foo()',
> > > > > > > > so
> > > > > > > > that we could use 'this' to access objects adjacent to the
> > > > > > > > current
> > > > > > > > object in
> > > > > > > > the
> > > > > > > > ultimate storage location.  (I think #c2 of PR c++/94537 is an
> > > > > > > > example
> > > > > > > > of
> > > > > > > > such
> > > > > > > > usage of 'this', which currently doesn't work.  But as #c1 shows
> > > > > > > > we
> > > > > > > > don't
> > > > > > > > seem
> > > > > > > > to handle this case correctly in non-constexpr initialization
> > > > > > > > either.)
> > > > > > > 
> > > > > > > As I commented in the PR, the standard doesn't require this to
> > > > > > > work
> > > > > > > because A
> > > > > > > is trivially copyable, and our ABI makes it impossible.  But
> > > > > > > there's
> > > > > > > still a
> > > > > > > constexpr bug when we add
> > > > > > > 
> > > > > > > A() = default; A(const A&);
> > > > > > > 
> > > > > > > clang doesn't require the constructors to make this work for
> > > > > > > constant
> > > > > > > initialization, but similarly can't make it work for non-constant
> > > > > > > initialization.
> > > > > > 
> > > > > > That makes a lot of sense, thanks for the detailed explanation.
> > > > > > 
> > > > > > > 
> > > > > > > > I haven't yet been able to make a solution using the above
> > > > > > > > approach
> > > > > > > > work --
> > > > > > > > making sure we use the ultimate object instead of the
> > > > > > > > RESULT_DECL
> > > > > > > > whenever
> > > > > > > > we
> > > > > > > > access ctx->global->values is proving to be tricky and subtle.
> > > > > > > 
> > > > > > > Do we need to go through ctx->global->values?  Would it work for
> > > > > > > the
> > > > > > > RESULT_DECL case in cxx_eval_constant_expression to go to straight
> > > > > > > to
> > > > > > > ctx->object or ctx->ctor instead?
> > > > > > 
> > > > > > I attempted that at some point, but IIRC we still end up not
> > > > > > resolving
> > > > > > some RESULT_DECLs because not all of them get processed through
> > > > > > cxx_eval_constant_expression before we manipulate
> > > > > > ctx->global->values
> > > > > > with them.  I'll try this approach more carefully and report back
> > > > > > with
> > > > > > more specifics.
> > > > > 
> > > > > It turns out that immediately resolving RESULT_DECLs/'this' to the
> > > > > ultimate ctx->object would not interact well with constexpr_call
> > > > > caching:
> > > > > 
> > > > > struct A { A() = default; A(const A&); A *ap = this; };
> > > > > constexpr A foo() { return {}; }
> > > > > constexpr A a = foo();
> > > > > constexpr A b = foo();
> > > > > static_assert(b.ap == &b); // fails
> > > > > 
> > > > > Evaluation of the first call to foo() returns {&a}, since we resolve
> > > > > 'this' to &a due to guaranteed RVO, and we cache this result.
> > > > > Evaluation of the second call to foo() just returns the cached result
> > > > > from the constexpr_call cache, and so we get {&a} again.
> > > > > 
> > > > > So it seems we would have to mark the result of a constexpr call as
> > > > > not
> > > > > cacheable whenever this RVO applies during its evaluation, even when
> > > > > doing the RVO has no observable difference in the final result (i.e.
> > > > > the
> > > > > constructor does not try to save the 'this' pointer).
> > > > > 
> > > > > Would the performance impact of disabling caching whenever RVO applies
> > > > > during constexpr call evaluation be worth it, or should we go with
> > > > > something like my first patch which "almost works," and which marks a
> > > > > constexpr call as not cacheable only when we replace a RESULT_DECL in
> > > > > the result of the call?
> > > > 
> > > > Could we search through the result o

Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-10 Thread Jason Merrill via Gcc-patches

On 4/10/20 2:15 PM, Patrick Palka wrote:

On Fri, 10 Apr 2020, Patrick Palka wrote:


On Fri, 10 Apr 2020, Jason Merrill wrote:


On 4/10/20 1:04 PM, Patrick Palka wrote:

On Thu, 9 Apr 2020, Patrick Palka wrote:

On Thu, 9 Apr 2020, Jason Merrill wrote:


On 4/8/20 7:49 PM, Patrick Palka wrote:

When evaluating the initializer of 'a' in the following example

 struct A { A *p = this; };
 constexpr A foo() { return {}; }
 constexpr A a = foo();

the PLACEHOLDER_EXPR for 'this' in the aggregate initializer returned
by foo
gets resolved to the RESULT_DECL of foo.  But due to guaranteed RVO,
the
'this'
should really be resolved to '&a'.



It seems to me that the right approach would be to immediately resolve
the
PLACEHOLDER_EXPR to the correct target object during evaluation of
'foo()',
so
that we could use 'this' to access objects adjacent to the current
object in
the
ultimate storage location.  (I think #c2 of PR c++/94537 is an example
of
such
usage of 'this', which currently doesn't work.  But as #c1 shows we
don't
seem
to handle this case correctly in non-constexpr initialization either.)


As I commented in the PR, the standard doesn't require this to work
because A
is trivially copyable, and our ABI makes it impossible.  But there's
still a
constexpr bug when we add

A() = default; A(const A&);

clang doesn't require the constructors to make this work for constant
initialization, but similarly can't make it work for non-constant
initialization.


That makes a lot of sense, thanks for the detailed explanation.




I haven't yet been able to make a solution using the above approach
work --
making sure we use the ultimate object instead of the RESULT_DECL
whenever
we
access ctx->global->values is proving to be tricky and subtle.


Do we need to go through ctx->global->values?  Would it work for the
RESULT_DECL case in cxx_eval_constant_expression to go to straight to
ctx->object or ctx->ctor instead?


I attempted that at some point, but IIRC we still end up not resolving
some RESULT_DECLs because not all of them get processed through
cxx_eval_constant_expression before we manipulate ctx->global->values
with them.  I'll try this approach more carefully and report back with
more specifics.


It turns out that immediately resolving RESULT_DECLs/'this' to the
ultimate ctx->object would not interact well with constexpr_call
caching:

struct A { A() = default; A(const A&); A *ap = this; };
constexpr A foo() { return {}; }
constexpr A a = foo();
constexpr A b = foo();
static_assert(b.ap == &b); // fails

Evaluation of the first call to foo() returns {&a}, since we resolve
'this' to &a due to guaranteed RVO, and we cache this result.
Evaluation of the second call to foo() just returns the cached result
from the constexpr_call cache, and so we get {&a} again.

So it seems we would have to mark the result of a constexpr call as not
cacheable whenever this RVO applies during its evaluation, even when
doing the RVO has no observable difference in the final result (i.e. the
constructor does not try to save the 'this' pointer).

Would the performance impact of disabling caching whenever RVO applies
during constexpr call evaluation be worth it, or should we go with
something like my first patch which "almost works," and which marks a
constexpr call as not cacheable only when we replace a RESULT_DECL in
the result of the call?


Could we search through the result of the call for ctx->object and cache if we
don't find it?


Hmm, I think the result of the call could still depend on ctx->object
without ctx->object explicitly appearing in the result.  Consider the
following testcase:

   struct A {
 A() = default; A(const A&);
 constexpr A(const A *q) : d{this - p} { }


Oops sorry, that 'q' should be a 'p'.


 long d = 0;
   };

   constexpr A baz(const A *q) { return A(p); };


And same here.


   constexpr A a = baz(&a);
   constexpr A b = baz(&a); // no error

The initialization of 'b' should be ill-formed, but the result of the
first call to baz(&a) would be {0}, so we would cache it and then reuse
the result when initializing 'b'.


Ah, true.  Can we still cache if we're initializing something that isn't 
TREE_STATIC?


Jason



Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-10 Thread Patrick Palka via Gcc-patches
On Fri, 10 Apr 2020, Patrick Palka wrote:

> On Fri, 10 Apr 2020, Jason Merrill wrote:
> 
> > On 4/10/20 1:04 PM, Patrick Palka wrote:
> > > On Thu, 9 Apr 2020, Patrick Palka wrote:
> > > > On Thu, 9 Apr 2020, Jason Merrill wrote:
> > > > 
> > > > > On 4/8/20 7:49 PM, Patrick Palka wrote:
> > > > > > When evaluating the initializer of 'a' in the following example
> > > > > > 
> > > > > > struct A { A *p = this; };
> > > > > > constexpr A foo() { return {}; }
> > > > > > constexpr A a = foo();
> > > > > > 
> > > > > > the PLACEHOLDER_EXPR for 'this' in the aggregate initializer 
> > > > > > returned
> > > > > > by foo
> > > > > > gets resolved to the RESULT_DECL of foo.  But due to guaranteed RVO,
> > > > > > the
> > > > > > 'this'
> > > > > > should really be resolved to '&a'.
> > > > > 
> > > > > > It seems to me that the right approach would be to immediately 
> > > > > > resolve
> > > > > > the
> > > > > > PLACEHOLDER_EXPR to the correct target object during evaluation of
> > > > > > 'foo()',
> > > > > > so
> > > > > > that we could use 'this' to access objects adjacent to the current
> > > > > > object in
> > > > > > the
> > > > > > ultimate storage location.  (I think #c2 of PR c++/94537 is an 
> > > > > > example
> > > > > > of
> > > > > > such
> > > > > > usage of 'this', which currently doesn't work.  But as #c1 shows we
> > > > > > don't
> > > > > > seem
> > > > > > to handle this case correctly in non-constexpr initialization 
> > > > > > either.)
> > > > > 
> > > > > As I commented in the PR, the standard doesn't require this to work
> > > > > because A
> > > > > is trivially copyable, and our ABI makes it impossible.  But there's
> > > > > still a
> > > > > constexpr bug when we add
> > > > > 
> > > > > A() = default; A(const A&);
> > > > > 
> > > > > clang doesn't require the constructors to make this work for constant
> > > > > initialization, but similarly can't make it work for non-constant
> > > > > initialization.
> > > > 
> > > > That makes a lot of sense, thanks for the detailed explanation.
> > > > 
> > > > > 
> > > > > > I haven't yet been able to make a solution using the above approach
> > > > > > work --
> > > > > > making sure we use the ultimate object instead of the RESULT_DECL
> > > > > > whenever
> > > > > > we
> > > > > > access ctx->global->values is proving to be tricky and subtle.
> > > > > 
> > > > > Do we need to go through ctx->global->values?  Would it work for the
> > > > > RESULT_DECL case in cxx_eval_constant_expression to go to straight to
> > > > > ctx->object or ctx->ctor instead?
> > > > 
> > > > I attempted that at some point, but IIRC we still end up not resolving
> > > > some RESULT_DECLs because not all of them get processed through
> > > > cxx_eval_constant_expression before we manipulate ctx->global->values
> > > > with them.  I'll try this approach more carefully and report back with
> > > > more specifics.
> > > 
> > > It turns out that immediately resolving RESULT_DECLs/'this' to the
> > > ultimate ctx->object would not interact well with constexpr_call
> > > caching:
> > > 
> > >struct A { A() = default; A(const A&); A *ap = this; };
> > >constexpr A foo() { return {}; }
> > >constexpr A a = foo();
> > >constexpr A b = foo();
> > >static_assert(b.ap == &b); // fails
> > > 
> > > Evaluation of the first call to foo() returns {&a}, since we resolve
> > > 'this' to &a due to guaranteed RVO, and we cache this result.
> > > Evaluation of the second call to foo() just returns the cached result
> > > from the constexpr_call cache, and so we get {&a} again.
> > > 
> > > So it seems we would have to mark the result of a constexpr call as not
> > > cacheable whenever this RVO applies during its evaluation, even when
> > > doing the RVO has no observable difference in the final result (i.e. the
> > > constructor does not try to save the 'this' pointer).
> > > 
> > > Would the performance impact of disabling caching whenever RVO applies
> > > during constexpr call evaluation be worth it, or should we go with
> > > something like my first patch which "almost works," and which marks a
> > > constexpr call as not cacheable only when we replace a RESULT_DECL in
> > > the result of the call?
> > 
> > Could we search through the result of the call for ctx->object and cache if 
> > we
> > don't find it?
> 
> Hmm, I think the result of the call could still depend on ctx->object
> without ctx->object explicitly appearing in the result.  Consider the
> following testcase:
> 
>   struct A {
> A() = default; A(const A&);
> constexpr A(const A *q) : d{this - p} { }

Oops sorry, that 'q' should be a 'p'.

> long d = 0;
>   };
> 
>   constexpr A baz(const A *q) { return A(p); };

And same here.

>   constexpr A a = baz(&a);
>   constexpr A b = baz(&a); // no error
> 
> The initialization of 'b' should be ill-formed, but the result of the
> first call to baz(&a) would be {0}, so we would cache it and then reuse
> the result when initial

Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-10 Thread Patrick Palka via Gcc-patches
On Fri, 10 Apr 2020, Jason Merrill wrote:

> On 4/10/20 1:04 PM, Patrick Palka wrote:
> > On Thu, 9 Apr 2020, Patrick Palka wrote:
> > > On Thu, 9 Apr 2020, Jason Merrill wrote:
> > > 
> > > > On 4/8/20 7:49 PM, Patrick Palka wrote:
> > > > > When evaluating the initializer of 'a' in the following example
> > > > > 
> > > > > struct A { A *p = this; };
> > > > > constexpr A foo() { return {}; }
> > > > > constexpr A a = foo();
> > > > > 
> > > > > the PLACEHOLDER_EXPR for 'this' in the aggregate initializer returned
> > > > > by foo
> > > > > gets resolved to the RESULT_DECL of foo.  But due to guaranteed RVO,
> > > > > the
> > > > > 'this'
> > > > > should really be resolved to '&a'.
> > > > 
> > > > > It seems to me that the right approach would be to immediately resolve
> > > > > the
> > > > > PLACEHOLDER_EXPR to the correct target object during evaluation of
> > > > > 'foo()',
> > > > > so
> > > > > that we could use 'this' to access objects adjacent to the current
> > > > > object in
> > > > > the
> > > > > ultimate storage location.  (I think #c2 of PR c++/94537 is an example
> > > > > of
> > > > > such
> > > > > usage of 'this', which currently doesn't work.  But as #c1 shows we
> > > > > don't
> > > > > seem
> > > > > to handle this case correctly in non-constexpr initialization either.)
> > > > 
> > > > As I commented in the PR, the standard doesn't require this to work
> > > > because A
> > > > is trivially copyable, and our ABI makes it impossible.  But there's
> > > > still a
> > > > constexpr bug when we add
> > > > 
> > > > A() = default; A(const A&);
> > > > 
> > > > clang doesn't require the constructors to make this work for constant
> > > > initialization, but similarly can't make it work for non-constant
> > > > initialization.
> > > 
> > > That makes a lot of sense, thanks for the detailed explanation.
> > > 
> > > > 
> > > > > I haven't yet been able to make a solution using the above approach
> > > > > work --
> > > > > making sure we use the ultimate object instead of the RESULT_DECL
> > > > > whenever
> > > > > we
> > > > > access ctx->global->values is proving to be tricky and subtle.
> > > > 
> > > > Do we need to go through ctx->global->values?  Would it work for the
> > > > RESULT_DECL case in cxx_eval_constant_expression to go to straight to
> > > > ctx->object or ctx->ctor instead?
> > > 
> > > I attempted that at some point, but IIRC we still end up not resolving
> > > some RESULT_DECLs because not all of them get processed through
> > > cxx_eval_constant_expression before we manipulate ctx->global->values
> > > with them.  I'll try this approach more carefully and report back with
> > > more specifics.
> > 
> > It turns out that immediately resolving RESULT_DECLs/'this' to the
> > ultimate ctx->object would not interact well with constexpr_call
> > caching:
> > 
> >struct A { A() = default; A(const A&); A *ap = this; };
> >constexpr A foo() { return {}; }
> >constexpr A a = foo();
> >constexpr A b = foo();
> >static_assert(b.ap == &b); // fails
> > 
> > Evaluation of the first call to foo() returns {&a}, since we resolve
> > 'this' to &a due to guaranteed RVO, and we cache this result.
> > Evaluation of the second call to foo() just returns the cached result
> > from the constexpr_call cache, and so we get {&a} again.
> > 
> > So it seems we would have to mark the result of a constexpr call as not
> > cacheable whenever this RVO applies during its evaluation, even when
> > doing the RVO has no observable difference in the final result (i.e. the
> > constructor does not try to save the 'this' pointer).
> > 
> > Would the performance impact of disabling caching whenever RVO applies
> > during constexpr call evaluation be worth it, or should we go with
> > something like my first patch which "almost works," and which marks a
> > constexpr call as not cacheable only when we replace a RESULT_DECL in
> > the result of the call?
> 
> Could we search through the result of the call for ctx->object and cache if we
> don't find it?

Hmm, I think the result of the call could still depend on ctx->object
without ctx->object explicitly appearing in the result.  Consider the
following testcase:

  struct A {
A() = default; A(const A&);
constexpr A(const A *q) : d{this - p} { }
long d = 0;
  };

  constexpr A baz(const A *q) { return A(p); };
  constexpr A a = baz(&a);
  constexpr A b = baz(&a); // no error

The initialization of 'b' should be ill-formed, but the result of the
first call to baz(&a) would be {0}, so we would cache it and then reuse
the result when initializing 'b'.



Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-10 Thread Jason Merrill via Gcc-patches

On 4/10/20 1:04 PM, Patrick Palka wrote:

On Thu, 9 Apr 2020, Patrick Palka wrote:

On Thu, 9 Apr 2020, Jason Merrill wrote:


On 4/8/20 7:49 PM, Patrick Palka wrote:

When evaluating the initializer of 'a' in the following example

struct A { A *p = this; };
constexpr A foo() { return {}; }
constexpr A a = foo();

the PLACEHOLDER_EXPR for 'this' in the aggregate initializer returned by foo
gets resolved to the RESULT_DECL of foo.  But due to guaranteed RVO, the
'this'
should really be resolved to '&a'.



It seems to me that the right approach would be to immediately resolve the
PLACEHOLDER_EXPR to the correct target object during evaluation of 'foo()',
so
that we could use 'this' to access objects adjacent to the current object in
the
ultimate storage location.  (I think #c2 of PR c++/94537 is an example of
such
usage of 'this', which currently doesn't work.  But as #c1 shows we don't
seem
to handle this case correctly in non-constexpr initialization either.)


As I commented in the PR, the standard doesn't require this to work because A
is trivially copyable, and our ABI makes it impossible.  But there's still a
constexpr bug when we add

A() = default; A(const A&);

clang doesn't require the constructors to make this work for constant
initialization, but similarly can't make it work for non-constant
initialization.


That makes a lot of sense, thanks for the detailed explanation.




I haven't yet been able to make a solution using the above approach work --
making sure we use the ultimate object instead of the RESULT_DECL whenever
we
access ctx->global->values is proving to be tricky and subtle.


Do we need to go through ctx->global->values?  Would it work for the
RESULT_DECL case in cxx_eval_constant_expression to go to straight to
ctx->object or ctx->ctor instead?


I attempted that at some point, but IIRC we still end up not resolving
some RESULT_DECLs because not all of them get processed through
cxx_eval_constant_expression before we manipulate ctx->global->values
with them.  I'll try this approach more carefully and report back with
more specifics.


It turns out that immediately resolving RESULT_DECLs/'this' to the
ultimate ctx->object would not interact well with constexpr_call
caching:

   struct A { A() = default; A(const A&); A *ap = this; };
   constexpr A foo() { return {}; }
   constexpr A a = foo();
   constexpr A b = foo();
   static_assert(b.ap == &b); // fails

Evaluation of the first call to foo() returns {&a}, since we resolve
'this' to &a due to guaranteed RVO, and we cache this result.
Evaluation of the second call to foo() just returns the cached result
from the constexpr_call cache, and so we get {&a} again.

So it seems we would have to mark the result of a constexpr call as not
cacheable whenever this RVO applies during its evaluation, even when
doing the RVO has no observable difference in the final result (i.e. the
constructor does not try to save the 'this' pointer).

Would the performance impact of disabling caching whenever RVO applies
during constexpr call evaluation be worth it, or should we go with
something like my first patch which "almost works," and which marks a
constexpr call as not cacheable only when we replace a RESULT_DECL in
the result of the call?


Could we search through the result of the call for ctx->object and cache 
if we don't find it?


Jason



Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-10 Thread Patrick Palka via Gcc-patches
On Thu, 9 Apr 2020, Patrick Palka wrote:
> On Thu, 9 Apr 2020, Jason Merrill wrote:
> 
> > On 4/8/20 7:49 PM, Patrick Palka wrote:
> > > When evaluating the initializer of 'a' in the following example
> > > 
> > >struct A { A *p = this; };
> > >constexpr A foo() { return {}; }
> > >constexpr A a = foo();
> > > 
> > > the PLACEHOLDER_EXPR for 'this' in the aggregate initializer returned by 
> > > foo
> > > gets resolved to the RESULT_DECL of foo.  But due to guaranteed RVO, the
> > > 'this'
> > > should really be resolved to '&a'.
> > 
> > > It seems to me that the right approach would be to immediately resolve the
> > > PLACEHOLDER_EXPR to the correct target object during evaluation of 
> > > 'foo()',
> > > so
> > > that we could use 'this' to access objects adjacent to the current object 
> > > in
> > > the
> > > ultimate storage location.  (I think #c2 of PR c++/94537 is an example of
> > > such
> > > usage of 'this', which currently doesn't work.  But as #c1 shows we don't
> > > seem
> > > to handle this case correctly in non-constexpr initialization either.)
> > 
> > As I commented in the PR, the standard doesn't require this to work because 
> > A
> > is trivially copyable, and our ABI makes it impossible.  But there's still a
> > constexpr bug when we add
> > 
> > A() = default; A(const A&);
> > 
> > clang doesn't require the constructors to make this work for constant
> > initialization, but similarly can't make it work for non-constant
> > initialization.
> 
> That makes a lot of sense, thanks for the detailed explanation.
> 
> > 
> > > I haven't yet been able to make a solution using the above approach work 
> > > --
> > > making sure we use the ultimate object instead of the RESULT_DECL whenever
> > > we
> > > access ctx->global->values is proving to be tricky and subtle.
> > 
> > Do we need to go through ctx->global->values?  Would it work for the
> > RESULT_DECL case in cxx_eval_constant_expression to go to straight to
> > ctx->object or ctx->ctor instead?
> 
> I attempted that at some point, but IIRC we still end up not resolving
> some RESULT_DECLs because not all of them get processed through
> cxx_eval_constant_expression before we manipulate ctx->global->values
> with them.  I'll try this approach more carefully and report back with
> more specifics.

It turns out that immediately resolving RESULT_DECLs/'this' to the
ultimate ctx->object would not interact well with constexpr_call
caching:

  struct A { A() = default; A(const A&); A *ap = this; };
  constexpr A foo() { return {}; }
  constexpr A a = foo();
  constexpr A b = foo();
  static_assert(b.ap == &b); // fails

Evaluation of the first call to foo() returns {&a}, since we resolve
'this' to &a due to guaranteed RVO, and we cache this result.
Evaluation of the second call to foo() just returns the cached result
from the constexpr_call cache, and so we get {&a} again.

So it seems we would have to mark the result of a constexpr call as not
cacheable whenever this RVO applies during its evaluation, even when
doing the RVO has no observable difference in the final result (i.e. the
constructor does not try to save the 'this' pointer).

Would the performance impact of disabling caching whenever RVO applies
during constexpr call evaluation be worth it, or should we go with
something like my first patch which "almost works," and which marks a
constexpr call as not cacheable only when we replace a RESULT_DECL in
the result of the call?



Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-09 Thread Patrick Palka via Gcc-patches
On Thu, 9 Apr 2020, Jason Merrill wrote:

> On 4/8/20 7:49 PM, Patrick Palka wrote:
> > When evaluating the initializer of 'a' in the following example
> > 
> >struct A { A *p = this; };
> >constexpr A foo() { return {}; }
> >constexpr A a = foo();
> > 
> > the PLACEHOLDER_EXPR for 'this' in the aggregate initializer returned by foo
> > gets resolved to the RESULT_DECL of foo.  But due to guaranteed RVO, the
> > 'this'
> > should really be resolved to '&a'.
> 
> > It seems to me that the right approach would be to immediately resolve the
> > PLACEHOLDER_EXPR to the correct target object during evaluation of 'foo()',
> > so
> > that we could use 'this' to access objects adjacent to the current object in
> > the
> > ultimate storage location.  (I think #c2 of PR c++/94537 is an example of
> > such
> > usage of 'this', which currently doesn't work.  But as #c1 shows we don't
> > seem
> > to handle this case correctly in non-constexpr initialization either.)
> 
> As I commented in the PR, the standard doesn't require this to work because A
> is trivially copyable, and our ABI makes it impossible.  But there's still a
> constexpr bug when we add
> 
> A() = default; A(const A&);
> 
> clang doesn't require the constructors to make this work for constant
> initialization, but similarly can't make it work for non-constant
> initialization.

That makes a lot of sense, thanks for the detailed explanation.

> 
> > I haven't yet been able to make a solution using the above approach work --
> > making sure we use the ultimate object instead of the RESULT_DECL whenever
> > we
> > access ctx->global->values is proving to be tricky and subtle.
> 
> Do we need to go through ctx->global->values?  Would it work for the
> RESULT_DECL case in cxx_eval_constant_expression to go to straight to
> ctx->object or ctx->ctor instead?

I attempted that at some point, but IIRC we still end up not resolving
some RESULT_DECLs because not all of them get processed through
cxx_eval_constant_expression before we manipulate ctx->global->values
with them.  I'll try this approach more carefully and report back with
more specifics.



Re: [PATCH] c++: Stray RESULT_DECLs in result of constexpr function call [PR94034]

2020-04-09 Thread Jason Merrill via Gcc-patches

On 4/8/20 7:49 PM, Patrick Palka wrote:

When evaluating the initializer of 'a' in the following example

   struct A { A *p = this; };
   constexpr A foo() { return {}; }
   constexpr A a = foo();

the PLACEHOLDER_EXPR for 'this' in the aggregate initializer returned by foo
gets resolved to the RESULT_DECL of foo.  But due to guaranteed RVO, the 'this'
should really be resolved to '&a'.



It seems to me that the right approach would be to immediately resolve the
PLACEHOLDER_EXPR to the correct target object during evaluation of 'foo()', so
that we could use 'this' to access objects adjacent to the current object in the
ultimate storage location.  (I think #c2 of PR c++/94537 is an example of such
usage of 'this', which currently doesn't work.  But as #c1 shows we don't seem
to handle this case correctly in non-constexpr initialization either.)


As I commented in the PR, the standard doesn't require this to work 
because A is trivially copyable, and our ABI makes it impossible.  But 
there's still a constexpr bug when we add


A() = default; A(const A&);

clang doesn't require the constructors to make this work for constant 
initialization, but similarly can't make it work for non-constant 
initialization.



I haven't yet been able to make a solution using the above approach work --
making sure we use the ultimate object instead of the RESULT_DECL whenever we
access ctx->global->values is proving to be tricky and subtle.


Do we need to go through ctx->global->values?  Would it work for the 
RESULT_DECL case in cxx_eval_constant_expression to go to straight to 
ctx->object or ctx->ctor instead?


Jason