Age | Commit message (Collapse) | Author | Files | Lines |
|
The recent libstdc++ changes caused lots of libstdc++-v3 tests FAILs
on i686-linux, all of them in the same spot during constexpr evaluation
of a recursive _S_gcd call.
The problem is yet another hash_map that used the default hasing of
tree keys through pointer hashing which is preserved across PCH write/read.
During PCH handling, the addresses of GC objects are changed, which means
that the hash values of the keys in such hash tables change without those
hash tables being rehashed. Which in the fundef_copies_table case usually
means we just don't find a copy of a FUNCTION_DECL body for recursive uses
and start from scratch. But when the hash table keeps growing, the "dead"
elements in the hash table can sometimes reappear and break things.
In particular what I saw under the debugger is when the fundef_copies_table
hash map has been used on the outer _S_gcd call, it didn't find an entry for
it, so returned a slot with *slot == NULL, which is treated as that the
function itself is used directly (i.e. no recursion), but that addition of
a hash table slot caused the recursive _S_gcd call to actually find
something in the hash table, unfortunately not the new *slot == NULL spot,
but a different one from the pre-PCH streaming which contained the returned
toplevel (non-recursive) call entry for it, which means that for the
recursive _S_gcd call we actually used the same trees as for the outer ones
rather than a copy of those, which breaks constexpr evaluation.
2020-09-03 Jakub Jelinek <jakub@redhat.com>
PR c++/96901
* tree.h (struct decl_tree_traits): New type.
(decl_tree_map): New typedef.
* constexpr.c (fundef_copies_table): Change type from
hash_map<tree, tree> * to decl_tree_map *.
|
|
As discussed in the PR, fold-const.c punts on floating point constant
evaluation if the result is inexact and -frounding-math is turned on.
/* Don't constant fold this floating point operation if the
result may dependent upon the run-time rounding mode and
flag_rounding_math is set, or if GCC's software emulation
is unable to accurately represent the result. */
if ((flag_rounding_math
|| (MODE_COMPOSITE_P (mode) && !flag_unsafe_math_optimizations))
&& (inexact || !real_identical (&result, &value)))
return NULL_TREE;
Jonathan said that we should be evaluating them anyway, e.g. conceptually
as if they are done with the default rounding mode before user had a chance
to change that, and e.g. in C in initializers it is also ignored.
In fact, fold-const.c for C initializers turns off various other options:
/* Perform constant folding and related simplification of initializer
expression EXPR. These behave identically to "fold_buildN" but ignore
potential run-time traps and exceptions that fold must preserve. */
int saved_signaling_nans = flag_signaling_nans;\
int saved_trapping_math = flag_trapping_math;\
int saved_rounding_math = flag_rounding_math;\
int saved_trapv = flag_trapv;\
int saved_folding_initializer = folding_initializer;\
flag_signaling_nans = 0;\
flag_trapping_math = 0;\
flag_rounding_math = 0;\
flag_trapv = 0;\
folding_initializer = 1;
flag_signaling_nans = saved_signaling_nans;\
flag_trapping_math = saved_trapping_math;\
flag_rounding_math = saved_rounding_math;\
flag_trapv = saved_trapv;\
folding_initializer = saved_folding_initializer;
So, shall cxx_eval_outermost_constant_expr instead turn off all those
options (then warning_sentinel wouldn't be the right thing to use, but given
the 8 or how many return stmts in cxx_eval_outermost_constant_expr, we'd
need a RAII class for this. Not sure about the folding_initializer, that
one is affecting complex multiplication and division constant evaluation
somehow.
2020-09-03 Jakub Jelinek <jakub@redhat.com>
PR c++/96862
* constexpr.c (cxx_eval_outermost_constant_expr): Temporarily disable
flag_rounding_math during manifestly constant evaluation.
* g++.dg/cpp1z/constexpr-96862.C: New test.
|
|
The following valid testcase is rejected, because cxx_eval_binary_expression
is called on the SPACESHIP_EXPR with lval = true, as the address of the
spaceship needs to be passed to a method call.
After recursing on the operands and calling genericize_spaceship which turns
it into a TARGET_EXPR with initialization, we call cxx_eval_constant_expression
on it which succeeds, but then we fall through into code that will
VERIFY_CONSTANT (r) which FAILs because it is an address of a variable. Rather
than avoiding that for lval = true and SPACESHIP_EXPR, the patch just tail
calls cxx_eval_constant_expression - I believe that call should perform all
the needed verifications.
2020-08-10 Jakub Jelinek <jakub@redhat.com>
PR c++/96497
* constexpr.c (cxx_eval_binary_expression): For SPACESHIP_EXPR, tail
call cxx_eval_constant_expression after genericize_spaceship to avoid
undesirable further VERIFY_CONSTANT.
* g++.dg/cpp2a/spaceship-constexpr3.C: New test.
|
|
In the first testcase below, expand_aggr_init_1 sets up t's default
constructor such that the ctor first zero-initializes the entire base b,
followed by calling b's default constructor, the latter of which just
default-initializes the array member b::m via a VEC_INIT_EXPR.
So upon constexpr evaluation of this latter VEC_INIT_EXPR, ctx->ctor is
nonempty due to the prior zero-initialization, and we proceed in
cxx_eval_vec_init to append new constructor_elts to the end of ctx->ctor
without first checking if a matching constructor_elt already exists.
This leads to ctx->ctor having two matching constructor_elts for each
index.
This patch fixes this issue by truncating a zero-initialized array
CONSTRUCTOR in cxx_eval_vec_init_1 before we begin appending array
elements to it. We propagate its zeroed out state during evaluation by
clearing CONSTRUCTOR_NO_CLEARING on each new appended aggregate element.
gcc/cp/ChangeLog:
PR c++/96282
* constexpr.c (cxx_eval_vec_init_1): Truncate ctx->ctor and
then clear CONSTRUCTOR_NO_CLEARING on each appended element
initializer if we're initializing a previously zero-initialized
array object.
gcc/testsuite/ChangeLog:
PR c++/96282
* g++.dg/cpp0x/constexpr-array26.C: New test.
* g++.dg/cpp0x/constexpr-array27.C: New test.
* g++.dg/cpp2a/constexpr-init18.C: New test.
Co-authored-by: Jason Merrill <jason@redhat.com>
|
|
In the testcase from the PR we're seeing excessive memory use (> 5GB)
during constexpr evaluation, almost all of which is due to the call to
decl_constant_value in the VAR_DECL/CONST_DECL branch of
cxx_eval_constant_expression. We reach here every time we evaluate an
ARRAY_REF of a constexpr VAR_DECL, and from there decl_constant_value
makes an unshared copy of the VAR_DECL's initializer. But unsharing
here is unnecessary because callers of cxx_eval_constant_expression
already unshare its result when necessary.
To fix this excessive unsharing, this patch adds a new defaulted
parameter unshare_p to decl_really_constant_value and
decl_constant_value so that callers can control whether to unshare.
As a simplification, we can also move the call to unshare_expr in
constant_value_1 outside of the loop, since doing unshare_expr on a
DECL_P is a no-op.
Now that we no longer unshare the result of decl_constant_value and
decl_really_constant_value from cxx_eval_constant_expression, memory use
during constexpr evaluation for the testcase from the PR falls from ~5GB
to 15MB according to -ftime-report.
gcc/cp/ChangeLog:
PR c++/96197
* constexpr.c (cxx_eval_constant_expression) <case CONST_DECL>:
Pass false to decl_constant_value and decl_really_constant_value
so that they don't unshare their result.
* cp-tree.h (decl_constant_value): New declaration with an added
bool parameter.
(decl_really_constant_value): Add bool parameter defaulting to
true to existing declaration.
* init.c (constant_value_1): Add bool parameter which controls
whether to unshare the initializer before returning. Call
unshare_expr at most once.
(scalar_constant_value): Pass true to constant_value_1's new
bool parameter.
(decl_really_constant_value): Add bool parameter and forward it
to constant_value_1.
(decl_constant_value): Likewise, but instead define a new
overload with an added bool parameter.
gcc/testsuite/ChangeLog:
PR c++/96197
* g++.dg/cpp1y/constexpr-array8.C: New test.
|
|
I was mistaken to assume that a dependent type is necessarily
incomplete, and indeed there are multiple places in the frontend where
we check a type for both dependency and completeness. So this patch
partially reverts the fix for PR95497, restoring the dependent_type_p
check that guarded the call to is_really_empty_class below.
gcc/cp/ChangeLog:
PR c++/96132
* constexpr.c (potential_constant_expression_1) <case PARM_DECL>:
Restore dependent_type_p check that guarded the call to
is_really_empty_class.
gcc/testsuite/ChangeLog:
PR c++/96132
* g++.dg/template/incomplete12.C: New test.
|
|
We are ICEing in the testcase below because we pass the
yet-uninstantiated class type A<int> of the PARM_DECL b to
is_really_empty_class from is_rvalue_constant_expression when parsing
the requirement t += b.
This patch fixes the ICE by guarding the problematic call to
is_really_empty_class with a COMPLETE_TYPE_P check, which should also
subsume the existing dependent_type_p check.
gcc/cp/ChangeLog:
PR c++/95497
* constexpr.c (potential_constant_expression_1) <case PARM_DECL>:
When processing_template_decl, check COMPLETE_TYPE_P before
calling is_really_empty_class. Don't check dependent_type_p.
gcc/testsuite/ChangeLog:
PR c++/95497
* g++.dg/cpp2a/concepts-pr95497.C: New test.
|
|
Jakub's partial implementation of consteval virtual had trouble with the
current ABI requirement that we omit the vtable slot for a consteval virtual
function; it's difficult to use the normal code for constant evaluation and
also magically make the slots disappear if the vtables get written out. I
notice that Clang trunk also doesn't implement that requirement, and it
seems unnecessary to me; I expect consteval virtual functions to be
extremely rare, so it should be fine to just give them a vtable slot as
normal but put zero in it if the vtable gets emitted. I've commented as
much to the ABI committee.
One of Jakub's testcases points out that we weren't handling thunks in
our constexpr virtual handling; that is fixed here as well.
Incidentally, being able to use C++11 range-for definitely simplified
clear_consteval_vfns.
gcc/c-family/ChangeLog:
* c-cppbuiltin.c (c_cpp_builtins): Define __cpp_consteval.
gcc/cp/ChangeLog:
* decl.c (grokfndecl): Allow consteval virtual.
* search.c (check_final_overrider): Check consteval mismatch.
* constexpr.c (cxx_eval_thunk_call): New.
(cxx_eval_call_expression): Call it.
* cvt.c (cp_get_fndecl_from_callee): Handle FDESC_EXPR.
* decl2.c (mark_vtable_entries): Track vtables with consteval.
(maybe_emit_vtables): Pass consteval_vtables through.
(clear_consteval_vfns): Replace consteval with nullptr.
(c_parse_final_cleanups): Call it.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/consteval-virtual1.C: New test.
* g++.dg/cpp2a/consteval-virtual2.C: New test.
* g++.dg/cpp2a/consteval-virtual3.C: New test.
* g++.dg/cpp2a/consteval-virtual4.C: New test.
* g++.dg/cpp2a/consteval-virtual5.C: New test.
Co-authored-by: Jakub Jelinek <jakub@redhat.com>
|
|
Since r10-7096 convert_like, when called in a template, creates an
IMPLICIT_CONV_EXPR when we're converting to/from array type.
In this test, we have e[f], and we're converting f (of type class A) to
int, so convert_like in build_new_op_1 created the IMPLICIT_CONV_EXPR
that got into cp_build_array_ref which calls maybe_constant_value. My
patch above failed to adjust this spot to call fold_non_dependent_expr
instead, which can handle codes like I_C_E in a template. Fixed by
using a new function maybe_fold_non_dependent_expr, which, if the expr
can't be evaluated to a constant, returns the original expression.
gcc/cp/ChangeLog:
PR c++/95508
* constexpr.c (maybe_fold_non_dependent_expr): New.
* cp-tree.h (maybe_fold_non_dependent_expr): Declare.
* typeck.c (cp_build_array_ref): Call maybe_fold_non_dependent_expr
instead of maybe_constant_value.
gcc/testsuite/ChangeLog:
PR c++/95508
* g++.dg/template/conv16.C: New test.
|
|
The code in constexpr for looking up the actual type of the object and then
getting the virtual function from there broke for both of these tests: for
16, it assumed incorrectly that the DECL_VINDEX would apply to the most
derived type's vtable; for 17, it failed to consider that during
construction the base subobject is treated as being of the base type.
Fixed by just doing constant evaluation of the expression that looks up the
function in the vtable. This means that a virtual call will involve loading
the vptr, so we will reject some calls through non-constexpr variables that
we previously accepted, but this seems appropriate to me. None of our
testcases were affected.
gcc/cp/ChangeLog:
PR c++/93310
* constexpr.c (cxx_eval_constant_expression) [OBJ_TYPE_REF]:
Evaluate OBJ_TYPE_REF_EXPR.
gcc/testsuite/ChangeLog:
PR c++/93310
* g++.dg/cpp2a/constexpr-virtual16.C: New test.
* g++.dg/cpp2a/constexpr-virtual17.C: New test.
* g++.dg/cpp2a/constexpr-new12.C: Adjust diagnostic.
|
|
cxx_eval_outermost_constant_expr had a check for reinterpret_casts from
pointers (well, it checked from ADDR_EXPRs) to integral type, but that
only caught such cases at the toplevel of expressions.
As the comment said, it should be done even inside of the expressions,
but at the point of the writing e.g. pointer differences used to be a
problem. We now have POINTER_DIFF_EXPR, so this is no longer an issue.
Had to do it just for CONVERT_EXPR, because the FE emits NOP_EXPR casts
from pointers to integrals in various spots, e.g. for the PMR & 1 tests,
though on NOP_EXPR we have the REINTERPRET_CAST_P bit that we do check,
while on CONVERT_EXPR we don't.
2020-06-04 Jakub Jelinek <jakub@redhat.com>
PR c++/82304
PR c++/95307
* constexpr.c (cxx_eval_constant_expression): Diagnose CONVERT_EXPR
conversions from pointer types to arithmetic types here...
(cxx_eval_outermost_constant_expr): ... instead of here.
* g++.dg/template/pr79650.C: Expect different diagnostics and expect
it on all lines that do pointer to integer casts.
* g++.dg/cpp1y/constexpr-shift1.C: Expect different diagnostics.
* g++.dg/cpp1y/constexpr-82304.C: New test.
* g++.dg/cpp0x/constexpr-95307.C: New test.
|
|
In the testcase below, the CONSTRUCTOR for 'field' contains a RANGE_EXPR
index:
{{aggr_init_expr<...>, [1...2]={.off=1}}}
but get_or_insert_ctor_field isn't prepared to handle looking up a
RANGE_EXPR index.
This patch adds limited support to get_or_insert_ctor_field for looking
up a RANGE_EXPR index. The limited scope of this patch should make it
more suitable for backporting, and more extensive support would be
needed only to handle self-modifying CONSTRUCTORs that contain a
RANGE_EXPR index, but I haven't yet been able to come up with a testcase
that actually creates such a CONSTRUCTOR.
gcc/cp/ChangeLog:
PR c++/95241
* constexpr.c (get_or_insert_ctor_field): Add limited support
for RANGE_EXPR index lookups.
gcc/testsuite/ChangeLog:
PR c++/95241
* g++.dg/cpp0x/constexpr-array25.C: New test.
|
|
In r9-297 I was trying to be more flexible and treat static data members of
class templates more like variable templates, where the type need not be
determined until the variable is instantiated, but I suppose that in a class
the types of all the non-template members need to be determined at the time
of class instantiation.
gcc/cp/ChangeLog:
PR c++/94926
* decl.c (cp_finish_decl): Revert r9-297 change.
(check_static_variable_definition): Likewise.
* constexpr.c (ensure_literal_type_for_constexpr_object): Likewise.
* pt.c (instantiate_decl): Return early on type error.
gcc/testsuite/ChangeLog:
* g++.dg/cpp1z/pr86648.C: Expect error.
* g++.dg/cpp1z/static2.C: Expect error.
* g++.dg/cpp0x/nsdmi16.C: New test.
|
|
Concept evaluation may entail DECL_UID generation and/or template
instantiation, so in general we can't perform it during uid-sensitive
constexpr evaluation.
gcc/cp/ChangeLog:
PR c++/94038
* constexpr.c (cxx_eval_constant_expression)
<case TEMPLATE_ID_EXPR>: Don't evaluate the concept when
constexpr evaluation is uid-sensitive.
gcc/testsuite/ChangeLog:
PR c++/94038
* g++.dg/warn/pr94038-3.C: New test.
|
|
The difference between a "potential" constant-expression and a regular
constant-expression is the treatment of parameters; in a constexpr function,
a parameter is potentially constant when evaluating a call to that function,
but it is not constant during parsing of the function.
cp_parser_constant_expression should check the latter rather than the
former.
gcc/cp/ChangeLog:
* cp-tree.h (is_rvalue_constant_expression): Declare.
* constexpr.c (is_rvalue_constant_expression): New.
* parser.c (cp_parser_constant_expression): Use it.
* decl.c (cp_finish_decl): Try to treat a constexpr initializer in a
template as constant.
|
|
Unfortunately, the previous fix to PR94038 is fragile. When the
argument to fold_for_warn is a bare CALL_EXPR, then all is well: the
result of maybe_constant_value from fold_for_warn (with
uid_sensitive=true) is reused via the cv_cache in the subsequent call to
maybe_constant_value from cp_fold (with uid_sensitive=false), so we
avoid instantiating bar<int>.
But when the argument to fold_for_warn is more complex, e.g. an
INDIRECT_REF of a CALL_EXPR, as in the testcase below (due to bar<int>()
returning const int& which we need to decay to int) then from
fold_for_warn we call maybe_constant_value on the INDIRECT_REF, and from
cp_fold we call it on the CALL_EXPR, so there is no reuse via the
cv_cache and we therefore end up instantiating bar<int>.
So for a more robust solution to this general issue of warning flags
affecting code generation, it seems that we need a way to globally avoid
template instantiation during constexpr evaluation whenever we're
performing warning-dependent folding.
To that end, this patch replaces the flag constexpr_ctx::uid_sensitive
with a global flag uid_sensitive_constexpr_evaluation_p, and enables it
during fold_for_warn using an RAII helper.
The patch also adds a counter that keeps track of the number of times
uid_sensitive_constexpr_evaluation_p is called and returned true, and we
use this to determine whether the result of constexpr evaluation
was restricted by the flag. This lets us safely update the cv_cache and
fold_cache from fold_for_warn in the most common case where the flag
did not restrict constexpr evaluation.
gcc/cp/ChangeLog:
PR c++/94038
* constexpr.c (constexpr_ctx::uid_sensitive): Remove field.
(uid_sensitive_constexpr_evaluation_value): Define.
(uid_sensitive_constexpr_evaluation_true_counter): Define.
(uid_sensitive_constexpr_evaluation_p): Define.
(uid_sensitive_constexpr_evaluation_sentinel): Define its
constructor.
(uid_sensitive_constexpr_evaluation_checker): Define its
constructor and its evaluation_restricted_p method.
(get_fundef_copy): Remove 'ctx' parameter. Use u_s_c_e_p
instead of constexpr_ctx::uid_sensitive.
(cxx_eval_call_expression): Use u_s_c_e_p instead, and test it
last. Adjust call to get_fundef_copy.
(instantiate_cx_fn_r): Test u_s_c_e_p so that we increment the
counter if necessary.
(cxx_eval_outermost_constant_expr): Remove 'uid_sensitive'
parameter. Adjust function body accordingly.
(maybe_constant_value): Remove 'uid_sensitive' parameter and
adjust function body accordingly. Set up a
uid_sensitive_constexpr_evaluation_checker, and use it to
conditionally update the cv_cache.
* cp-gimplify.c (cp_fold): Set up a
uid_sensitive_constexpr_evaluation_checker, and use it to
conditionally update the fold_cache.
* cp-tree.h (maybe_constant_value): Update declaration.
(struct uid_sensitive_constexpr_evaluation_sentinel): Define.
(struct sensitive_constexpr_evaluation_checker): Define.
* expr.c (fold_for_warn): Set up a
uid_sensitive_constexpr_evaluation_sentinel before calling
the folding subroutines. Drop all but the first argument to
maybe_constant_value.
gcc/testsuite/ChangeLog:
PR c++/94038
* g++.dg/warn/pr94038-2.C: New test.
|
|
C++20 isn't final quite yet, but all that remains is formalities, so let's
go ahead and change all the references.
I think for the next C++ standard we can just call it C++23 rather than
C++2b, since the committee has been consistent about time-based releases
rather than feature-based.
gcc/c-family/ChangeLog
2020-05-13 Jason Merrill <jason@redhat.com>
* c.opt (std=c++20): Make c++2a the alias.
(std=gnu++20): Likewise.
* c-common.h (cxx_dialect): Change cxx2a to cxx20.
* c-opts.c: Adjust.
* c-cppbuiltin.c: Adjust.
* c-ubsan.c: Adjust.
* c-warn.c: Adjust.
gcc/cp/ChangeLog
2020-05-13 Jason Merrill <jason@redhat.com>
* call.c, class.c, constexpr.c, constraint.cc, decl.c, init.c,
lambda.c, lex.c, method.c, name-lookup.c, parser.c, pt.c, tree.c,
typeck2.c: Change cxx2a to cxx20.
libcpp/ChangeLog
2020-05-13 Jason Merrill <jason@redhat.com>
* include/cpplib.h (enum c_lang): Change CXX2A to CXX20.
* init.c, lex.c: Adjust.
|
|
This is the same issue as PR86429, just in potential_constant_expression_1
rather than cxx_eval_constant_expression. As in that case, when we're
trying to evaluate a constant expression within a lambda, we don't have a
constant closure object to refer to, but we can try to refer directly to the
captured variable.
gcc/cp/ChangeLog
2020-05-05 Jason Merrill <jason@redhat.com>
PR c++/90212
* constexpr.c (potential_constant_expression_1): In a lambda
function, consider a captured variable directly.
|
|
In the first testcase below, the call to the target constructor foo{} from foo's
delegating constructor is encoded as the INIT_EXPR
*(struct foo *) this = AGGR_INIT_EXPR <4, __ct_comp, D.2140, ...>;
During initialization of the variable 'bar', we prematurely set TREE_READONLY on
bar's CONSTRUCTOR in two places before the outer delegating constructor has
returned: first, at the end of cxx_eval_call_expression after evaluating the RHS
of the above INIT_EXPR, and second, at the end of cxx_eval_store_expression
after having finished evaluating the above INIT_EXPR. This then prevents the
rest of the outer delegating constructor from mutating 'bar'.
This (hopefully minimally risky) patch makes cxx_eval_call_expression refrain
from setting TREE_READONLY when evaluating the target constructor of a
delegating constructor. It also makes cxx_eval_store_expression refrain from
setting TREE_READONLY when the object being initialized is "*this', on the basis
that it should be the responsibility of the routine that set 'this' in the first
place to set the object's TREE_READONLY appropriately.
gcc/cp/ChangeLog:
PR c++/94772
* constexpr.c (cxx_eval_call_expression): Don't set new_obj if we're
evaluating the target constructor of a delegating constructor.
(cxx_eval_store_expression): Don't set TREE_READONLY if the LHS of the
INIT_EXPR is '*this'.
gcc/testsuite/ChangeLog:
PR c++/94772
* g++.dg/cpp1y/constexpr-tracking-const23.C: New test.
* g++.dg/cpp1y/constexpr-tracking-const24.C: New test.
* g++.dg/cpp1y/constexpr-tracking-const25.C: New test.
|
|
As an extension (there should be a CWG about this though), we support
braced-init-list as a template argument, but convert_nontype_argument
had trouble digesting them. We ICEd because of the double coercion we
perform for template arguments: convert_nontype_argument called from
finish_template_type got a { }, and since a class type was involved and
we were in a template, convert_like created an IMPLICIT_CONV_EXPR. Then
the second conversion of the same argument crashed in constexpr.c
because the IMPLICIT_CONV_EXPR had gotten wrapped in a TARGET_EXPR.
Another issue was that an IMPLICIT_CONV_EXPR leaked to constexpr.c when
building an aggregate init.
We should have instantiated the IMPLICIT_CONV_EXPR in the first call to
convert_nontype_argument, but we didn't, because the call to
is_nondependent_constant_expression returned false because it checks
!BRACE_ENCLOSED_INITIALIZER_P. Then non_dep was false even though the
expression didn't contain anything dependent and we didn't instantiate
it in convert_nontype_argument. To fix this, check
BRACE_ENCLOSED_INITIALIZER_P in cxx_eval_outermost_constant_expr rather
than in is_nondependent_*.
PR c++/94592
* constexpr.c (cxx_eval_outermost_constant_expr): Return when T is
a BRACE_ENCLOSED_INITIALIZER_P.
(is_nondependent_constant_expression): Don't check
BRACE_ENCLOSED_INITIALIZER_P.
(is_nondependent_static_init_expression): Likewise.
* g++.dg/cpp2a/nontype-class34.C: New test.
* g++.dg/cpp2a/nontype-class35.C: New test.
|
|
When evaluating the initializer of 'a' in the following example
struct A {
A() = default; A(const 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'.
Fixing this properly by immediately resolving 'this' and PLACEHOLDER_EXPRs to
the ultimate object under construction would in general mean that we would no
longer be able to cache constexpr calls for which RVO possibly applies, because
the result of the call may now depend on the ultimate object under construction.
So as a mostly correct stopgap solution that retains cachability of RVO'd
constexpr calls, this patch fixes this issue by rewriting all occurrences of the
RESULT_DECL in the result of a constexpr function call with the current object
under construction, after the call returns. This means the 'this' pointer
during construction of the temporary will still point to the temporary object
instead of the ultimate object, but besides that this approach seems
functionally equivalent to the proper approach.
gcc/cp/ChangeLog:
PR c++/94034
* constexpr.c (replace_result_decl_data): New struct.
(replace_result_decl_data_r): New function.
(replace_result_decl): New function.
(cxx_eval_call_expression): Use it.
* tree.c (build_aggr_init_expr): Set the location of the AGGR_INIT_EXPR
to that of its initializer.
gcc/testsuite/ChangeLog:
PR c++/94034
* g++.dg/cpp0x/constexpr-empty15.C: New test.
* g++.dg/cpp1y/constexpr-nsdmi6a.C: New test.
* g++.dg/cpp1y/constexpr-nsdmi6b.C: New test.
* g++.dg/cpp1y/constexpr-nsdmi7a.C: New test.
* g++.dg/cpp1y/constexpr-nsdmi7b.C: New test.
|
|
In this PR we're incorrectly rejecting a self-modifying constexpr initializer as
a consequence of the fix for PR78572.
It looks like however that the fix for PR78572 is obsoleted by the fix for
PR89336: the testcase from the former PR successfully compiles even with its fix
reverted.
But then further testing showed that the analogous testcase of PR78572 where the
array has an aggregate element type is still problematic (i.e. we ICE) even with
the fix for PR78572 applied. The reason is that in cxx_eval_bare_aggregate we
attach a constructor_elt of aggregate type always to the end of the new
CONSTRUCTOR, but that's not necessarily correct if the CONSTRUCTOR is
self-modifying. We should instead be using get_or_insert_ctor_field to insert
the constructor_elt in the right place.
So this patch reverts the PR78572 fix and makes the appropriate changes to
cxx_eval_bare_aggregate. This fixes PR94470, and we now are also able to fully
reduce the initializers of 'arr' and 'arr2' in the new test array57.C to
constant initializers.
gcc/cp/ChangeLog:
PR c++/94470
* constexpr.c (get_or_insert_ctor_field): Set default value of parameter
'pos_hint' to -1.
(cxx_eval_bare_aggregate): Use get_or_insert_ctor_field instead of
assuming the the next index belongs at the end of the new CONSTRUCTOR.
(cxx_eval_store_expression): Revert PR c++/78572 fix.
gcc/testsuite/ChangeLog:
PR c++/94470
* g++.dg/cpp1y/constexpr-nsdmi8.C: New test.
* g++.dg/cpp1y/constexpr-nsdmi9.C: New test.
* g++.dg/init/array57.C: New test.
|
|
Here due to my recent change to store_init_value we were expanding the
initializer of aw knowing that we were initializing aw. When
cxx_eval_call_expression finished the constructor, it wanted to look up the
value of aw to set TREE_READONLY on it, but we haven't set DECL_INITIAL yet,
so decl_constant_value tried to instantiate the initializer again. And
infinite recursion. Stopped by optimizing the case of asking for the value
of ctx->object, which is ctx->value. It also would have worked to look in
the values hash table, so let's move that up before decl_constant_value as
well.
gcc/cp/ChangeLog
2020-04-09 Jason Merrill <jason@redhat.com>
PR c++/94523
* constexpr.c (cxx_eval_constant_expression) [VAR_DECL]: Look at
ctx->object and ctx->global->values first.
|
|
This removes the use of replace_placeholders in cxx_eval_constant_expression
(which is causing the new test lambda-this6.C to ICE due to replace_placeholders
mutating the shared TARGET_EXPR_INITIAL tree which then trips up the
gimplifier).
In its place, this patch adds a 'parent' field to constexpr_ctx which is used to
store a pointer to an outer constexpr_ctx that refers to another object under
construction. With this new field, we can beef up lookup_placeholder to resolve
PLACEHOLDER_EXPRs which refer to former objects under construction, which fixes
PR94205 without needing to do replace_placeholders. Also we can now respect the
CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag when resolving PLACEHOLDER_EXPRs, and
doing so fixes the constexpr analogue of PR79937.
gcc/cp/ChangeLog:
PR c++/94205
PR c++/79937
* constexpr.c (struct constexpr_ctx): New field 'parent'.
(cxx_eval_bare_aggregate): Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY
flag from the original constructor to the reduced constructor.
(lookup_placeholder): Prefer to return the outermost matching object
by recursively calling lookup_placeholder on the 'parent' context,
but don't cross CONSTRUCTOR_PLACEHOLDER_BOUNDARY constructors.
(cxx_eval_constant_expression): Link the 'ctx' context to the 'new_ctx'
context via 'new_ctx.parent' when being expanded without an explicit
target. Don't call replace_placeholders.
(cxx_eval_outermost_constant_expr): Initialize 'ctx.parent' to NULL.
gcc/testsuite/ChangeLog:
PR c++/94205
PR c++/79937
* g++.dg/cpp1y/pr79937-5.C: New test.
* g++.dg/cpp1z/lambda-this6.C: New test.
|
|
This PR reveals that cxx_eval_bare_aggregate and cxx_eval_store_expression do
not anticipate that a constructor element's initializer could mutate the
underlying CONSTRUCTOR. Evaluation of the initializer could add new elements to
the underlying CONSTRUCTOR, thereby potentially invalidating any pointers to
or assumptions about the CONSTRUCTOR's elements, and so these routines should be
prepared for that.
To fix this problem, this patch makes cxx_eval_bare_aggregate and
cxx_eval_store_expression recompute the constructor_elt pointers through which
we're assigning, after it evaluates the initializer. Care is taken to to not
slow down the common case where the initializer does not modify the underlying
CONSTRUCTOR.
gcc/cp/ChangeLog:
PR c++/94219
PR c++/94205
* constexpr.c (get_or_insert_ctor_field): Split out (while adding
support for VECTOR_TYPEs, and optimizations for the common case)
from ...
(cxx_eval_store_expression): ... here. Rename local variable
'changed_active_union_member_p' to 'activated_union_member_p'. Record
the sequence of indexes into 'indexes' that yields the subobject we're
assigning to. Record the integer offsets of the constructor indexes
we're assigning through into 'index_pos_hints'. After evaluating the
initializer of the store expression, recompute 'valp' using 'indexes'
and using 'index_pos_hints' as hints.
(cxx_eval_bare_aggregate): Tweak comments. Use get_or_insert_ctor_field
to recompute the constructor_elt pointer we're assigning through after
evaluating each initializer.
gcc/testsuite/ChangeLog:
PR c++/94219
PR c++/94205
* g++.dg/cpp1y/constexpr-nsdmi3.C: New test.
* g++.dg/cpp1y/constexpr-nsdmi4.C: New test.
* g++.dg/cpp1y/constexpr-nsdmi5.C: New test.
* g++.dg/cpp1z/lambda-this5.C: New test.
|
|
The testcase hit an ICE trying to expand a TARGET_EXPR temporary cached from
the other lambda-expression. This patch fixes this in two ways:
1) Avoid reusing a TARGET_EXPR from another function.
2) Avoid ending up with a TARGET_EXPR at all; the use of 'p' had become
<TARGET_EXPR<NON_LVALUE_EXPR<TARGET_EXPR ...>>>, which doesn't make any
sense.
gcc/cp/ChangeLog
2020-04-04 Jason Merrill <jason@redhat.com>
PR c++/94453
* constexpr.c (maybe_constant_value): Use break_out_target_exprs.
* expr.c (mark_use) [VIEW_CONVERT_EXPR]: Don't wrap a TARGET_EXPR in
NON_LVALUE_EXPR.
|
|
We represent 'this' in a default member initializer with a PLACEHOLDER_EXPR.
Normally in constexpr evaluation when we encounter one it refers to
ctx->ctor, but when we're creating a temporary of class type, that replaces
ctx->ctor, so a PLACEHOLDER_EXPR that refers to the type of the member being
initialized needs to be replaced before that happens.
gcc/cp/ChangeLog
2020-03-31 Jason Merrill <jason@redhat.com>
PR c++/94205
* constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Call
replace_placeholders.
* typeck2.c (store_init_value): Fix arguments to
fold_non_dependent_expr.
|
|
This patch has no semantic effect; committing it separately makes the change
for 94205 easier to read.
gcc/cp/ChangeLog
2020-03-31 Jason Merrill <jason@redhat.com>
* constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Use
local variables.
|
|
This patch adds a check to detect changing the active union member during
initialization of another member of the union in cxx_eval_store_expression. It
uses the CONSTRUCTOR_NO_CLEARING flag as a proxy for whether the non-empty
CONSTRUCTOR of UNION_TYPE we're assigning to is in the process of being
initialized.
This patch additionally fixes an issue in reduced_constant_expression_p where we
were returning false for an uninitialized union with no active member. This
lets us correctly reject the uninitialized use in the testcase
testconstexpr-union4.C that we weren't before.
gcc/cp/ChangeLog:
PR c++/94066
* constexpr.c (reduced_constant_expression_p) [CONSTRUCTOR]: Properly
handle unions without an initializer.
(cxx_eval_component_reference): Emit a different diagnostic when the
constructor element corresponding to a union member is NULL.
(cxx_eval_bare_aggregate): When constructing a union, always set the
active union member before evaluating the initializer. Relax assertion
that verifies the index of the constructor element we're initializing
hasn't been changed.
(cxx_eval_store_expression): Diagnose changing the active union member
while the union is in the process of being initialized. After setting
an active union member, clear CONSTRUCTOR_NO_CLEARING on the underlying
CONSTRUCTOR.
(cxx_eval_constant_expression) [PLACEHOLDER_EXPR]: Don't re-reduce a
CONSTRUCTOR returned by lookup_placeholder.
gcc/testsuite/ChangeLog:
PR c++/94066
* g++.dg/cpp1y/constexpr-union2.C: New test.
* g++.dg/cpp1y/constexpr-union3.C: New test.
* g++.dg/cpp1y/constexpr-union4.C: New test.
* g++.dg/cpp1y/constexpr-union5.C: New test.
* g++.dg/cpp1y/pr94066.C: New test.
* g++.dg/cpp1y/pr94066-2.C: New test.
* g++.dg/cpp1y/pr94066-3.C: New test.
* g++.dg/cpp2a/constexpr-union1.C: New test.
|
|
I got a report that building Chromium fails with the "modifying a const
object" error. After some poking I realized it's a bug in GCC, not in
their codebase.
Much like with ARRAY_REFs, which can be const even though the array
itself isn't, COMPONENT_REFs can be const although neither the object
nor the field were declared const. So let's dial down the checking.
Here the COMPONENT_REF was const because of the "const_cast<const U &>(m)"
thing -- cxx_eval_component_reference then builds a COMPONENT_REF with
TREE_TYPE (t).
While looking into this I noticed that we don't detect modifying a const
object in certain cases like in
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94074#c2>. That's because
we never evaluate an X::X() CALL_EXPR -- there's none. Fixed as per
Jason's suggestion by setting TREE_READONLY on a CONSTRUCTOR after
initialization in cxx_eval_store_expression.
2020-03-11 Marek Polacek <polacek@redhat.com>
Jason Merrill <jason@redhat.com>
PR c++/94074 - wrong modifying const object error for COMPONENT_REF.
* constexpr.c (cref_has_const_field): New function.
(modifying_const_object_p): Consider a COMPONENT_REF
const only if any of its fields are const.
(cxx_eval_store_expression): Mark a CONSTRUCTOR of a const type
as readonly after its initialization has been done.
* g++.dg/cpp1y/constexpr-tracking-const17.C: New test.
* g++.dg/cpp1y/constexpr-tracking-const18.C: New test.
* g++.dg/cpp1y/constexpr-tracking-const19.C: New test.
* g++.dg/cpp1y/constexpr-tracking-const20.C: New test.
* g++.dg/cpp1y/constexpr-tracking-const21.C: New test.
* g++.dg/cpp1y/constexpr-tracking-const22.C: New test.
|
|
Since r10-6527-gaaa26bf496a646778ac861aed124d960b5bf549f fold_for_warn
will perform maybe_constant_value even on some cp_fold produced trees and
so can include rotate exprs which were removed last fall from constexpr.c
2020-03-09 Jakub Jelinek <jakub@redhat.com>
PR c++/94067
Revert
2019-10-11 Paolo Carlini <paolo.carlini@oracle.com>
* constexpr.c (cxx_eval_constant_expression): Do not handle
RROTATE_EXPR and LROTATE_EXPR.
* g++.dg/warn/Wconversion-pr94067.C: New test.
|
|
output_constructor doesn't like two consecutive entries with fields at the
same position; let's avoid adding the one for the empty field.
gcc/cp/ChangeLog
2020-03-04 Jason Merrill <jason@redhat.com>
PR c++/90432
* init.c (perform_member_init): Don't do aggregate initialization of
empty field.
* constexpr.c (cx_check_missing_mem_inits): Don't enforce
initialization of empty field.
|
|
We ICE on the following testcase since I've added the SAVE_EXPR-like
constexpr handling where the TARGET_EXPR initializer (and cleanup) is
evaluated only once (because it might have side-effects like new or delete
expressions in it).
The problem is if the TARGET_EXPR (but I guess in theory SAVE_EXPR too)
initializer is *non_constant_p. We still remember the result, but already
not that it is *non_constant_p. Normally that wouldn't be a big problem,
if something is *non_constant_p, we only or into it and so the whole
expression will be non-constant too. Except in the builtins handling,
we try to evaluate the arguments with non_constant_p pointing into a dummy1
bool which we ignore. This is because some builtins might fold into a
constant even if they don't have a constexpr argument. Unfortunately if
we evaluate the TARGET_EXPR first in the argument of such a builtin and then
once again, we don't set *non_constant_p.
So, either we don't remember the TARGET_EXPR/SAVE_EXPR result if it wasn't
constant, like the following patch does, or we could remember it, but in
some way that would make it clear that it is non-constant (e.g. by
pushing into the global->values SAVE_EXPR, SAVE_EXPR entry and perhaps
for TARGET_EXPR don't remember it on TARGET_EXPR_SLOT, but the TARGET_EXPR
itself and similarly push TARGET_EXPR, TARGET_EXPR and if we see those
after the lookup, diagnose + set *non_constant_p. Or we could perhaps
during the builtin argument evaluation push expressions into a different
save_expr vec and undo them afterwards.
2020-03-03 Jakub Jelinek <jakub@redhat.com>
PR c++/93998
* constexpr.c (cxx_eval_constant_expression)
<case TARGET_EXPR, case SAVE_EXPR>: Don't record anything if
*non_constant_p is true.
* g++.dg/ext/pr93998.C: New test.
|
|
Here we crash when constexpr-initializing a class member of empty class
type with [[no_unique_address]]. Without the attribute we would have
a ctor (that initializes bar) of the form
{ .D.2173 = { .x = {} } }
but with the attribute reduced_constant_expression_p gets
{ .x = {} }
That means that "idx != field" is true for the latter and we see that
foo, the base class of bar, is an empty class, so we want to look at
the next initializable field (since empty class fields may not have an
initializer). But in this case there are no more, therefore accessing
DECL_CHAIN (field) crashes. Long story short, we need to avoid a crash
on a null field when we're initializing a class that only contains an
empty base class.
While poking into this I discovered c++/93898, but that's a different
problem.
2020-02-26 Marek Polacek <polacek@redhat.com>
PR c++/93803 - ICE with constexpr init and [[no_unique_address]].
* constexpr.c (reduced_constant_expression_p): Don't crash on a null
field.
* g++.dg/cpp2a/constexpr-init16.C: New test.
* g++.dg/cpp2a/constexpr-init17.C: New test.
|
|
In order to detect modifying constant objects in constexpr evaluation,
which is UB, in r10-2655 I added code that sets TREE_READONLY on
CONSTRUCTORs of const-qualified objects after they have been fully
constructed. But I never made sure that what we're setting the flag
on actually is a CONSTRUCTOR. Consequently, as this test case shows,
we could set TREE_READONLY on a VAR_DECL that in fact wasn't constant,
causing problems later. Fixed by setting the flag on CONSTRUCTORs
only, and only when the evaluation produced something constant.
2020-02-19 Marek Polacek <polacek@redhat.com>
PR c++/93169 - wrong-code with a non-constexpr constructor.
* constexpr.c (cxx_eval_call_expression): Only set TREE_READONLY
on constant CONSTRUCTORs.
* g++.dg/cpp0x/constexpr-93169.C: New test.
|
|
Constant evaluation of genericize_spaceship produced a CONSTRUCTOR, which we
then wanted to bind to a reference, which we can't do. So wrap the result
in a TARGET_EXPR so we get something with an address.
We also need to handle treating the result of cxx_eval_binary_expression as
a glvalue for SPACESHIP_EXPR.
My earlier change to add uid_sensitive to maybe_constant_value was wrong; we
don't even look at the cache when manifestly_const_eval, and I failed to
adjust the later call to cxx_eval_outermost_constant_expr.
gcc/cp/ChangeLog
2020-02-11 Jason Merrill <jason@redhat.com>
PR c++/93650
PR c++/90691
* constexpr.c (maybe_constant_value): Correct earlier change.
(cxx_eval_binary_expression) [SPACESHIP_EXPR]: Pass lval through.
* method.c (genericize_spaceship): Wrap result in TARGET_EXPR.
|
|
The first (valid) testcase ICEs because for
A *a = new B ();
a->foo (); // virtual method call
we actually see &heap and the "heap " objects don't have the class or
whatever else type was used in new expression, but an array type containing
one (or more of those for array new) and so when using TYPE_BINFO (objtype)
on it we ICE.
This patch handles this special case, and otherwise punts (as shown e.g. in
the second testcase, where because the heap object is already deleted,
we don't really want to allow it to be used.
2020-02-09 Jakub Jelinek <jakub@redhat.com>
PR c++/93633
* constexpr.c (cxx_eval_constant_expression): If obj is heap var with
ARRAY_TYPE, use the element type. Punt if objtype after that is not
a class type.
* g++.dg/cpp2a/constexpr-new11.C: New test.
* g++.dg/cpp2a/constexpr-new12.C: New test.
* g++.dg/cpp2a/constexpr-new13.C: New test.
|
|
We would like to do constexpr evaluation to avoid false positives on
warnings, but constexpr evaluation can involve function body copying that
changes DECL_UID, which breaks -fcompare-debug. So let's remember
that we need to avoid that.
PR c++/90691
* expr.c (fold_for_warn): Call maybe_constant_value.
* constexpr.c (struct constexpr_ctx): Add uid_sensitive field.
(maybe_constant_value): Add uid_sensitive parm.
(get_fundef_copy): Don't copy if it's true.
(cxx_eval_call_expression): Don't instantiate if it's true.
(cxx_eval_outermost_constant_expr): Likewise.
|
|
If cxx_eval_outermost_constant_expr doesn't change the argument, we really
shouldn't unshare it when we try to fold it again.
PR c++/92852
* constexpr.c (maybe_constant_value): Don't unshare if the cached
value is the same as the argument.
|
|
My change
* typeck2.c (store_init_value): Don't call cp_fully_fold_init on
initializers of automatic non-constexpr variables in constexpr
functions.
- value = cp_fully_fold_init (value);
+ /* Don't fold initializers of automatic variables in constexpr functions,
+ that might fold away something that needs to be diagnosed at constexpr
+ evaluation time. */
+ if (!current_function_decl
+ || !DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+ || TREE_STATIC (decl))
+ value = cp_fully_fold_init (value);
from the constexpr new change apparently broke the following testcase.
When handling COND_EXPR, we build_vector_from_val, however as the argument we
pass to it is not an INTEGER_CST/REAL_CST, but that wrapped in a
NON_LVALUE_EXPR location wrapper, we end up with a CONSTRUCTOR and as it is
middle-end that builds it, it doesn't bother with indexes. The
cp_fully_fold_init call used to fold it into VECTOR_CST in the past, but as
we intentionally don't invoke it anymore as it might fold away something
that needs to be diagnosed during constexpr evaluation, we end up evaluating
ARRAY_REF into the index-less CONSTRUCTOR. The following patch fixes the
ICE by teaching find_array_ctor_elt to handle CONSTRUCTORs without indexes
(that itself could be still very efficient) and CONSTRUCTORs with some
indexes present and others missing (the rules are that if the index on the
first element is missing, then it is the array's lowest index (in C/C++ 0)
and if other indexes are missing, they are the index of the previous element
+ 1).
Here is a new version, which assumes CONSTRUCTORs with all or none indexes
and for CONSTRUCTORs without indexes performs the verification for
flag_checking directly in find_array_ctor_elt. For CONSTRUCTORs with
indexes, it doesn't do the verification of all elts, because some CONSTRUCTORs
can be large, and it "verifies" only what it really needs - if all elts
touched during the binary search have indexes, that is actually all we care
about because we are sure we found the right elt. It is just if we see a
missing index we need assurance that all are missing to be able to directly
access it.
The assumption then simplifies the patch, for no index CONSTRUCTORs we can
use direct access like for CONSTRUCTORs where last elt index is equal to the
elt position. If we append right after the last elt, we just should clear
the index so that we don't violate the assumption, and if we need a gap
between the elts and the elt to be added, we need to add indexes.
2020-02-08 Jakub Jelinek <jakub@redhat.com>
PR c++/93549
* constexpr.c (find_array_ctor_elt): If last element has no index,
for flag_checking verify all elts have no index. If i is within the
elts, return it directly, if it is right after the last elt, append
if NULL index, otherwise force indexes on all elts.
(cxx_eval_store_expression): Allow cep->index to be NULL.
* g++.dg/ext/constexpr-pr93549.C: New test.
|
|
Value-initialization is importantly different from {}-initialization for
this testcase, where the former calls the deleted S constructor and the
latter initializes S happily.
PR c++/90951
* constexpr.c (cxx_eval_array_reference): {}-initialize missing
elements instead of value-initializing them.
|
|
Here, we were going down the wrong path in perform_member_init because of
the incorrect parens around the mem-initializer for the array. And then
cxx_eval_vec_init_1 didn't know what to do with a CONSTRUCTOR as the
initializer. The latter issue was a straightforward fix, but I also wanted
to fix us silently accepting the parens, which led to factoring out handling
of TREE_LIST and flexarrays. The latter led to adjusting the expected
behavior on flexary29.C: we should complain about the initializer, but not
complain about a missing initializer.
As I commented on PR 92812, in this process I noticed that we weren't
handling C++20 parenthesized aggregate initialization as a mem-initializer.
So my TREE_LIST handling includes a commented out section that should
probably be part of a future fix for that issue; with it uncommented we
continue to crash on the testcase in C++20 mode, but should instead complain
about the braced-init-list not being a valid initializer for an A.
PR c++/86917
* init.c (perform_member_init): Simplify.
* constexpr.c (cx_check_missing_mem_inits): Allow uninitialized
flexarray.
(cxx_eval_vec_init_1): Handle CONSTRUCTOR.
|
|
[expr.const] specifically rules out mentioning a reference even if its
address is never used, because it implies indirection that is similarly
non-constant for a pointer variable.
PR c++/66477
* constexpr.c (cxx_eval_constant_expression) [PARM_DECL]: Don't
defer loading the value of a reference.
|
|
Since copying a class object is defined in terms of the copy constructor,
copying an empty class is OK even if it would otherwise not be usable in a
constant expression. Relatedly, using a parameter as an lvalue is no more
problematic than a local variable, and calling a member function uses the
object as an lvalue.
PR c++/91953
* constexpr.c (potential_constant_expression_1) [PARM_DECL]: Allow
empty class type.
[COMPONENT_REF]: A member function reference doesn't use the object
as an rvalue.
|
|
I neglected to add a proper diagnostic for the reference dynamic_cast
case when the operand of a dynamic_cast doesn't refer to a public base
of Derived, resulting in suboptimal error message
error: call to non-'constexpr' function 'void* __cxa_bad_cast()'
2020-01-25 Marek Polacek <polacek@redhat.com>
PR c++/93414 - poor diagnostic for dynamic_cast in constexpr context.
* constexpr.c (cxx_eval_dynamic_cast_fn): Add a reference
dynamic_cast diagnostic.
* g++.dg/cpp2a/constexpr-dynamic18.C: New test.
|
|
Another place we need to unshare cached expressions.
PR c++/92852 - ICE with generic lambda and reference var.
* constexpr.c (maybe_constant_value): Likewise.
|
|
If we can't change the argument to &"...", use the original arg instead of
the partially munged one.
PR c++/93331 - ICE with __builtin_strchr.
* constexpr.c (cxx_eval_builtin_function_call): Use the original
argument if we didn't manage to extract a STRING_CST.
|
|
This is the squashed version of the first 6 patches that were split to
facilitate review.
The changes to libiberty (7th patch) to support demangling the co_await
operator stand alone and are applied separately.
The patch series is an initial implementation of a coroutine feature,
expected to be standardised in C++20.
Standardisation status (and potential impact on this implementation)
--------------------------------------------------------------------
The facility was accepted into the working draft for C++20 by WG21 in
February 2019. During following WG21 meetings, design and national body
comments have been reviewed, with no significant change resulting.
The current GCC implementation is against n4835 [1].
At this stage, the remaining potential for change comes from:
* Areas of national body comments that were not resolved in the version we
have worked to:
(a) handling of the situation where aligned allocation is available.
(b) handling of the situation where a user wants coroutines, but does not
want exceptions (e.g. a GPU).
* Agreed changes that have not yet been worded in a draft standard that we
have worked to.
It is not expected that the resolution to these can produce any major
change at this phase of the standardisation process. Such changes should be
limited to the coroutine-specific code.
ABI
---
The various compiler developers 'vendors' have discussed a minimal ABI to
allow one implementation to call coroutines compiled by another.
This amounts to:
1. The layout of a public portion of the coroutine frame.
Coroutines need to preserve state across suspension points, the storage for
this is called a "coroutine frame".
The ABI mandates that pointers into the coroutine frame point to an area
begining with two function pointers (to the resume and destroy functions
described below); these are immediately followed by the "promise object"
described in the standard.
This is sufficient that the builtins can take a coroutine frame pointer and
determine the address of the promise (or call the resume/destroy functions).
2. A number of compiler builtins that the standard library might use.
These are implemented by this patch series.
3. This introduces a new operator 'co_await' the mangling for which is also
agreed between vendors (and has an issue filed for that against the upstream
c++abi). Demangling for this is added to libiberty in a separate patch.
The ABI has currently no target-specific content (a given psABI might elect
to mandate alignment, but the common ABI does not do this).
Standard Library impact
-----------------------
The current implementations require addition of only a single header to
the standard library (no change to the runtime). This header is part of
the patch.
GCC Implementation outline
--------------------------
The standard's design for coroutines does not decorate the definition of
a coroutine in any way, so that a function is only known to be a coroutine
when one of the keywords (co_await, co_yield, co_return) is encountered.
This means that we cannot special-case such functions from the outset, but
must process them differently when they are finalised - which we do from
"finish_function ()".
At a high level, this design of coroutine produces four pieces from the
original user's function:
1. A coroutine state frame (taking the logical place of the activation
record for a regular function). One item stored in that state is the
index of the current suspend point.
2. A "ramp" function
This is what the user calls to construct the coroutine frame and start
the coroutine execution. This will return some object representing the
coroutine's eventual return value (or means to continue it when it it
suspended).
3. A "resume" function.
This is what gets called when a the coroutine is resumed when suspended.
4. A "destroy" function.
This is what gets called when the coroutine state should be destroyed
and its memory released.
The standard's coroutines involve cooperation of the user's authored function
with a provided "promise" class, which includes mandatory methods for
handling the state transitions and providing output values. Most realistic
coroutines will also have one or more 'awaiter' classes that implement the
user's actions for each suspend point. As we parse (or during template
expansion) the types of the promise and awaiter classes become known, and can
then be verified against the signatures expected by the standard.
Once the function is parsed (and templates expanded) we are able to make the
transformation into the four pieces noted above.
The implementation here takes the approach of a series of AST transforms.
The state machine suspend points are encoded in three internal functions
(one of which represents an exit from scope without cleanups). These three
IFNs are lowered early in the middle end, such that the majority of GCC's
optimisers can be run on the resulting output.
As a design choice, we have carried out the outlining of the user's function
in the front end, and taken advantage of the existing middle end's abilities
to inline and DCE where that is profitable.
Since the state machine is actually common to both resumer and destroyer
functions, we make only a single function "actor" that contains both the
resume and destroy paths. The destroy function is represented by a small
stub that sets a value to signal the use of the destroy path and calls the
actor. The idea is that optimisation of the state machine need only be done
once - and then the resume and destroy paths can be identified allowing the
middle end's inline and DCE machinery to optimise as profitable as noted
above.
The middle end components for this implementation are:
A pass that:
1. Lowers the coroutine builtins that allow the standard library header to
interact with the coroutine frame (these fairly simple logical or
numerical substitution of values, given a coroutine frame pointer).
2. Lowers the IFN that represents the exit from state without cleanup.
Essentially, this becomes a gimple goto.
3. Sets the final size of the coroutine frame at this stage.
A second pass (that requires the revised CFG that results from the lowering
of the scope exit IFNs in the first).
1. Lower the IFNs that represent the state machine paths for the resume and
destroy cases.
Patches squashed into this commit:
[C++ coroutines 1] Common code and base definitions.
This part of the patch series provides the gating flag, the keywords,
cpp defines etc.
[C++ coroutines 2] Define builtins and internal functions.
This part of the patch series provides the builtin functions
used by the standard library code and the internal functions
used to implement lowering of the coroutine state machine.
[C++ coroutines 3] Front end parsing and transforms.
There are two parts to this.
1. Parsing, template instantiation and diagnostics for the standard-
mandated class entries.
The user authors a function that becomes a coroutine (lazily) by
making use of any of the co_await, co_yield or co_return keywords.
Unlike a regular function, where the activation record is placed on the
stack, and is destroyed on function exit, a coroutine has some state that
persists between calls - the 'coroutine frame' (thus analogous to a stack
frame).
We transform the user's function into three pieces:
1. A so-called ramp function, that establishes the coroutine frame and
begins execution of the coroutine.
2. An actor function that contains the state machine corresponding to the
user's suspend/resume structure.
3. A stub function that calls the actor function in 'destroy' mode.
The actor function is executed:
* from "resume point 0" by the ramp.
* from resume point N ( > 0 ) for handle.resume() calls.
* from the destroy stub for destroy point N for handle.destroy() calls.
The C++ coroutine design described in the standard makes use of some helper
methods that are authored in a so-called "promise" class provided by the
user.
At parse time (or post substitution) the type of the coroutine promise
will be determined. At that point, we can look up the required promise
class methods and issue diagnostics if they are missing or incorrect. To
avoid repeating these actions at code-gen time, we make use of temporary
'proxy' variables for the coroutine handle and the promise - which will
eventually be instantiated in the coroutine frame.
Each of the keywords will expand to a code sequence (although co_yield is
just syntactic sugar for a co_await).
We defer the analysis and transformatin until template expansion is
complete so that we have complete types at that time.
2. AST analysis and transformation which performs the code-gen for the
outlined state machine.
The entry point here is morph_fn_to_coro () which is called from
finish_function () when we have completed any template expansion.
This is preceded by helper functions that implement the phases below.
The process proceeds in four phases.
A Initial framing.
The user's function body is wrapped in the initial and final suspend
points and we begin building the coroutine frame.
We build empty decls for the actor and destroyer functions at this
time too.
When exceptions are enabled, the user's function body will also be
wrapped in a try-catch block with the catch invoking the promise
class 'unhandled_exception' method.
B Analysis.
The user's function body is analysed to determine the suspend points,
if any, and to capture local variables that might persist across such
suspensions. In most cases, it is not necessary to capture compiler
temporaries, since the tree-lowering nests the suspensions correctly.
However, in the case of a captured reference, there is a lifetime
extension to the end of the full expression - which can mean across a
suspend point in which case it must be promoted to a frame variable.
At the conclusion of analysis, we have a conservative frame layout and
maps of the local variables to their frame entry points.
C Build the ramp function.
Carry out the allocation for the coroutine frame (NOTE; the actual size
computation is deferred until late in the middle end to allow for future
optimisations that will be allowed to elide unused frame entries).
We build the return object.
D Build and expand the actor and destroyer function bodies.
The destroyer is a trivial shim that sets a bit to indicate that the
destroy dispatcher should be used and then calls into the actor.
The actor function is the implementation of the user's state machine.
The current suspend point is noted in an index.
Each suspend point is encoded as a pair of internal functions, one in
the relevant dispatcher, and one representing the suspend point.
During this process, the user's local variables and the proxies for the
self-handle and the promise class instanceare re-written to their
coroutine frame equivalents.
The complete bodies for the ramp, actor and destroy function are passed
back to finish_function for folding and gimplification.
[C++ coroutines 4] Middle end expanders and transforms.
The first part of this is a pass that provides:
* expansion of the library support builtins, these are simple boolean
or numerical substitutions.
* The functionality of implementing an exit from scope without cleanup
is performed here by lowering an IFN to a gimple goto.
This pass has to run for non-coroutine functions, since functions calling
the builtins are not necessarily coroutines (i.e. they are implementing the
library interfaces which may be called from anywhere).
The second part is the expansion of the coroutine IFNs that describe the
state machine connections to the dispatchers. This only has to be run
for functions that are coroutine components. The work done by this pass
is:
In the front end we construct a single actor function that contains
the coroutine state machine.
The actor function has three entry conditions:
1. from the ramp, resume point 0 - to initial-suspend.
2. when resume () is executed (resume point N).
3. from the destroy () shim when that is executed.
The actor function begins with two dispatchers; one for resume and
one for destroy (where the initial entry from the ramp is a special-
case of resume point 0).
Each suspend point and each dispatch entry is marked with an IFN such
that we can connect the relevant dispatchers to their target labels.
So, if we have:
CO_YIELD (NUM, FINAL, RES_LAB, DEST_LAB, FRAME_PTR)
This is await point NUM, and is the final await if FINAL is non-zero.
The resume point is RES_LAB, and the destroy point is DEST_LAB.
We expect to find a CO_ACTOR (NUM) in the resume dispatcher and a
CO_ACTOR (NUM+1) in the destroy dispatcher.
Initially, the intent of keeping the resume and destroy paths together
is that the conditionals controlling them are identical, and thus there
would be duplication of any optimisation of those paths if the split
were earlier.
Subsequent inlining of the actor (and DCE) is then able to extract the
resume and destroy paths as separate functions if that is found
profitable by the optimisers.
Once we have remade the connections to their correct postions, we elide
the labels that the front end inserted.
[C++ coroutines 5] Standard library header.
This provides the interfaces mandated by the standard and implements
the interaction with the coroutine frame by means of inline use of
builtins expanded at compile-time. There should be a 1:1 correspondence
with the standard sections which are cross-referenced.
There is no runtime content.
At this stage, we have the content in an inline namespace "__n4835" for
the CD we worked to.
[C++ coroutines 6] Testsuite.
There are two categories of test:
1. Checks for correctly formed source code and the error reporting.
2. Checks for transformation and code-gen.
The second set are run as 'torture' tests for the standard options
set, including LTO. These are also intentionally run with no options
provided (from the coroutines.exp script).
gcc/ChangeLog:
2020-01-18 Iain Sandoe <iain@sandoe.co.uk>
* Makefile.in: Add coroutine-passes.o.
* builtin-types.def (BT_CONST_SIZE): New.
(BT_FN_BOOL_PTR): New.
(BT_FN_PTR_PTR_CONST_SIZE_BOOL): New.
* builtins.def (DEF_COROUTINE_BUILTIN): New.
* coroutine-builtins.def: New file.
* coroutine-passes.cc: New file.
* function.h (struct GTY function): Add a bit to indicate that the
function is a coroutine component.
* internal-fn.c (expand_CO_FRAME): New.
(expand_CO_YIELD): New.
(expand_CO_SUSPN): New.
(expand_CO_ACTOR): New.
* internal-fn.def (CO_ACTOR): New.
(CO_YIELD): New.
(CO_SUSPN): New.
(CO_FRAME): New.
* passes.def: Add pass_coroutine_lower_builtins,
pass_coroutine_early_expand_ifns.
* tree-pass.h (make_pass_coroutine_lower_builtins): New.
(make_pass_coroutine_early_expand_ifns): New.
* doc/invoke.texi: Document the fcoroutines command line
switch.
gcc/c-family/ChangeLog:
2020-01-18 Iain Sandoe <iain@sandoe.co.uk>
* c-common.c (co_await, co_yield, co_return): New.
* c-common.h (RID_CO_AWAIT, RID_CO_YIELD,
RID_CO_RETURN): New enumeration values.
(D_CXX_COROUTINES): Bit to identify coroutines are active.
(D_CXX_COROUTINES_FLAGS): Guard for coroutine keywords.
* c-cppbuiltin.c (__cpp_coroutines): New cpp define.
* c.opt (fcoroutines): New command-line switch.
gcc/cp/ChangeLog:
2020-01-18 Iain Sandoe <iain@sandoe.co.uk>
* Make-lang.in: Add coroutines.o.
* cp-tree.h (lang_decl-fn): coroutine_p, new bit.
(DECL_COROUTINE_P): New.
* lex.c (init_reswords): Enable keywords when the coroutine flag
is set,
* operators.def (co_await): New operator.
* call.c (add_builtin_candidates): Handle CO_AWAIT_EXPR.
(op_error): Likewise.
(build_new_op_1): Likewise.
(build_new_function_call): Validate coroutine builtin arguments.
* constexpr.c (potential_constant_expression_1): Handle
CO_AWAIT_EXPR, CO_YIELD_EXPR, CO_RETURN_EXPR.
* coroutines.cc: New file.
* cp-objcp-common.c (cp_common_init_ts): Add CO_AWAIT_EXPR,
CO_YIELD_EXPR, CO_RETRN_EXPR as TS expressions.
* cp-tree.def (CO_AWAIT_EXPR, CO_YIELD_EXPR, (CO_RETURN_EXPR): New.
* cp-tree.h (coro_validate_builtin_call): New.
* decl.c (emit_coro_helper): New.
(finish_function): Handle the case when a function is found to
be a coroutine, perform the outlining and emit the outlined
functions. Set a bit to signal that this is a coroutine component.
* parser.c (enum required_token): New enumeration RT_CO_YIELD.
(cp_parser_unary_expression): Handle co_await.
(cp_parser_assignment_expression): Handle co_yield.
(cp_parser_statement): Handle RID_CO_RETURN.
(cp_parser_jump_statement): Handle co_return.
(cp_parser_operator): Handle co_await operator.
(cp_parser_yield_expression): New.
(cp_parser_required_error): Handle RT_CO_YIELD.
* pt.c (tsubst_copy): Handle CO_AWAIT_EXPR.
(tsubst_expr): Handle CO_AWAIT_EXPR, CO_YIELD_EXPR and
CO_RETURN_EXPRs.
* tree.c (cp_walk_subtrees): Likewise.
libstdc++-v3/ChangeLog:
2020-01-18 Iain Sandoe <iain@sandoe.co.uk>
* include/Makefile.am: Add coroutine to the std set.
* include/Makefile.in: Regenerated.
* include/std/coroutine: New file.
gcc/testsuite/ChangeLog:
2020-01-18 Iain Sandoe <iain@sandoe.co.uk>
* g++.dg/coroutines/co-await-syntax-00-needs-expr.C: New test.
* g++.dg/coroutines/co-await-syntax-01-outside-fn.C: New test.
* g++.dg/coroutines/co-await-syntax-02-outside-fn.C: New test.
* g++.dg/coroutines/co-await-syntax-03-auto.C: New test.
* g++.dg/coroutines/co-await-syntax-04-ctor-dtor.C: New test.
* g++.dg/coroutines/co-await-syntax-05-constexpr.C: New test.
* g++.dg/coroutines/co-await-syntax-06-main.C: New test.
* g++.dg/coroutines/co-await-syntax-07-varargs.C: New test.
* g++.dg/coroutines/co-await-syntax-08-lambda-auto.C: New test.
* g++.dg/coroutines/co-return-syntax-01-outside-fn.C: New test.
* g++.dg/coroutines/co-return-syntax-02-outside-fn.C: New test.
* g++.dg/coroutines/co-return-syntax-03-auto.C: New test.
* g++.dg/coroutines/co-return-syntax-04-ctor-dtor.C: New test.
* g++.dg/coroutines/co-return-syntax-05-constexpr-fn.C: New test.
* g++.dg/coroutines/co-return-syntax-06-main.C: New test.
* g++.dg/coroutines/co-return-syntax-07-vararg.C: New test.
* g++.dg/coroutines/co-return-syntax-08-bad-return.C: New test.
* g++.dg/coroutines/co-return-syntax-09-lambda-auto.C: New test.
* g++.dg/coroutines/co-yield-syntax-00-needs-expr.C: New test.
* g++.dg/coroutines/co-yield-syntax-01-outside-fn.C: New test.
* g++.dg/coroutines/co-yield-syntax-02-outside-fn.C: New test.
* g++.dg/coroutines/co-yield-syntax-03-auto.C: New test.
* g++.dg/coroutines/co-yield-syntax-04-ctor-dtor.C: New test.
* g++.dg/coroutines/co-yield-syntax-05-constexpr.C: New test.
* g++.dg/coroutines/co-yield-syntax-06-main.C: New test.
* g++.dg/coroutines/co-yield-syntax-07-varargs.C: New test.
* g++.dg/coroutines/co-yield-syntax-08-needs-expr.C: New test.
* g++.dg/coroutines/co-yield-syntax-09-lambda-auto.C: New test.
* g++.dg/coroutines/coro-builtins.C: New test.
* g++.dg/coroutines/coro-missing-gro.C: New test.
* g++.dg/coroutines/coro-missing-promise-yield.C: New test.
* g++.dg/coroutines/coro-missing-ret-value.C: New test.
* g++.dg/coroutines/coro-missing-ret-void.C: New test.
* g++.dg/coroutines/coro-missing-ueh-1.C: New test.
* g++.dg/coroutines/coro-missing-ueh-2.C: New test.
* g++.dg/coroutines/coro-missing-ueh-3.C: New test.
* g++.dg/coroutines/coro-missing-ueh.h: New test.
* g++.dg/coroutines/coro-pre-proc.C: New test.
* g++.dg/coroutines/coro.h: New file.
* g++.dg/coroutines/coro1-ret-int-yield-int.h: New file.
* g++.dg/coroutines/coroutines.exp: New file.
* g++.dg/coroutines/torture/alloc-00-gro-on-alloc-fail.C: New test.
* g++.dg/coroutines/torture/alloc-01-overload-newdel.C: New test.
* g++.dg/coroutines/torture/call-00-co-aw-arg.C: New test.
* g++.dg/coroutines/torture/call-01-multiple-co-aw.C: New test.
* g++.dg/coroutines/torture/call-02-temp-co-aw.C: New test.
* g++.dg/coroutines/torture/call-03-temp-ref-co-aw.C: New test.
* g++.dg/coroutines/torture/class-00-co-ret.C: New test.
* g++.dg/coroutines/torture/class-01-co-ret-parm.C: New test.
* g++.dg/coroutines/torture/class-02-templ-parm.C: New test.
* g++.dg/coroutines/torture/class-03-operator-templ-parm.C: New test.
* g++.dg/coroutines/torture/class-04-lambda-1.C: New test.
* g++.dg/coroutines/torture/class-05-lambda-capture-copy-local.C: New test.
* g++.dg/coroutines/torture/class-06-lambda-capture-ref.C: New test.
* g++.dg/coroutines/torture/co-await-00-trivial.C: New test.
* g++.dg/coroutines/torture/co-await-01-with-value.C: New test.
* g++.dg/coroutines/torture/co-await-02-xform.C: New test.
* g++.dg/coroutines/torture/co-await-03-rhs-op.C: New test.
* g++.dg/coroutines/torture/co-await-04-control-flow.C: New test.
* g++.dg/coroutines/torture/co-await-05-loop.C: New test.
* g++.dg/coroutines/torture/co-await-06-ovl.C: New test.
* g++.dg/coroutines/torture/co-await-07-tmpl.C: New test.
* g++.dg/coroutines/torture/co-await-08-cascade.C: New test.
* g++.dg/coroutines/torture/co-await-09-pair.C: New test.
* g++.dg/coroutines/torture/co-await-10-template-fn-arg.C: New test.
* g++.dg/coroutines/torture/co-await-11-forwarding.C: New test.
* g++.dg/coroutines/torture/co-await-12-operator-2.C: New test.
* g++.dg/coroutines/torture/co-await-13-return-ref.C: New test.
* g++.dg/coroutines/torture/co-ret-00-void-return-is-ready.C: New test.
* g++.dg/coroutines/torture/co-ret-01-void-return-is-suspend.C: New test.
* g++.dg/coroutines/torture/co-ret-03-different-GRO-type.C: New test.
* g++.dg/coroutines/torture/co-ret-04-GRO-nontriv.C: New test.
* g++.dg/coroutines/torture/co-ret-05-return-value.C: New test.
* g++.dg/coroutines/torture/co-ret-06-template-promise-val-1.C: New test.
* g++.dg/coroutines/torture/co-ret-07-void-cast-expr.C: New test.
* g++.dg/coroutines/torture/co-ret-08-template-cast-ret.C: New test.
* g++.dg/coroutines/torture/co-ret-09-bool-await-susp.C: New test.
* g++.dg/coroutines/torture/co-ret-10-expression-evaluates-once.C: New test.
* g++.dg/coroutines/torture/co-ret-11-co-ret-co-await.C: New test.
* g++.dg/coroutines/torture/co-ret-12-co-ret-fun-co-await.C: New test.
* g++.dg/coroutines/torture/co-ret-13-template-2.C: New test.
* g++.dg/coroutines/torture/co-ret-14-template-3.C: New test.
* g++.dg/coroutines/torture/co-yield-00-triv.C: New test.
* g++.dg/coroutines/torture/co-yield-01-multi.C: New test.
* g++.dg/coroutines/torture/co-yield-02-loop.C: New test.
* g++.dg/coroutines/torture/co-yield-03-tmpl.C: New test.
* g++.dg/coroutines/torture/co-yield-04-complex-local-state.C: New test.
* g++.dg/coroutines/torture/co-yield-05-co-aw.C: New test.
* g++.dg/coroutines/torture/co-yield-06-fun-parm.C: New test.
* g++.dg/coroutines/torture/co-yield-07-template-fn-param.C: New test.
* g++.dg/coroutines/torture/co-yield-08-more-refs.C: New test.
* g++.dg/coroutines/torture/co-yield-09-more-templ-refs.C: New test.
* g++.dg/coroutines/torture/coro-torture.exp: New file.
* g++.dg/coroutines/torture/exceptions-test-0.C: New test.
* g++.dg/coroutines/torture/func-params-00.C: New test.
* g++.dg/coroutines/torture/func-params-01.C: New test.
* g++.dg/coroutines/torture/func-params-02.C: New test.
* g++.dg/coroutines/torture/func-params-03.C: New test.
* g++.dg/coroutines/torture/func-params-04.C: New test.
* g++.dg/coroutines/torture/func-params-05.C: New test.
* g++.dg/coroutines/torture/func-params-06.C: New test.
* g++.dg/coroutines/torture/lambda-00-co-ret.C: New test.
* g++.dg/coroutines/torture/lambda-01-co-ret-parm.C: New test.
* g++.dg/coroutines/torture/lambda-02-co-yield-values.C: New test.
* g++.dg/coroutines/torture/lambda-03-auto-parm-1.C: New test.
* g++.dg/coroutines/torture/lambda-04-templ-parm.C: New test.
* g++.dg/coroutines/torture/lambda-05-capture-copy-local.C: New test.
* g++.dg/coroutines/torture/lambda-06-multi-capture.C: New test.
* g++.dg/coroutines/torture/lambda-07-multi-yield.C: New test.
* g++.dg/coroutines/torture/lambda-08-co-ret-parm-ref.C: New test.
* g++.dg/coroutines/torture/local-var-0.C: New test.
* g++.dg/coroutines/torture/local-var-1.C: New test.
* g++.dg/coroutines/torture/local-var-2.C: New test.
* g++.dg/coroutines/torture/local-var-3.C: New test.
* g++.dg/coroutines/torture/local-var-4.C: New test.
* g++.dg/coroutines/torture/mid-suspend-destruction-0.C: New test.
* g++.dg/coroutines/torture/pr92933.C: New test.
|
|
A prvalue can have void type, and if it doesn't do anything prohibited in a
constant expression, it's vacuously constant.
* constexpr.c (verify_constant): Allow void_node.
|
|
There were two issues in this PR:
1) We were crashing in is_really_empty_class because we say that the
internal RTTI types are classes, but never gave them TYPE_BINFO.
2) We were allowing the cast to a different pointer type because STRIP_NOPS
in cxx_fold_indirect_ref ignored REINTERPRET_CAST_P.
* rtti.c (get_tinfo_desc): Call xref_basetypes.
* constexpr.c (cxx_fold_indirect_ref): Don't strip
REINTERPRET_CAST_P.
|