[Bug c++/111284] [11/12/13/14 Regression] Some passing-by-value parameters are mishandled since GCC 9, affecting libstdc++'s constexpr std::string

2024-04-25 Thread cvs-commit at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111284

--- Comment #10 from GCC Commits  ---
The master branch has been updated by Jakub Jelinek :

https://gcc.gnu.org/g:f541757ba4632e204169dd08a5f10c782199af42

commit r14-10134-gf541757ba4632e204169dd08a5f10c782199af42
Author: Jakub Jelinek 
Date:   Thu Apr 25 20:45:04 2024 +0200

c++: Fix constexpr evaluation of parameters passed by invisible reference
[PR111284]

My r9-6136 changes to make a copy of constexpr function bodies before
genericization modifies it broke the constant evaluation of non-POD
arguments passed by value.
In the callers such arguments are passed as reference to usually a
TARGET_EXPR, but on the callee side until genericization they are just
direct uses of a PARM_DECL with some class type.
In cxx_bind_parameters_in_call I've used convert_from_reference to
pretend it is passed by value and then cxx_eval_constant_expression
is called there and evaluates that as an rvalue, followed by
adjust_temp_type if the types don't match exactly (e.g. const Foo
argument and passing to it reference to Foo TARGET_EXPR).

The reason this doesn't work is that when the TARGET_EXPR in the caller
is constant initialized, this for it is the address of the
TARGET_EXPR_SLOT,
but if the code later on pretends the PARM_DECL is just initialized to the
rvalue of the constant evaluation of the TARGET_EXPR, it is as if there
is a bitwise copy of the TARGET_EXPR to the callee, so this in the callee
is then address of the PARM_DECL in the callee.

The following patch attempts to fix that by constexpr evaluation of such
arguments in the caller as an lvalue instead of rvalue, and on the callee
side when seeing such a PARM_DECL, if we want an lvalue, lookup the value
(lvalue) saved in ctx->globals (if any), and if wanting an rvalue,
recursing with vc_prvalue on the looked up value (because it is there
as an lvalue, nor rvalue).

adjust_temp_type doesn't work for lvalues of non-scalarish types, for
such types it relies on changing the type of a CONSTRUCTOR, but on the
other side we know what we pass to the argument is addressable, so
the patch on type mismatch takes address of the argument value, casts
to reference to the desired type and dereferences it.

2024-04-25  Jakub Jelinek  

PR c++/111284
* constexpr.cc (cxx_bind_parameters_in_call): For PARM_DECLs with
TREE_ADDRESSABLE types use vc_glvalue rather than vc_prvalue for
cxx_eval_constant_expression and if it doesn't have the same
type as it should, cast the reference type to reference to type
before convert_from_reference and instead of adjust_temp_type
take address of the arg, cast to reference to type and then
convert_from_reference.
(cxx_eval_constant_expression) : For lval case
on parameters with TREE_ADDRESSABLE types lookup result in
ctx->globals if possible.  Otherwise if lookup in ctx->globals
was successful for parameter with TREE_ADDRESSABLE type,
recurse with vc_prvalue on the returned value.

* g++.dg/cpp1z/constexpr-111284.C: New test.
* g++.dg/cpp1y/constexpr-lifetime7.C: Expect one error on a
different
line.

[Bug c++/111284] [11/12/13/14 Regression] Some passing-by-value parameters are mishandled since GCC 9, affecting libstdc++'s constexpr std::string

2024-03-11 Thread ppalka at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111284

--- Comment #9 from Patrick Palka  ---
(In reply to Jakub Jelinek from comment #8)
> Created attachment 57648 [details]
> gcc14-pr111284.patch
> 
> So, I've tried to fix this by constexpr evaluating the arguments passed to
> PARM_DECLs with TREE_ADDRESSABLE types in the caller as lvalues rather than
> rvaluea and later, if we try to evaluate the PARM_DECL in the callee as lval,
> lookup the value and use that, if it is rval constexpr evaluate again as
> rvalue.
> There is a complication for qualified type, say if the argument is const in
> the callee and caller is passing reference to non-const, adjust_temp_type
> can't handle that when it isn't a rvalue.
Interesting, hopefully this fixes the std::string testcases in PR111258 and
related PRs?

And perhaps the following augmented testcase from this PR with a constexpr dtor
that checks valid():

void non_constant();

struct self_locator {
self_locator() = default;
constexpr self_locator(const self_locator&) noexcept : this_{this} {}
constexpr self_locator& operator=(const self_locator&) noexcept { return
*this; }

constexpr bool valid() const noexcept { return this_ == this; }
constexpr ~self_locator() { if (!valid()) non_constant(); }

self_locator *this_ = this;
};

constexpr bool demonstrator(self_locator x) noexcept
{
return x.valid();
}

static_assert(demonstrator(self_locator{}), "");
static_assert([](self_locator x){ return x.valid(); }(self_locator{}), "");

[Bug c++/111284] [11/12/13/14 Regression] Some passing-by-value parameters are mishandled since GCC 9, affecting libstdc++'s constexpr std::string

2024-03-07 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111284

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

So, I've tried to fix this by constexpr evaluating the arguments passed to
PARM_DECLs with TREE_ADDRESSABLE types in the caller as lvalues rather than
rvaluea and later, if we try to evaluate the PARM_DECL in the callee as lval,
lookup the value and use that, if it is rval constexpr evaluate again as
rvalue.
There is a complication for qualified type, say if the argument is const in the
callee and caller is passing reference to non-const, adjust_temp_type can't
handle that when it isn't a rvalue.