aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-10-08 10:19:23 +0200
committerMartin Liska <mliska@suse.cz>2022-10-08 10:19:23 +0200
commitd9e7934d25da4a78ffef1f738206aa1d897911df (patch)
tree1bd1697c14259e095f4b4790946eae7df0c5a2e3 /gcc/cp
parentda0970e441345f8349522ff1abac5c223044ebb1 (diff)
parent6ffbf87ca66f4ed9cd79cff675fabe2109e46e85 (diff)
downloadgcc-d9e7934d25da4a78ffef1f738206aa1d897911df.zip
gcc-d9e7934d25da4a78ffef1f738206aa1d897911df.tar.gz
gcc-d9e7934d25da4a78ffef1f738206aa1d897911df.tar.bz2
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog151
-rw-r--r--gcc/cp/Make-lang.in2
-rw-r--r--gcc/cp/call.cc60
-rw-r--r--gcc/cp/constexpr.cc90
-rw-r--r--gcc/cp/coroutines.cc48
-rw-r--r--gcc/cp/cp-gimplify.cc92
-rw-r--r--gcc/cp/cp-tree.h17
-rw-r--r--gcc/cp/decl.cc2
-rw-r--r--gcc/cp/except.cc2
-rw-r--r--gcc/cp/init.cc50
-rw-r--r--gcc/cp/lex.cc4
-rw-r--r--gcc/cp/method.cc6
-rw-r--r--gcc/cp/module.cc43
-rw-r--r--gcc/cp/name-lookup.cc2
-rw-r--r--gcc/cp/parser.cc117
-rw-r--r--gcc/cp/pt.cc184
-rw-r--r--gcc/cp/semantics.cc87
-rw-r--r--gcc/cp/tree.cc16
-rw-r--r--gcc/cp/typeck.cc6
-rw-r--r--gcc/cp/typeck2.cc56
20 files changed, 709 insertions, 326 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index db6fea1..3aa9f03 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,154 @@
+2022-10-07 Marek Polacek <polacek@redhat.com>
+
+ PR c++/107085
+ * call.cc (conv_binds_ref_to_temporary): New.
+ (ref_conv_binds_directly): Rename to...
+ (ref_conv_binds_to_temporary): ...this. Use
+ conv_binds_ref_to_temporary.
+ * cp-tree.h (ref_conv_binds_directly): Rename to...
+ (ref_conv_binds_to_temporary): ...this.
+ * method.cc (ref_xes_from_temporary): Use ref_conv_binds_to_temporary.
+ * parser.cc (warn_for_range_copy): Likewise.
+
+2022-10-07 Qing Zhao <qing.zhao@oracle.com>
+
+ * module.cc (trees_out::core_bools): Stream out new bit
+ decl_not_flexarray.
+ (trees_in::core_bools): Stream in new bit decl_not_flexarray.
+
+2022-10-07 Patrick Palka <ppalka@redhat.com>
+
+ * module.cc (trees_out::mark_class_def): Guard against
+ DECL_BIT_FIELD_REPRESENTATIVE not being a decl.
+
+2022-10-07 Jason Merrill <jason@redhat.com>
+
+ * init.cc (expand_default_init): Also push the INIT_EXPR inside a
+ CLEANUP_POINT_EXPR.
+
+2022-10-07 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/104433
+ * module.cc (trees_out::core_bools): Don't override
+ DECL_EXTERNAL to true for static variables from an inline
+ function.
+
+2022-10-07 Martin Liska <mliska@suse.cz>
+
+ * module.cc (enum module_state_counts): Use array size.
+ * name-lookup.cc (class namespace_limit_reached): Likewise.
+ (class module_state): Move up in the file.
+
+2022-10-07 Jakub Jelinek <jakub@redhat.com>
+
+ * parser.cc (cp_parser_check_std_attribute): Only do checks if
+ attribute is a standard attribute or in gnu namespace and only
+ lookup other attributes in those namespaces.
+ * cp-gimplify.cc (lookup_hotness_attribute): Adjust function comment.
+ Only return true for standard attribute or gnu namespace attribute.
+ (remove_hotness_attribute): Only remove hotness attributes when
+ they are standard or in gnu namespace, implement it in a single
+ loop rather than former 4 now 8 remove_attribute calls.
+
+2022-10-06 Jason Merrill <jason@redhat.com>
+
+ * coroutines.cc (expand_one_await_expression): Change conversion
+ to VIEW_CONVERT_EXPR.
+ * cp-gimplify.cc (cp_genericize_r) [CONVERT_EXPR]: Add assert.
+
+2022-10-06 Joseph Myers <joseph@codesourcery.com>
+
+ * lex.cc (init_reswords): Handle D_EXT11.
+
+2022-10-06 Patrick Palka <ppalka@redhat.com>
+
+ * pt.cc (optimize_specialization_lookup_p): Remove.
+ (retrieve_specialization): Assume the above returns false
+ and simplify accordingly.
+ (register_specialization): Likewise.
+
+2022-10-06 Jakub Jelinek <jakub@redhat.com>
+
+ * parser.cc (cp_parser_omp_assumption_clauses): Emit IFN_ASSUME
+ call for holds clause on assume construct.
+
+2022-10-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/106654
+ * cp-tree.h (process_stmt_assume_attribute): Implement C++23
+ P1774R8 - Portable assumptions. Declare.
+ (diagnose_failing_condition): Declare.
+ (find_failing_clause): Likewise.
+ * parser.cc (assume_attr): New enumerator.
+ (cp_parser_parenthesized_expression_list): Handle assume_attr.
+ Remove identifier variable, for id_attr push the identifier into
+ expression_list right away instead of inserting it before all the
+ others at the end.
+ (cp_parser_conditional_expression): New function.
+ (cp_parser_constant_expression): Use it.
+ (cp_parser_statement): Handle assume attribute.
+ (cp_parser_expression_statement): Likewise.
+ (cp_parser_gnu_attribute_list): Use assume_attr for assume
+ attribute.
+ (cp_parser_std_attribute): Likewise. Handle standard assume
+ attribute like gnu::assume.
+ * cp-gimplify.cc (process_stmt_assume_attribute): New function.
+ * constexpr.cc: Include fold-const.h.
+ (find_failing_clause_r, find_failing_clause): New functions,
+ moved from semantics.cc with ctx argument added and if non-NULL,
+ call cxx_eval_constant_expression rather than fold_non_dependent_expr.
+ (cxx_eval_internal_function): Handle IFN_ASSUME.
+ (potential_constant_expression_1): Likewise.
+ * pt.cc (tsubst_copy_and_build): Likewise.
+ * semantics.cc (diagnose_failing_condition): New function.
+ (find_failing_clause_r, find_failing_clause): Moved to constexpr.cc.
+ (finish_static_assert): Use it. Add auto_diagnostic_group.
+
+2022-10-05 Jason Merrill <jason@redhat.com>
+
+ * tree.cc (lvalue_kind) [VIEW_CONVERT_EXPR]: Change prvalue to
+ xvalue.
+
+2022-10-04 Jason Merrill <jason@redhat.com>
+
+ PR c++/107154
+ * cp-gimplify.cc (cp_genericize_init_expr): Use iloc_sentinel.
+ (cp_genericize_target_expr): Likewise.
+
+2022-10-04 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/107136
+ * Make-lang.in (CP_PLUGIN_HEADERS): Add cp-trait.def.
+
+2022-10-04 Jakub Jelinek <jakub@redhat.com>
+
+ * cp-tree.h (struct omp_declare_target_attr): Rename to ...
+ (cp_omp_declare_target_attr): ... this. Add device_type member.
+ (omp_begin_assumes_data): Rename to ...
+ (cp_omp_begin_assumes_data): ... this.
+ (struct saved_scope): Change types of omp_declare_target_attribute
+ and omp_begin_assumes.
+ * parser.cc (cp_parser_omp_clause_device_type): Uncomment
+ check_no_duplicate_clause call.
+ (cp_parser_omp_all_clauses): Fix up pasto, c_name for OMP_CLAUSE_LINK
+ should be "link" rather than "to".
+ (cp_parser_omp_declare_target): Adjust for omp_declare_target_attr
+ to cp_omp_declare_target_attr changes, push -1 as device_type. Use
+ error_at rather than warning_at for declare target with only
+ device_type clauses.
+ (OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK): Define.
+ (cp_parser_omp_begin): Add begin declare target support. Adjust
+ for omp_begin_assumes_data to cp_omp_begin_assumes_data change.
+ (cp_parser_omp_end): Adjust for the
+ omp_declare_target_attr to cp_omp_declare_target_attr and
+ omp_begin_assumes_data to cp_omp_begin_assumes_data type changes,
+ adjust diagnostics wording and simplify format strings for easier
+ translations.
+ * semantics.cc (finish_translation_unit): Likewise.
+ * decl2.cc (cplus_decl_attributes): If device_type was present on
+ begin declare target, add "omp declare target host" and/or
+ "omp declare target nohost" attributes.
+
2022-10-03 Jakub Jelinek <jakub@redhat.com>
* cp-tree.h (BCS_STMT_EXPR): New enumerator.
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 38d8eee..aa84d68 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -39,7 +39,7 @@ CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
CXX_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo c++|sed '$(program_transform_name)')
GXX_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo g++|sed '$(program_transform_name)')
-CP_PLUGIN_HEADERS := cp-tree.h cxx-pretty-print.h name-lookup.h type-utils.h operators.def
+CP_PLUGIN_HEADERS := cp-tree.h cxx-pretty-print.h name-lookup.h type-utils.h operators.def cp-trait.def
#
# Define the names for selecting c++ in LANGUAGES.
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index bd04a1d..70ec964 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9144,7 +9144,7 @@ init_by_return_slot_p (tree exp)
Places that use this function (or _opt) to decide to elide a copy should
probably use make_safe_copy_elision instead. */
-static bool
+bool
unsafe_copy_elision_p (tree target, tree exp)
{
return unsafe_return_slot_p (target) && init_by_return_slot_p (exp);
@@ -9210,15 +9210,47 @@ conv_binds_ref_to_prvalue (conversion *c)
return conv_is_prvalue (next_conversion (c));
}
-/* Return tristate::TS_TRUE if converting EXPR to a reference type TYPE does
- not involve creating a temporary. Return tristate::TS_FALSE if converting
- EXPR to a reference type TYPE binds the reference to a temporary. If the
- conversion is invalid or bad, return tristate::TS_UNKNOWN. DIRECT_INIT_P
+/* True iff C is a conversion that binds a reference to a temporary.
+ This is a superset of conv_binds_ref_to_prvalue: here we're also
+ interested in xvalues. */
+
+static bool
+conv_binds_ref_to_temporary (conversion *c)
+{
+ if (conv_binds_ref_to_prvalue (c))
+ return true;
+ if (c->kind != ck_ref_bind)
+ return false;
+ c = next_conversion (c);
+ /* This is the case for
+ struct Base {};
+ struct Derived : Base {};
+ const Base& b(Derived{});
+ where we bind 'b' to the Base subobject of a temporary object of type
+ Derived. The subobject is an xvalue; the whole object is a prvalue. */
+ if (c->kind != ck_base)
+ return false;
+ c = next_conversion (c);
+ if (c->kind == ck_identity && c->u.expr)
+ {
+ tree expr = c->u.expr;
+ while (handled_component_p (expr))
+ expr = TREE_OPERAND (expr, 0);
+ if (TREE_CODE (expr) == TARGET_EXPR)
+ return true;
+ }
+ return false;
+}
+
+/* Return tristate::TS_TRUE if converting EXPR to a reference type TYPE binds
+ the reference to a temporary. Return tristate::TS_FALSE if converting
+ EXPR to a reference type TYPE doesn't bind the reference to a temporary. If
+ the conversion is invalid or bad, return tristate::TS_UNKNOWN. DIRECT_INIT_P
says whether the conversion should be done in direct- or copy-initialization
context. */
tristate
-ref_conv_binds_directly (tree type, tree expr, bool direct_init_p /*= false*/)
+ref_conv_binds_to_temporary (tree type, tree expr, bool direct_init_p/*=false*/)
{
gcc_assert (TYPE_REF_P (type));
@@ -9230,7 +9262,7 @@ ref_conv_binds_directly (tree type, tree expr, bool direct_init_p /*= false*/)
/*c_cast_p=*/false, flags, tf_none);
tristate ret (tristate::TS_UNKNOWN);
if (conv && !conv->bad_p)
- ret = tristate (!conv_binds_ref_to_prvalue (conv));
+ ret = tristate (conv_binds_ref_to_temporary (conv));
/* Free all the conversions we allocated. */
obstack_free (&conversion_obstack, p);
@@ -9909,7 +9941,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
&& !unsafe)
{
tree to = cp_build_fold_indirect_ref (fa);
- val = build2 (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
+ val = cp_build_init_expr (to, arg);
return val;
}
}
@@ -10068,7 +10100,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
}
call = cxx_constant_value (call, obj_arg, complain);
if (obj_arg && !error_operand_p (call))
- call = build2 (INIT_EXPR, void_type_node, obj_arg, call);
+ call = cp_build_init_expr (obj_arg, call);
call = convert_from_reference (call);
}
}
@@ -10733,7 +10765,7 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args,
check_self_delegation (arg);
/* Avoid change of behavior on Wunused-var-2.C. */
instance = mark_lvalue_use (instance);
- return build2 (INIT_EXPR, class_type, instance, arg);
+ return cp_build_init_expr (instance, arg);
}
}
@@ -11151,9 +11183,7 @@ build_new_method_call (tree instance, tree fns, vec<tree, va_gc> **args,
{
if (is_dummy_object (instance))
return get_target_expr (init, complain);
- init = build2 (INIT_EXPR, TREE_TYPE (instance), instance, init);
- TREE_SIDE_EFFECTS (init) = true;
- return init;
+ return cp_build_init_expr (instance, init);
}
/* Otherwise go ahead with overload resolution. */
@@ -11200,9 +11230,7 @@ build_new_method_call (tree instance, tree fns, vec<tree, va_gc> **args,
ctor = digest_init (basetype, ctor, complain);
if (ctor == error_mark_node)
return error_mark_node;
- ctor = build2 (INIT_EXPR, TREE_TYPE (instance), instance, ctor);
- TREE_SIDE_EFFECTS (ctor) = true;
- return ctor;
+ return cp_build_init_expr (instance, ctor);
}
}
if (complain & tf_error)
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index db7571d..06dcd71 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "opts.h"
#include "stringpool.h"
#include "attribs.h"
+#include "fold-const.h"
static bool verify_constant (tree, bool, bool *, bool *);
#define VERIFY_CONSTANT(X) \
@@ -1818,6 +1819,52 @@ cx_error_context (void)
return r;
}
+/* If we have a condition in conjunctive normal form (CNF), find the first
+ failing clause. In other words, given an expression like
+
+ true && true && false && true && false
+
+ return the first 'false'. EXPR is the expression. */
+
+static tree
+find_failing_clause_r (constexpr_ctx *ctx, tree expr)
+{
+ if (TREE_CODE (expr) == TRUTH_ANDIF_EXPR)
+ {
+ /* First check the left side... */
+ tree e = find_failing_clause_r (ctx, TREE_OPERAND (expr, 0));
+ if (e == NULL_TREE)
+ /* ...if we didn't find a false clause, check the right side. */
+ e = find_failing_clause_r (ctx, TREE_OPERAND (expr, 1));
+ return e;
+ }
+ tree e = contextual_conv_bool (expr, tf_none);
+ if (ctx)
+ {
+ bool new_non_constant_p = false, new_overflow_p = false;
+ e = cxx_eval_constant_expression (ctx, e, vc_prvalue,
+ &new_non_constant_p,
+ &new_overflow_p);
+ }
+ else
+ e = fold_non_dependent_expr (e, tf_none, /*manifestly_const_eval=*/true);
+ if (integer_zerop (e))
+ /* This is the failing clause. */
+ return expr;
+ return NULL_TREE;
+}
+
+/* Wrapper for find_failing_clause_r. */
+
+tree
+find_failing_clause (constexpr_ctx *ctx, tree expr)
+{
+ if (TREE_CODE (expr) == TRUTH_ANDIF_EXPR)
+ if (tree e = find_failing_clause_r (ctx, expr))
+ expr = e;
+ return expr;
+}
+
/* Evaluate a call T to a GCC internal function when possible and return
the evaluated result or, under the control of CTX, give an error, set
NON_CONSTANT_P, and return the unevaluated call T otherwise. */
@@ -1837,6 +1884,48 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
case IFN_FALLTHROUGH:
return void_node;
+ case IFN_ASSUME:
+ /* For now, restrict constexpr evaluation of [[assume (cond)]]
+ only to the cases which don't have side-effects. Evaluating
+ it even when it does would mean we'd need to somehow undo
+ all the side-effects e.g. in ctx->global->values. */
+ if (!TREE_SIDE_EFFECTS (CALL_EXPR_ARG (t, 0))
+ /* And it needs to be a potential constant expression. */
+ && potential_rvalue_constant_expression (CALL_EXPR_ARG (t, 0)))
+ {
+ constexpr_ctx new_ctx = *ctx;
+ new_ctx.quiet = true;
+ tree arg = CALL_EXPR_ARG (t, 0);
+ bool new_non_constant_p = false, new_overflow_p = false;
+ arg = cxx_eval_constant_expression (&new_ctx, arg, vc_prvalue,
+ &new_non_constant_p,
+ &new_overflow_p);
+ if (!new_non_constant_p && !new_overflow_p && integer_zerop (arg))
+ {
+ if (!*non_constant_p && !ctx->quiet)
+ {
+ /* See if we can find which clause was failing
+ (for logical AND). */
+ tree bad = find_failing_clause (&new_ctx,
+ CALL_EXPR_ARG (t, 0));
+ /* If not, or its location is unusable, fall back to the
+ previous location. */
+ location_t cloc = cp_expr_loc_or_loc (bad, EXPR_LOCATION (t));
+
+ auto_diagnostic_group d;
+
+ /* Report the error. */
+ error_at (cloc,
+ "failed %<assume%> attribute assumption");
+ diagnose_failing_condition (bad, cloc, false);
+ }
+
+ *non_constant_p = true;
+ return t;
+ }
+ }
+ return void_node;
+
case IFN_ADD_OVERFLOW:
opcode = PLUS_EXPR;
break;
@@ -8706,6 +8795,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
case IFN_UBSAN_BOUNDS:
case IFN_UBSAN_VPTR:
case IFN_FALLTHROUGH:
+ case IFN_ASSUME:
return true;
case IFN_ADD_OVERFLOW:
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index eca01ab..01a3e83 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1728,8 +1728,11 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d)
}
else
{
- r = build1_loc (loc, CONVERT_EXPR, void_coro_handle_type, suspend);
- r = build2_loc (loc, INIT_EXPR, void_coro_handle_type, data->conthand, r);
+ r = suspend;
+ if (!same_type_ignoring_top_level_qualifiers_p (susp_type,
+ void_coro_handle_type))
+ r = build1_loc (loc, VIEW_CONVERT_EXPR, void_coro_handle_type, r);
+ r = cp_build_init_expr (loc, data->conthand, r);
r = build1 (CONVERT_EXPR, void_type_node, r);
append_to_statement_list (r, &body_list);
is_cont = true;
@@ -1752,7 +1755,7 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d)
r = build_call_expr_internal_loc (loc, IFN_CO_YIELD, integer_type_node, 5,
susp_idx, final_susp, r_l, d_l,
data->coro_fp);
- r = build2 (INIT_EXPR, integer_type_node, cond, r);
+ r = cp_build_init_expr (cond, r);
finish_switch_cond (r, sw);
r = build_case_label (build_int_cst (integer_type_node, 0), NULL_TREE,
create_anon_label_with_ctx (loc, actor));
@@ -2301,7 +2304,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
vec<tree, va_gc> *args = make_tree_vector_single (r);
tree hfa = build_new_method_call (ash, hfa_m, &args, NULL_TREE, LOOKUP_NORMAL,
NULL, tf_warning_or_error);
- r = build2 (INIT_EXPR, handle_type, ash, hfa);
+ r = cp_build_init_expr (ash, hfa);
r = coro_build_cvt_void_expr_stmt (r, loc);
add_stmt (r);
release_tree_vector (args);
@@ -2773,17 +2776,19 @@ flatten_await_stmt (var_nest_node *n, hash_set<tree> *promoted,
if (!VOID_TYPE_P (TREE_TYPE (then_cl)))
{
gcc_checking_assert (TREE_CODE (then_cl) != STATEMENT_LIST);
- then_cl
- = build2 (init_expr ? INIT_EXPR : MODIFY_EXPR, var_type,
- var, then_cl);
+ if (init_expr)
+ then_cl = cp_build_init_expr (var, then_cl);
+ else
+ then_cl = build2 (MODIFY_EXPR, var_type, var, then_cl);
}
tree else_cl = COND_EXPR_ELSE (old_expr);
if (!VOID_TYPE_P (TREE_TYPE (else_cl)))
{
gcc_checking_assert (TREE_CODE (else_cl) != STATEMENT_LIST);
- else_cl
- = build2 (init_expr ? INIT_EXPR : MODIFY_EXPR, var_type,
- var, else_cl);
+ if (init_expr)
+ else_cl = cp_build_init_expr (var, else_cl);
+ else
+ else_cl = build2 (MODIFY_EXPR, var_type, var, else_cl);
}
n->init = build3 (COND_EXPR, var_type, cond, then_cl, else_cl);
}
@@ -2801,7 +2806,7 @@ flatten_await_stmt (var_nest_node *n, hash_set<tree> *promoted,
DECL_ARTIFICIAL (cond_var) = true;
layout_decl (cond_var, 0);
gcc_checking_assert (!TYPE_NEEDS_CONSTRUCTING (cond_type));
- cond = build2 (INIT_EXPR, cond_type, cond_var, cond);
+ cond = cp_build_init_expr (cond_var, cond);
var_nest_node *ins
= new var_nest_node (cond_var, cond, n->prev, n);
COND_EXPR_COND (n->init) = cond_var;
@@ -2954,8 +2959,7 @@ handle_nested_conditionals (var_nest_node *n, vec<tree>& list,
expression that performs the init and then records that the
variable is live (and the DTOR should be run at the scope
exit. */
- tree set_flag = build2 (INIT_EXPR, boolean_type_node,
- flag, boolean_true_node);
+ tree set_flag = cp_build_init_expr (flag, boolean_true_node);
n->init
= build2 (COMPOUND_EXPR, boolean_type_node, n->init, set_flag);
}
@@ -3468,8 +3472,7 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d)
/* We want to initialize the new variable with the expression
that contains the await(s) and potentially also needs to
have truth_if expressions expanded. */
- tree new_s = build2_loc (sloc, INIT_EXPR, boolean_type_node,
- newvar, cond_inner);
+ tree new_s = cp_build_init_expr (sloc, newvar, cond_inner);
finish_expr_stmt (new_s);
IF_COND (if_stmt) = newvar;
add_stmt (if_stmt);
@@ -3653,7 +3656,7 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d)
if (TREE_CODE (cond_inner) == CLEANUP_POINT_EXPR)
cond_inner = TREE_OPERAND (cond_inner, 0);
location_t sloc = EXPR_LOCATION (SWITCH_STMT_COND (sw_stmt));
- tree new_s = build2_loc (sloc, INIT_EXPR, sw_type, newvar,
+ tree new_s = cp_build_init_expr (sloc, newvar,
cond_inner);
finish_expr_stmt (new_s);
SWITCH_STMT_COND (sw_stmt) = newvar;
@@ -4732,7 +4735,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
}
tree allocated = build1 (CONVERT_EXPR, coro_frame_ptr, new_fn);
- tree r = build2 (INIT_EXPR, TREE_TYPE (coro_fp), coro_fp, allocated);
+ tree r = cp_build_init_expr (coro_fp, allocated);
r = coro_build_cvt_void_expr_stmt (r, fn_start);
add_stmt (r);
@@ -4793,7 +4796,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
1, 0,tf_warning_or_error);
tree fnf_x = build_class_member_access_expr (deref_fp, fnf_m, NULL_TREE,
false, tf_warning_or_error);
- r = build2 (INIT_EXPR, boolean_type_node, fnf_x, boolean_true_node);
+ r = cp_build_init_expr (fnf_x, boolean_true_node);
r = coro_build_cvt_void_expr_stmt (r, fn_start);
add_stmt (r);
@@ -4805,7 +4808,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
/*protect=*/1, /*want_type=*/0, tf_warning_or_error);
tree resume_x = build_class_member_access_expr (deref_fp, resume_m, NULL_TREE,
false, tf_warning_or_error);
- r = build2_loc (fn_start, INIT_EXPR, act_des_fn_ptr, resume_x, actor_addr);
+ r = cp_build_init_expr (fn_start, resume_x, actor_addr);
finish_expr_stmt (r);
tree destroy_addr = build1 (ADDR_EXPR, act_des_fn_ptr, destroy);
@@ -4815,7 +4818,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
tree destroy_x
= build_class_member_access_expr (deref_fp, destroy_m, NULL_TREE, false,
tf_warning_or_error);
- r = build2_loc (fn_start, INIT_EXPR, act_des_fn_ptr, destroy_x, destroy_addr);
+ r = cp_build_init_expr (fn_start, destroy_x, destroy_addr);
finish_expr_stmt (r);
/* [dcl.fct.def.coroutine] /13
@@ -5008,8 +5011,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
release_tree_vector (arg);
}
else
- r = build2_loc (fn_start, INIT_EXPR, gro_type,
- DECL_RESULT (orig), get_ro);
+ r = cp_build_init_expr (fn_start, DECL_RESULT (orig), get_ro);
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (gro_type))
/* If some part of the initalization code (prior to the await_resume
@@ -5064,7 +5066,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
= build_class_member_access_expr (deref_fp, resume_idx_m, NULL_TREE, false,
tf_warning_or_error);
r = build_int_cst (short_unsigned_type_node, 0);
- r = build2_loc (fn_start, INIT_EXPR, short_unsigned_type_node, resume_idx, r);
+ r = cp_build_init_expr (fn_start, resume_idx, r);
r = coro_build_cvt_void_expr_stmt (r, fn_start);
add_stmt (r);
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index cca3b9f..d0e12c9 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -250,6 +250,7 @@ cp_gimplify_init_expr (tree *expr_p)
if (TREE_CODE (from) == TARGET_EXPR)
if (tree init = TARGET_EXPR_INITIAL (from))
{
+ gcc_checking_assert (TARGET_EXPR_ELIDING_P (from));
if (target_expr_needs_replace (from))
{
/* If this was changed by cp_genericize_target_expr, we need to
@@ -745,6 +746,11 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
/* A TARGET_EXPR that expresses direct-initialization should have been
elided by cp_gimplify_init_expr. */
gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P (*expr_p));
+ /* Likewise, but allow extra temps of trivial type so that
+ gimplify_init_ctor_preeval can materialize subobjects of a CONSTRUCTOR
+ on the rhs of an assignment, as in constexpr-aggr1.C. */
+ gcc_checking_assert (!TARGET_EXPR_ELIDING_P (*expr_p)
+ || !TREE_ADDRESSABLE (TREE_TYPE (*expr_p)));
ret = GS_UNHANDLED;
break;
@@ -920,6 +926,7 @@ cp_genericize_init (tree *replace, tree from, tree to)
static void
cp_genericize_init_expr (tree *stmt_p)
{
+ iloc_sentinel ils = EXPR_LOCATION (*stmt_p);
tree to = TREE_OPERAND (*stmt_p, 0);
tree from = TREE_OPERAND (*stmt_p, 1);
if (SIMPLE_TARGET_EXPR_P (from)
@@ -935,6 +942,7 @@ cp_genericize_init_expr (tree *stmt_p)
static void
cp_genericize_target_expr (tree *stmt_p)
{
+ iloc_sentinel ils = EXPR_LOCATION (*stmt_p);
tree slot = TARGET_EXPR_SLOT (*stmt_p);
cp_genericize_init (&TARGET_EXPR_INITIAL (*stmt_p),
TARGET_EXPR_INITIAL (*stmt_p), slot);
@@ -1108,7 +1116,10 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
cp_walk_tree (&init, cp_fold_r, data, NULL);
*walk_subtrees = 0;
if (TREE_CODE (init) == TARGET_EXPR)
- *stmt_p = init;
+ {
+ TARGET_EXPR_ELIDING_P (init) = TARGET_EXPR_ELIDING_P (stmt);
+ *stmt_p = init;
+ }
}
break;
@@ -1587,6 +1598,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
break;
case CONVERT_EXPR:
+ gcc_checking_assert (!AGGREGATE_TYPE_P (TREE_TYPE (stmt)));
gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt));
break;
@@ -2899,7 +2911,7 @@ cp_fold (tree x)
loc = EXPR_LOCATION (x);
tree s = build_fold_indirect_ref_loc (loc,
CALL_EXPR_ARG (x, 0));
- r = build2_loc (loc, INIT_EXPR, TREE_TYPE (s), s, r);
+ r = cp_build_init_expr (s, r);
}
x = r;
break;
@@ -3025,7 +3037,7 @@ cp_fold (tree x)
return x;
}
-/* Look up either "hot" or "cold" in attribute list LIST. */
+/* Look up "hot", "cold", "likely" or "unlikely" in attribute list LIST. */
tree
lookup_hotness_attribute (tree list)
@@ -3033,24 +3045,36 @@ lookup_hotness_attribute (tree list)
for (; list; list = TREE_CHAIN (list))
{
tree name = get_attribute_name (list);
- if (is_attribute_p ("hot", name)
- || is_attribute_p ("cold", name)
- || is_attribute_p ("likely", name)
- || is_attribute_p ("unlikely", name))
+ if ((is_attribute_p ("hot", name)
+ || is_attribute_p ("cold", name)
+ || is_attribute_p ("likely", name)
+ || is_attribute_p ("unlikely", name))
+ && is_attribute_namespace_p ("", list))
break;
}
return list;
}
-/* Remove both "hot" and "cold" attributes from LIST. */
+/* Remove "hot", "cold", "likely" and "unlikely" attributes from LIST. */
static tree
remove_hotness_attribute (tree list)
{
- list = remove_attribute ("hot", list);
- list = remove_attribute ("cold", list);
- list = remove_attribute ("likely", list);
- list = remove_attribute ("unlikely", list);
+ for (tree *p = &list; *p; )
+ {
+ tree l = *p;
+ tree name = get_attribute_name (l);
+ if ((is_attribute_p ("hot", name)
+ || is_attribute_p ("cold", name)
+ || is_attribute_p ("likely", name)
+ || is_attribute_p ("unlikely", name))
+ && is_attribute_namespace_p ("", l))
+ {
+ *p = TREE_CHAIN (l);
+ continue;
+ }
+ p = &TREE_CHAIN (l);
+ }
return list;
}
@@ -3079,6 +3103,50 @@ process_stmt_hotness_attribute (tree std_attrs, location_t attrs_loc)
return std_attrs;
}
+/* If [[assume (cond)]] appears on this statement, handle it. */
+
+tree
+process_stmt_assume_attribute (tree std_attrs, tree statement,
+ location_t attrs_loc)
+{
+ if (std_attrs == error_mark_node)
+ return std_attrs;
+ tree attr = lookup_attribute ("gnu", "assume", std_attrs);
+ if (!attr)
+ return std_attrs;
+ /* The next token after the assume attribute is not ';'. */
+ if (statement)
+ {
+ warning_at (attrs_loc, OPT_Wattributes,
+ "%<assume%> attribute not followed by %<;%>");
+ attr = NULL_TREE;
+ }
+ for (; attr; attr = lookup_attribute ("gnu", "assume", TREE_CHAIN (attr)))
+ {
+ tree args = TREE_VALUE (attr);
+ int nargs = list_length (args);
+ if (nargs != 1)
+ {
+ auto_diagnostic_group d;
+ error_at (attrs_loc, "wrong number of arguments specified for "
+ "%qE attribute", get_attribute_name (attr));
+ inform (attrs_loc, "expected %i, found %i", 1, nargs);
+ }
+ else
+ {
+ tree arg = TREE_VALUE (args);
+ if (!type_dependent_expression_p (arg))
+ arg = contextual_conv_bool (arg, tf_warning_or_error);
+ if (error_operand_p (arg))
+ continue;
+ statement = build_call_expr_internal_loc (attrs_loc, IFN_ASSUME,
+ void_type_node, 1, arg);
+ finish_expr_stmt (statement);
+ }
+ }
+ return remove_attribute ("gnu", "assume", std_attrs);
+}
+
/* Helper of fold_builtin_source_location, return the
std::source_location::__impl type after performing verification
on it. LOC is used for reporting any errors. */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8cf9707..ab6f85a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -505,6 +505,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
DECL_MODULE_EXPORT_P (in _DECL)
PACK_EXPANSION_FORCE_EXTRA_ARGS_P (in *_PACK_EXPANSION)
LAMBDA_EXPR_STATIC_P (in LAMBDA_EXPR)
+ TARGET_EXPR_ELIDING_P (in TARGET_EXPR)
4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
CALL_EXPR, or FIELD_DECL).
@@ -5370,6 +5371,11 @@ get_vec_init_expr (tree t)
#define TARGET_EXPR_DIRECT_INIT_P(NODE) \
TREE_LANG_FLAG_2 (TARGET_EXPR_CHECK (NODE))
+/* True if we expect this TARGET_EXPR to be used as an initializer, not to
+ materialize as a temporary. */
+#define TARGET_EXPR_ELIDING_P(NODE) \
+ TREE_LANG_FLAG_3 (TARGET_EXPR_CHECK (NODE))
+
/* True if NODE is a TARGET_EXPR that just expresses a copy of its INITIAL; if
the initializer has void type, it's doing something more complicated. */
#define SIMPLE_TARGET_EXPR_P(NODE) \
@@ -6534,7 +6540,7 @@ extern bool sufficient_parms_p (const_tree);
extern tree type_decays_to (tree);
extern tree extract_call_expr (tree);
extern tree build_trivial_dtor_call (tree, bool = false);
-extern tristate ref_conv_binds_directly (tree, tree, bool = false);
+extern tristate ref_conv_binds_to_temporary (tree, tree, bool = false);
extern tree build_user_type_conversion (tree, tree, int,
tsubst_flags_t);
extern tree build_new_function_call (tree, vec<tree, va_gc> **,
@@ -6657,6 +6663,7 @@ extern bool is_list_ctor (tree);
extern void validate_conversion_obstack (void);
extern void mark_versions_used (tree);
extern int unsafe_return_slot_p (tree);
+extern bool unsafe_copy_elision_p (tree, tree);
extern bool make_safe_copy_elision (tree, tree);
extern bool cp_handle_deprecated_or_unavailable (tree, tsubst_flags_t = tf_warning_or_error);
extern void cp_warn_deprecated_use_scopes (tree);
@@ -7715,6 +7722,7 @@ extern tree build_transaction_expr (location_t, tree, int, tree);
extern bool cxx_omp_create_clause_info (tree, tree, bool, bool,
bool, bool);
extern tree baselink_for_fns (tree);
+extern void diagnose_failing_condition (tree, location_t, bool);
extern void finish_static_assert (tree, tree, location_t,
bool, bool);
extern tree finish_decltype_type (tree, bool, tsubst_flags_t);
@@ -8181,6 +8189,10 @@ extern tree build_functional_cast (location_t, tree, tree,
tsubst_flags_t);
extern tree add_exception_specifier (tree, tree, tsubst_flags_t);
extern tree merge_exception_specifiers (tree, tree);
+extern void set_target_expr_eliding (tree);
+extern tree cp_build_init_expr (location_t, tree, tree);
+inline tree cp_build_init_expr (tree t, tree i)
+{ return cp_build_init_expr (input_location, t, i); }
/* in mangle.cc */
extern void init_mangle (void);
@@ -8242,6 +8254,7 @@ extern tree predeclare_vla (tree);
extern void clear_fold_cache (void);
extern tree lookup_hotness_attribute (tree);
extern tree process_stmt_hotness_attribute (tree, location_t);
+extern tree process_stmt_assume_attribute (tree, tree, location_t);
extern bool simple_empty_class_p (tree, tree, tree_code);
extern tree fold_builtin_source_location (location_t);
@@ -8447,6 +8460,8 @@ extern tree fold_sizeof_expr (tree);
extern void clear_cv_and_fold_caches (void);
extern tree unshare_constructor (tree CXX_MEM_STAT_INFO);
extern bool decl_implicit_constexpr_p (tree);
+struct constexpr_ctx;
+extern tree find_failing_clause (constexpr_ctx *ctx, tree);
extern bool replace_decl (tree *, tree, tree);
/* An RAII sentinel used to restrict constexpr evaluation so that it
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 07148b9..82eb0c2 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -7500,7 +7500,7 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
}
if (init && init != error_mark_node)
- init_code = build2 (INIT_EXPR, type, decl, init);
+ init_code = cp_build_init_expr (decl, init);
if (init_code && !TREE_SIDE_EFFECTS (init_code)
&& init_code != error_mark_node)
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index 048612d..b8a85ed 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -755,7 +755,7 @@ build_throw (location_t loc, tree exp)
tree tmp = decay_conversion (exp, tf_warning_or_error);
if (tmp == error_mark_node)
return error_mark_node;
- exp = build2 (INIT_EXPR, temp_type, object, tmp);
+ exp = cp_build_init_expr (object, tmp);
}
/* Mark any cleanups from the initialization as MUST_NOT_THROW, since
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index bf46578..3d5d390 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -686,6 +686,8 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain)
/* Now put it back so C++17 copy elision works. */
init = get_target_expr (init);
+ set_target_expr_eliding (init);
+
current_class_ptr = save_ccp;
current_class_ref = save_ccr;
return init;
@@ -1006,7 +1008,7 @@ perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
if (TREE_CODE (type) == ARRAY_TYPE)
{
init = build_vec_init_expr (type, init, tf_warning_or_error);
- init = build2 (INIT_EXPR, type, decl, init);
+ init = cp_build_init_expr (decl, init);
finish_expr_stmt (init);
}
else
@@ -1014,7 +1016,7 @@ perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
tree value = build_value_init (type, tf_warning_or_error);
if (value == error_mark_node)
return;
- init = build2 (INIT_EXPR, type, decl, value);
+ init = cp_build_init_expr (decl, value);
finish_expr_stmt (init);
}
}
@@ -1025,7 +1027,7 @@ perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
{
if (init)
{
- init = build2 (INIT_EXPR, type, decl, TREE_VALUE (init));
+ init = cp_build_init_expr (decl, TREE_VALUE (init));
finish_expr_stmt (init);
}
}
@@ -1062,7 +1064,7 @@ perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type)))
init = build_vec_init_expr (type, init, tf_warning_or_error);
- init = build2 (INIT_EXPR, type, decl, init);
+ init = cp_build_init_expr (decl, init);
finish_expr_stmt (init);
FOR_EACH_VEC_ELT (*cleanups, i, t)
push_cleanup (NULL_TREE, t, false);
@@ -1081,7 +1083,7 @@ perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
/* Initialize the array only if it's not a flexible
array member (i.e., if it has an upper bound). */
init = build_vec_init_expr (type, init, tf_warning_or_error);
- init = build2 (INIT_EXPR, type, decl, init);
+ init = cp_build_init_expr (decl, init);
finish_expr_stmt (init);
}
}
@@ -2097,7 +2099,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
complete objects. */
gcc_assert (TREE_CODE (init) == CONSTRUCTOR || true_exp == exp);
- init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init);
+ init = cp_build_init_expr (exp, init);
TREE_SIDE_EFFECTS (init) = 1;
finish_expr_stmt (init);
return true;
@@ -2124,19 +2126,19 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
return false;
}
- if (TREE_CODE (init) == MUST_NOT_THROW_EXPR)
- /* We need to protect the initialization of a catch parm with a
- call to terminate(), which shows up as a MUST_NOT_THROW_EXPR
- around the TARGET_EXPR for the copy constructor. See
- initialize_handler_parm. */
+ /* We need to protect the initialization of a catch parm with a
+ call to terminate(), which shows up as a MUST_NOT_THROW_EXPR
+ around the TARGET_EXPR for the copy constructor. See
+ initialize_handler_parm. */
+ tree *p = &init;
+ while (TREE_CODE (*p) == MUST_NOT_THROW_EXPR
+ || TREE_CODE (*p) == CLEANUP_POINT_EXPR)
{
- TREE_OPERAND (init, 0) = build2 (INIT_EXPR, TREE_TYPE (exp), exp,
- TREE_OPERAND (init, 0));
- TREE_TYPE (init) = void_type_node;
+ /* Avoid voidify_wrapper_expr making a temporary. */
+ TREE_TYPE (*p) = void_type_node;
+ p = &TREE_OPERAND (*p, 0);
}
- else
- init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init);
- TREE_SIDE_EFFECTS (init) = 1;
+ *p = cp_build_init_expr (exp, *p);
finish_expr_stmt (init);
return true;
}
@@ -2201,7 +2203,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
{
tree e = maybe_constant_init (rval, exp);
if (TREE_CONSTANT (e))
- rval = build2 (INIT_EXPR, type, exp, e);
+ rval = cp_build_init_expr (exp, e);
}
}
@@ -2289,7 +2291,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
field_size = TYPE_SIZE (CLASSTYPE_AS_BASE (type));
init = build_zero_init_1 (type, NULL_TREE, /*static_storage_p=*/false,
field_size);
- init = build2 (INIT_EXPR, type, exp, init);
+ init = cp_build_init_expr (exp, init);
finish_expr_stmt (init);
}
@@ -3677,7 +3679,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
tree val = build_value_init (type, complain | tf_no_cleanup);
if (val == error_mark_node)
return error_mark_node;
- init_expr = build2 (INIT_EXPR, type, init_expr, val);
+ init_expr = cp_build_init_expr (init_expr, val);
}
else
{
@@ -4429,7 +4431,7 @@ build_vec_init (tree base, tree maxindex, tree init,
if (BRACE_ENCLOSED_INITIALIZER_P (init))
init = digest_init (atype, init, complain);
- stmt_expr = build2 (INIT_EXPR, atype, base, init);
+ stmt_expr = cp_build_init_expr (base, init);
return stmt_expr;
}
@@ -4601,7 +4603,7 @@ build_vec_init (tree base, tree maxindex, tree init,
gcc_checking_assert (!target_expr_needs_replace (elt));
if (digested)
- one_init = build2 (INIT_EXPR, type, baseref, elt);
+ one_init = cp_build_init_expr (baseref, elt);
else if (tree vi = get_vec_init_expr (elt))
one_init = expand_vec_init_expr (baseref, vi, complain, flags);
else if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
@@ -4622,7 +4624,7 @@ build_vec_init (tree base, tree maxindex, tree init,
if (do_static_init)
one_init = NULL_TREE;
else
- one_init = build2 (INIT_EXPR, type, baseref, e);
+ one_init = cp_build_init_expr (baseref, e);
}
else
{
@@ -4804,7 +4806,7 @@ build_vec_init (tree base, tree maxindex, tree init,
{
elt_init = build_value_init (type, complain);
if (elt_init != error_mark_node)
- elt_init = build2 (INIT_EXPR, type, to, elt_init);
+ elt_init = cp_build_init_expr (to, elt_init);
}
else
{
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 0b121a9..22d1ab9 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -241,9 +241,9 @@ init_reswords (void)
if (!flag_char8_t)
mask |= D_CXX_CHAR8_T;
if (flag_no_asm)
- mask |= D_ASM | D_EXT;
+ mask |= D_ASM | D_EXT | D_EXT11;
if (flag_no_gnu_keywords)
- mask |= D_EXT;
+ mask |= D_EXT | D_EXT11;
/* The Objective-C keywords are all context-dependent. */
mask |= D_OBJC;
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 55af5c4..c217d7e 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -680,7 +680,7 @@ do_build_copy_constructor (tree fndecl)
else if (tree_int_cst_equal (TYPE_SIZE (current_class_type),
CLASSTYPE_SIZE (current_class_type)))
{
- tree t = build2 (INIT_EXPR, void_type_node, current_class_ref, parm);
+ tree t = cp_build_init_expr (current_class_ref, parm);
finish_expr_stmt (t);
}
else
@@ -695,7 +695,7 @@ do_build_copy_constructor (tree fndecl)
current_class_ptr, alias_set);
tree rhs = build2 (MEM_REF, array_type,
TREE_OPERAND (parm, 0), alias_set);
- tree t = build2 (INIT_EXPR, void_type_node, lhs, rhs);
+ tree t = cp_build_init_expr (lhs, rhs);
finish_expr_stmt (t);
}
}
@@ -2233,7 +2233,7 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p)
tree val = build_stub_object (from);
if (!TYPE_REF_P (from) && TREE_CODE (from) != FUNCTION_TYPE)
val = CLASS_TYPE_P (from) ? force_rvalue (val, tf_none) : rvalue (val);
- return ref_conv_binds_directly (to, val, direct_init_p).is_false ();
+ return ref_conv_binds_to_temporary (to, val, direct_init_p).is_true ();
}
/* Worker for is_{,nothrow_}convertible. Attempt to perform an implicit
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 500ac06..4d27ceb 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -3469,6 +3469,20 @@ enum streamed_extensions {
SE_BITS = 1
};
+/* Counter indices. */
+enum module_state_counts
+{
+ MSC_sec_lwm,
+ MSC_sec_hwm,
+ MSC_pendings,
+ MSC_entities,
+ MSC_namespaces,
+ MSC_bindings,
+ MSC_macros,
+ MSC_inits,
+ MSC_HWM
+};
+
/********************************************************************/
struct module_state_config;
@@ -3666,8 +3680,8 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state {
private:
void write_config (elf_out *to, struct module_state_config &, unsigned crc);
bool read_config (struct module_state_config &);
- static void write_counts (elf_out *to, unsigned [], unsigned *crc_ptr);
- bool read_counts (unsigned []);
+ static void write_counts (elf_out *to, unsigned [MSC_HWM], unsigned *crc_ptr);
+ bool read_counts (unsigned *);
public:
void note_cmi_name ();
@@ -5397,6 +5411,9 @@ trees_out::core_bools (tree t)
case VAR_DECL:
if (TREE_PUBLIC (t)
+ && !(TREE_STATIC (t)
+ && DECL_FUNCTION_SCOPE_P (t)
+ && DECL_DECLARED_INLINE_P (DECL_CONTEXT (t)))
&& !DECL_VAR_DECLARED_INLINE_P (t))
is_external = true;
break;
@@ -5416,6 +5433,7 @@ trees_out::core_bools (tree t)
WB (t->decl_common.decl_by_reference_flag);
WB (t->decl_common.decl_read_flag);
WB (t->decl_common.decl_nonshareable_flag);
+ WB (t->decl_common.decl_not_flexarray);
}
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
@@ -5560,6 +5578,7 @@ trees_in::core_bools (tree t)
RB (t->decl_common.decl_by_reference_flag);
RB (t->decl_common.decl_read_flag);
RB (t->decl_common.decl_nonshareable_flag);
+ RB (t->decl_common.decl_not_flexarray);
}
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
@@ -11902,7 +11921,11 @@ trees_out::mark_class_def (tree defn)
mark_class_member (member);
if (TREE_CODE (member) == FIELD_DECL)
if (tree repr = DECL_BIT_FIELD_REPRESENTATIVE (member))
- mark_declaration (repr, false);
+ /* If we're marking a class template definition, then
+ this'll contain the width (as set by grokbitfield)
+ instead of a decl. */
+ if (DECL_P (repr))
+ mark_declaration (repr, false);
}
/* Mark the binfo hierarchy. */
@@ -14541,20 +14564,6 @@ module_state::read_partitions (unsigned count)
return true;
}
-/* Counter indices. */
-enum module_state_counts
-{
- MSC_sec_lwm,
- MSC_sec_hwm,
- MSC_pendings,
- MSC_entities,
- MSC_namespaces,
- MSC_bindings,
- MSC_macros,
- MSC_inits,
- MSC_HWM
-};
-
/* Data for config reading and writing. */
struct module_state_config {
const char *dialect_str;
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index d6757d1..25657cf 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -6382,7 +6382,7 @@ class namespace_limit_reached : public deferred_diagnostic
std::unique_ptr<deferred_diagnostic> wrapped)
: deferred_diagnostic (loc),
m_limit (limit), m_name (name),
- m_wrapped (move (wrapped))
+ m_wrapped (std::move (wrapped))
{
}
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 7b41635..dc3d17c 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2258,7 +2258,7 @@ static vec<tree, va_gc> *cp_parser_parenthesized_expression_list
(cp_parser *, int, bool, bool, bool *, location_t * = NULL,
bool = false);
/* Values for the second parameter of cp_parser_parenthesized_expression_list. */
-enum { non_attr = 0, normal_attr = 1, id_attr = 2 };
+enum { non_attr = 0, normal_attr = 1, id_attr = 2, assume_attr = 3 };
static void cp_parser_pseudo_destructor_name
(cp_parser *, tree, tree *, tree *);
static cp_expr cp_parser_unary_expression
@@ -2287,6 +2287,7 @@ static cp_expr cp_parser_binary_expression
(cp_parser *, bool, bool, enum cp_parser_prec, cp_id_kind *);
static tree cp_parser_question_colon_clause
(cp_parser *, cp_expr);
+static cp_expr cp_parser_conditional_expression (cp_parser *);
static cp_expr cp_parser_assignment_expression
(cp_parser *, cp_id_kind * = NULL, bool = false, bool = false);
static enum tree_code cp_parser_assignment_operator_opt
@@ -8480,7 +8481,6 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
bool wrap_locations_p)
{
vec<tree, va_gc> *expression_list;
- tree identifier = NULL_TREE;
bool saved_greater_than_is_operator_p;
/* Assume all the expressions will be constant. */
@@ -8509,33 +8509,26 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
next token is an identifier. */
if (is_attribute_list == id_attr
&& cp_lexer_peek_token (parser->lexer)->type == CPP_NAME)
- {
- cp_token *token;
-
- /* Consume the identifier. */
- token = cp_lexer_consume_token (parser->lexer);
- /* Save the identifier. */
- identifier = token->u.value;
- }
+ expr = cp_lexer_consume_token (parser->lexer)->u.value;
+ else if (is_attribute_list == assume_attr)
+ expr = cp_parser_conditional_expression (parser);
else
- {
- expr
- = cp_parser_parenthesized_expression_list_elt (parser, cast_p,
- allow_expansion_p,
- non_constant_p);
+ expr
+ = cp_parser_parenthesized_expression_list_elt (parser, cast_p,
+ allow_expansion_p,
+ non_constant_p);
- if (wrap_locations_p)
- expr.maybe_add_location_wrapper ();
+ if (wrap_locations_p)
+ expr.maybe_add_location_wrapper ();
- /* Add it to the list. We add error_mark_node
- expressions to the list, so that we can still tell if
- the correct form for a parenthesized expression-list
- is found. That gives better errors. */
- vec_safe_push (expression_list, expr.get_value ());
+ /* Add it to the list. We add error_mark_node
+ expressions to the list, so that we can still tell if
+ the correct form for a parenthesized expression-list
+ is found. That gives better errors. */
+ vec_safe_push (expression_list, expr.get_value ());
- if (expr == error_mark_node)
- goto skip_comma;
- }
+ if (expr == error_mark_node)
+ goto skip_comma;
/* After the first item, attribute lists look the same as
expression lists. */
@@ -8577,9 +8570,6 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
- if (identifier)
- vec_safe_insert (expression_list, 0, identifier);
-
return expression_list;
}
@@ -10310,7 +10300,8 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
logical-or-expression that started the conditional-expression.
Returns a representation of the entire conditional-expression.
- This routine is used by cp_parser_assignment_expression.
+ This routine is used by cp_parser_assignment_expression
+ and cp_parser_conditional_expression.
? expression : assignment-expression
@@ -10377,6 +10368,28 @@ cp_parser_question_colon_clause (cp_parser* parser, cp_expr logical_or_expr)
tf_warning_or_error);
}
+/* Parse a conditional-expression.
+
+ conditional-expression:
+ logical-or-expression
+ logical-or-expression ? expression : assignment-expression
+
+ GNU Extensions:
+
+ logical-or-expression ? : assignment-expression */
+
+static cp_expr
+cp_parser_conditional_expression (cp_parser *parser)
+{
+ cp_expr expr = cp_parser_binary_expression (parser, false, false, false,
+ PREC_NOT_OPERATOR, NULL);
+ /* If the next token is a `?' then we're actually looking at
+ a conditional-expression; otherwise we're done. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
+ return cp_parser_question_colon_clause (parser, expr);
+ return expr;
+}
+
/* Parse an assignment-expression.
assignment-expression:
@@ -10702,15 +10715,7 @@ cp_parser_constant_expression (cp_parser* parser,
determine whether a particular assignment-expression is in fact
constant. */
if (strict_p)
- {
- /* Parse the binary expressions (logical-or-expression). */
- expression = cp_parser_binary_expression (parser, false, false, false,
- PREC_NOT_OPERATOR, NULL);
- /* If the next token is a `?' then we're actually looking at
- a conditional-expression; otherwise we're done. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
- expression = cp_parser_question_colon_clause (parser, expression);
- }
+ expression = cp_parser_conditional_expression (parser);
else
expression = cp_parser_assignment_expression (parser);
/* Restore the old settings. */
@@ -12503,6 +12508,9 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
/* Look for an expression-statement instead. */
statement = cp_parser_expression_statement (parser, in_statement_expr);
+ std_attrs = process_stmt_assume_attribute (std_attrs, statement,
+ attrs_loc);
+
/* Handle [[fallthrough]];. */
if (attribute_fallthrough_p (std_attrs))
{
@@ -12526,7 +12534,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
if (statement && STATEMENT_CODE_P (TREE_CODE (statement)))
SET_EXPR_LOCATION (statement, statement_location);
- /* Allow "[[fallthrough]];", but warn otherwise. */
+ /* Allow "[[fallthrough]];" or "[[assume(cond)]];", but warn otherwise. */
if (std_attrs != NULL_TREE)
warning_at (attrs_loc,
OPT_Wattributes,
@@ -12718,6 +12726,8 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
}
}
+ attr = process_stmt_assume_attribute (attr, statement, loc);
+
/* Handle [[fallthrough]];. */
if (attribute_fallthrough_p (attr))
{
@@ -13721,7 +13731,8 @@ warn_for_range_copy (tree decl, tree expr)
if (TYPE_REF_P (type))
{
- if (glvalue_p (expr) && ref_conv_binds_directly (type, expr).is_false ())
+ if (glvalue_p (expr)
+ && ref_conv_binds_to_temporary (type, expr).is_true ())
{
auto_diagnostic_group d;
if (warning_at (loc, OPT_Wrange_loop_construct,
@@ -13752,7 +13763,7 @@ warn_for_range_copy (tree decl, tree expr)
/* If we can initialize a reference directly, suggest that to avoid the
copy. */
tree rtype = cp_build_reference_type (type, /*rval*/false);
- if (ref_conv_binds_directly (rtype, expr).is_true ())
+ if (ref_conv_binds_to_temporary (rtype, expr).is_false ())
{
auto_diagnostic_group d;
if (warning_at (loc, OPT_Wrange_loop_construct,
@@ -28876,6 +28887,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */)
vec<tree, va_gc> *vec;
int attr_flag = (attribute_takes_identifier_p (identifier)
? id_attr : normal_attr);
+ if (is_attribute_p ("assume", identifier))
+ attr_flag = assume_attr;
vec = cp_parser_parenthesized_expression_list
(parser, attr_flag, /*cast_p=*/false,
/*allow_expansion_p=*/false,
@@ -29127,6 +29140,9 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
/* C++17 fallthrough attribute is equivalent to GNU's. */
else if (is_attribute_p ("fallthrough", attr_id))
TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier;
+ /* C++23 assume attribute is equivalent to GNU's. */
+ else if (is_attribute_p ("assume", attr_id))
+ TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier;
/* Transactional Memory TS optimize_for_synchronized attribute is
equivalent to GNU transaction_callable. */
else if (is_attribute_p ("optimize_for_synchronized", attr_id))
@@ -29171,8 +29187,12 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
return error_mark_node;
}
- if (attr_ns == gnu_identifier
- && attribute_takes_identifier_p (attr_id))
+ if (is_attribute_p ("assume", attr_id)
+ && (attr_ns == NULL_TREE || attr_ns == gnu_identifier))
+ /* The assume attribute needs special handling of the argument. */
+ attr_flag = assume_attr;
+ else if (attr_ns == gnu_identifier
+ && attribute_takes_identifier_p (attr_id))
/* A GNU attribute that takes an identifier in parameter. */
attr_flag = id_attr;
@@ -29246,7 +29266,8 @@ cp_parser_check_std_attribute (location_t loc, tree attributes, tree attribute)
if (attributes)
for (const auto &a : alist)
if (is_attribute_p (a, get_attribute_name (attribute))
- && lookup_attribute (a, attributes))
+ && is_attribute_namespace_p ("", attribute)
+ && lookup_attribute ("", a, attributes))
{
if (!from_macro_expansion_at (loc))
warning_at (loc, OPT_Wattributes, "attribute %qs specified "
@@ -46004,13 +46025,15 @@ cp_parser_omp_assumption_clauses (cp_parser *parser, cp_token *pragma_tok,
matching_parens parens;
if (parens.require_open (parser))
{
+ location_t eloc = cp_lexer_peek_token (parser->lexer)->location;
tree t = cp_parser_assignment_expression (parser);
if (!type_dependent_expression_p (t))
t = contextual_conv_bool (t, tf_warning_or_error);
- if (is_assume)
+ if (is_assume && !error_operand_p (t))
{
- /* FIXME: Emit .ASSUME (t) call here. */
- (void) t;
+ t = build_call_expr_internal_loc (eloc, IFN_ASSUME,
+ void_type_node, 1, t);
+ finish_expr_stmt (t);
}
if (!parens.require_close (parser))
cp_parser_skip_to_closing_parenthesis (parser,
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index bce2a77..5b9fc58 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1170,39 +1170,6 @@ maybe_process_partial_specialization (tree type)
return type;
}
-/* Returns nonzero if we can optimize the retrieval of specializations
- for TMPL, a TEMPLATE_DECL. In particular, for such a template, we
- do not use DECL_TEMPLATE_SPECIALIZATIONS at all. */
-
-static inline bool
-optimize_specialization_lookup_p (tree tmpl)
-{
- return (DECL_FUNCTION_TEMPLATE_P (tmpl)
- && DECL_CLASS_SCOPE_P (tmpl)
- /* DECL_CLASS_SCOPE_P holds of T::f even if T is a template
- parameter. */
- && CLASS_TYPE_P (DECL_CONTEXT (tmpl))
- /* The optimized lookup depends on the fact that the
- template arguments for the member function template apply
- purely to the containing class, which is not true if the
- containing class is an explicit or partial
- specialization. */
- && !CLASSTYPE_TEMPLATE_SPECIALIZATION (DECL_CONTEXT (tmpl))
- && !DECL_MEMBER_TEMPLATE_P (tmpl)
- && !DECL_CONV_FN_P (tmpl)
- /* It is possible to have a template that is not a member
- template and is not a member of a template class:
-
- template <typename T>
- struct S { friend A::f(); };
-
- Here, the friend function is a template, but the context does
- not have template information. The optimized lookup relies
- on having ARGS be the template arguments for both the class
- and the function template. */
- && !DECL_UNIQUE_FRIEND_P (DECL_TEMPLATE_RESULT (tmpl)));
-}
-
/* Make sure ARGS doesn't use any inappropriate typedefs; we should have
gone through coerce_template_parms by now. */
@@ -1276,54 +1243,21 @@ retrieve_specialization (tree tmpl, tree args, hashval_t hash)
if (lambda_fn_in_template_p (tmpl))
return NULL_TREE;
- if (optimize_specialization_lookup_p (tmpl))
- {
- /* The template arguments actually apply to the containing
- class. Find the class specialization with those
- arguments. */
- tree class_template = CLASSTYPE_TI_TEMPLATE (DECL_CONTEXT (tmpl));
- tree class_specialization
- = retrieve_specialization (class_template, args, 0);
- if (!class_specialization)
- return NULL_TREE;
+ spec_entry elt;
+ elt.tmpl = tmpl;
+ elt.args = args;
+ elt.spec = NULL_TREE;
- /* Find the instance of TMPL. */
- tree fns = get_class_binding (class_specialization, DECL_NAME (tmpl));
- for (ovl_iterator iter (fns); iter; ++iter)
- {
- tree fn = *iter;
- if (tree ti = get_template_info (fn))
- if (TI_TEMPLATE (ti) == tmpl
- /* using-declarations can bring in a different
- instantiation of tmpl as a member of a different
- instantiation of tmpl's class. We don't want those
- here. */
- && DECL_CONTEXT (fn) == class_specialization)
- return fn;
- }
- return NULL_TREE;
- }
+ spec_hash_table *specializations;
+ if (DECL_CLASS_TEMPLATE_P (tmpl))
+ specializations = type_specializations;
else
- {
- spec_entry *found;
- spec_entry elt;
- spec_hash_table *specializations;
-
- elt.tmpl = tmpl;
- elt.args = args;
- elt.spec = NULL_TREE;
-
- if (DECL_CLASS_TEMPLATE_P (tmpl))
- specializations = type_specializations;
- else
- specializations = decl_specializations;
+ specializations = decl_specializations;
- if (hash == 0)
- hash = spec_hasher::hash (&elt);
- found = specializations->find_with_hash (&elt, hash);
- if (found)
- return found->spec;
- }
+ if (hash == 0)
+ hash = spec_hasher::hash (&elt);
+ if (spec_entry *found = specializations->find_with_hash (&elt, hash))
+ return found->spec;
return NULL_TREE;
}
@@ -1567,8 +1501,6 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
hashval_t hash)
{
tree fn;
- spec_entry **slot = NULL;
- spec_entry elt;
gcc_assert ((TREE_CODE (tmpl) == TEMPLATE_DECL && DECL_P (spec))
|| (TREE_CODE (tmpl) == FIELD_DECL
@@ -1589,25 +1521,19 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
instantiation unless and until it is actually needed. */
return spec;
- if (optimize_specialization_lookup_p (tmpl))
- /* We don't put these specializations in the hash table, but we might
- want to give an error about a mismatch. */
- fn = retrieve_specialization (tmpl, args, 0);
- else
- {
- elt.tmpl = tmpl;
- elt.args = args;
- elt.spec = spec;
+ spec_entry elt;
+ elt.tmpl = tmpl;
+ elt.args = args;
+ elt.spec = spec;
- if (hash == 0)
- hash = spec_hasher::hash (&elt);
+ if (hash == 0)
+ hash = spec_hasher::hash (&elt);
- slot = decl_specializations->find_slot_with_hash (&elt, hash, INSERT);
- if (*slot)
- fn = (*slot)->spec;
- else
- fn = NULL_TREE;
- }
+ spec_entry **slot = decl_specializations->find_slot_with_hash (&elt, hash, INSERT);
+ if (*slot)
+ fn = (*slot)->spec;
+ else
+ fn = NULL_TREE;
/* We can sometimes try to re-register a specialization that we've
already got. In particular, regenerate_decl_from_template calls
@@ -1704,26 +1630,23 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
&& !check_specialization_namespace (tmpl))
DECL_CONTEXT (spec) = DECL_CONTEXT (tmpl);
- if (slot != NULL /* !optimize_specialization_lookup_p (tmpl) */)
- {
- spec_entry *entry = ggc_alloc<spec_entry> ();
- gcc_assert (tmpl && args && spec);
- *entry = elt;
- *slot = entry;
- if ((TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec)
- && PRIMARY_TEMPLATE_P (tmpl)
- && DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE)
- || variable_template_p (tmpl))
- /* If TMPL is a forward declaration of a template function, keep a list
- of all specializations in case we need to reassign them to a friend
- template later in tsubst_friend_function.
-
- Also keep a list of all variable template instantiations so that
- process_partial_specialization can check whether a later partial
- specialization would have used it. */
- DECL_TEMPLATE_INSTANTIATIONS (tmpl)
- = tree_cons (args, spec, DECL_TEMPLATE_INSTANTIATIONS (tmpl));
- }
+ spec_entry *entry = ggc_alloc<spec_entry> ();
+ gcc_assert (tmpl && args && spec);
+ *entry = elt;
+ *slot = entry;
+ if ((TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec)
+ && PRIMARY_TEMPLATE_P (tmpl)
+ && DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE)
+ || variable_template_p (tmpl))
+ /* If TMPL is a forward declaration of a template function, keep a list
+ of all specializations in case we need to reassign them to a friend
+ template later in tsubst_friend_function.
+
+ Also keep a list of all variable template instantiations so that
+ process_partial_specialization can check whether a later partial
+ specialization would have used it. */
+ DECL_TEMPLATE_INSTANTIATIONS (tmpl)
+ = tree_cons (args, spec, DECL_TEMPLATE_INSTANTIATIONS (tmpl));
return spec;
}
@@ -21163,6 +21086,33 @@ tsubst_copy_and_build (tree t,
break;
}
+ case IFN_ASSUME:
+ gcc_assert (nargs == 1);
+ if (vec_safe_length (call_args) != 1)
+ {
+ error_at (cp_expr_loc_or_input_loc (t),
+ "wrong number of arguments to "
+ "%<assume%> attribute");
+ ret = error_mark_node;
+ }
+ else
+ {
+ tree &arg = (*call_args)[0];
+ if (!type_dependent_expression_p (arg))
+ arg = contextual_conv_bool (arg, tf_warning_or_error);
+ if (error_operand_p (arg))
+ {
+ ret = error_mark_node;
+ break;
+ }
+ ret = build_call_expr_internal_loc (EXPR_LOCATION (t),
+ IFN_ASSUME,
+ void_type_node, 1,
+ arg);
+ RETURN (ret);
+ }
+ break;
+
default:
/* Unsupported internal function with arguments. */
gcc_unreachable ();
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 30cf2f9..7d46c3c 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -2519,6 +2519,10 @@ finish_stmt_expr_expr (tree expr, tree stmt_expr)
/* Update for array-to-pointer decay. */
type = TREE_TYPE (expr);
+ /* This TARGET_EXPR will initialize the outer one added by
+ finish_stmt_expr. */
+ set_target_expr_eliding (expr);
+
/* Wrap it in a CLEANUP_POINT_EXPR and add it to the list like a
normal statement, but don't convert to void or actually add
the EXPR_STMT. */
@@ -4668,7 +4672,7 @@ simplify_aggr_init_expr (tree *tp)
expand_call{,_inline}. */
cxx_mark_addressable (slot);
CALL_EXPR_RETURN_SLOT_OPT (call_expr) = true;
- call_expr = build2 (INIT_EXPR, TREE_TYPE (call_expr), slot, call_expr);
+ call_expr = cp_build_init_expr (slot, call_expr);
}
else if (style == pcc)
{
@@ -4687,7 +4691,7 @@ simplify_aggr_init_expr (tree *tp)
{
tree init = build_zero_init (type, NULL_TREE,
/*static_storage_p=*/false);
- init = build2 (INIT_EXPR, void_type_node, slot, init);
+ init = cp_build_init_expr (slot, init);
call_expr = build2 (COMPOUND_EXPR, TREE_TYPE (call_expr),
init, call_expr);
}
@@ -4882,7 +4886,7 @@ finalize_nrv_r (tree* tp, int* walk_subtrees, void* data)
tree init;
if (DECL_INITIAL (dp->var)
&& DECL_INITIAL (dp->var) != error_mark_node)
- init = build2 (INIT_EXPR, void_type_node, dp->result,
+ init = cp_build_init_expr (dp->result,
DECL_INITIAL (dp->var));
else
init = build_empty_stmt (EXPR_LOCATION (*tp));
@@ -6426,7 +6430,7 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor)
else
init = fold_convert (TREE_TYPE (v), integer_zero_node);
OMP_CLAUSE_REDUCTION_INIT (c)
- = build2 (INIT_EXPR, TREE_TYPE (v), v, init);
+ = cp_build_init_expr (v, init);
}
}
}
@@ -11172,42 +11176,31 @@ init_cp_semantics (void)
}
-/* If we have a condition in conjunctive normal form (CNF), find the first
- failing clause. In other words, given an expression like
-
- true && true && false && true && false
+/* Emit additional diagnostics for failing condition BAD.
+ Used by finish_static_assert and IFN_ASSUME constexpr diagnostics.
+ If SHOW_EXPR_P is true, print the condition (because it was
+ instantiation-dependent). */
- return the first 'false'. EXPR is the expression. */
-
-static tree
-find_failing_clause_r (tree expr)
+void
+diagnose_failing_condition (tree bad, location_t cloc, bool show_expr_p)
{
- if (TREE_CODE (expr) == TRUTH_ANDIF_EXPR)
+ /* Nobody wants to see the artificial (bool) cast. */
+ bad = tree_strip_nop_conversions (bad);
+
+ /* Actually explain the failure if this is a concept check or a
+ requires-expression. */
+ if (concept_check_p (bad) || TREE_CODE (bad) == REQUIRES_EXPR)
+ diagnose_constraints (cloc, bad, NULL_TREE);
+ else if (COMPARISON_CLASS_P (bad)
+ && ARITHMETIC_TYPE_P (TREE_TYPE (TREE_OPERAND (bad, 0))))
{
- /* First check the left side... */
- tree e = find_failing_clause_r (TREE_OPERAND (expr, 0));
- if (e == NULL_TREE)
- /* ...if we didn't find a false clause, check the right side. */
- e = find_failing_clause_r (TREE_OPERAND (expr, 1));
- return e;
+ tree op0 = fold_non_dependent_expr (TREE_OPERAND (bad, 0));
+ tree op1 = fold_non_dependent_expr (TREE_OPERAND (bad, 1));
+ tree cond = build2 (TREE_CODE (bad), boolean_type_node, op0, op1);
+ inform (cloc, "the comparison reduces to %qE", cond);
}
- tree e = contextual_conv_bool (expr, tf_none);
- e = fold_non_dependent_expr (e, tf_none, /*manifestly_const_eval=*/true);
- if (integer_zerop (e))
- /* This is the failing clause. */
- return expr;
- return NULL_TREE;
-}
-
-/* Wrapper for find_failing_clause_r. */
-
-static tree
-find_failing_clause (tree expr)
-{
- if (TREE_CODE (expr) == TRUTH_ANDIF_EXPR)
- if (tree e = find_failing_clause_r (expr))
- expr = e;
- return expr;
+ else if (show_expr_p)
+ inform (cloc, "%qE evaluates to false", bad);
}
/* Build a STATIC_ASSERT for a static assertion with the condition
@@ -11274,12 +11267,12 @@ finish_static_assert (tree condition, tree message, location_t location,
int len = TREE_STRING_LENGTH (message) / sz - 1;
/* See if we can find which clause was failing (for logical AND). */
- tree bad = find_failing_clause (orig_condition);
+ tree bad = find_failing_clause (NULL, orig_condition);
/* If not, or its location is unusable, fall back to the previous
location. */
location_t cloc = cp_expr_loc_or_loc (bad, location);
- /* Nobody wants to see the artificial (bool) cast. */
- bad = tree_strip_nop_conversions (bad);
+
+ auto_diagnostic_group d;
/* Report the error. */
if (len == 0)
@@ -11288,21 +11281,7 @@ finish_static_assert (tree condition, tree message, location_t location,
error_at (cloc, "static assertion failed: %s",
TREE_STRING_POINTER (message));
- /* Actually explain the failure if this is a concept check or a
- requires-expression. */
- if (concept_check_p (bad)
- || TREE_CODE (bad) == REQUIRES_EXPR)
- diagnose_constraints (location, bad, NULL_TREE);
- else if (COMPARISON_CLASS_P (bad)
- && ARITHMETIC_TYPE_P (TREE_TYPE (TREE_OPERAND (bad, 0))))
- {
- tree op0 = fold_non_dependent_expr (TREE_OPERAND (bad, 0));
- tree op1 = fold_non_dependent_expr (TREE_OPERAND (bad, 1));
- tree cond = build2 (TREE_CODE (bad), boolean_type_node, op0, op1);
- inform (cloc, "the comparison reduces to %qE", cond);
- }
- else if (show_expr_p)
- inform (cloc, "%qE evaluates to false", bad);
+ diagnose_failing_condition (bad, cloc, show_expr_p);
}
else if (condition && condition != error_mark_node)
{
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index aa9c1b7..3532e44 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -104,7 +104,17 @@ lvalue_kind (const_tree ref)
case REALPART_EXPR:
case IMAGPART_EXPR:
case VIEW_CONVERT_EXPR:
- return lvalue_kind (TREE_OPERAND (ref, 0));
+ op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0));
+ /* As for ARRAY_REF and COMPONENT_REF, these codes turn a class prvalue
+ into an xvalue: we need to materialize the temporary before we mess
+ with it. Except VIEW_CONVERT_EXPR that doesn't actually change the
+ type, as in location wrapper and REF_PARENTHESIZED_P. */
+ if (op1_lvalue_kind == clk_class
+ && !(TREE_CODE (ref) == VIEW_CONVERT_EXPR
+ && (same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (ref), TREE_TYPE (TREE_OPERAND (ref, 0))))))
+ return clk_rvalueref;
+ return op1_lvalue_kind;
case ARRAY_REF:
{
@@ -523,6 +533,9 @@ build_target_expr (tree decl, tree value, tsubst_flags_t complain)
if (t == error_mark_node)
return error_mark_node;
}
+
+ set_target_expr_eliding (value);
+
t = build4 (TARGET_EXPR, type, decl, value, t, NULL_TREE);
if (location_t eloc = cp_expr_location (value))
SET_EXPR_LOCATION (t, eloc);
@@ -3184,6 +3197,7 @@ bot_manip (tree* tp, int* walk_subtrees, void* data_)
TARGET_EXPR_IMPLICIT_P (u) = TARGET_EXPR_IMPLICIT_P (t);
TARGET_EXPR_LIST_INIT_P (u) = TARGET_EXPR_LIST_INIT_P (t);
TARGET_EXPR_DIRECT_INIT_P (u) = TARGET_EXPR_DIRECT_INIT_P (t);
+ TARGET_EXPR_ELIDING_P (u) = TARGET_EXPR_ELIDING_P (t);
/* Map the old variable to the new one. */
splay_tree_insert (target_remap,
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index cecf825..b4a8e3c 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -9294,7 +9294,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
if (! same_type_p (TREE_TYPE (rhs), lhstype))
/* Call convert to generate an error; see PR 11063. */
rhs = convert (lhstype, rhs);
- result = build2 (INIT_EXPR, lhstype, lhs, rhs);
+ result = cp_build_init_expr (lhs, rhs);
TREE_SIDE_EFFECTS (result) = 1;
goto ret;
}
@@ -9542,6 +9542,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
result = build2_loc (loc, modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
lhstype, lhs, newrhs);
+ if (modifycode == INIT_EXPR)
+ set_target_expr_eliding (newrhs);
TREE_SIDE_EFFECTS (result) = 1;
if (!plain_assign)
@@ -11105,7 +11107,7 @@ check_return_expr (tree retval, bool *no_warning)
/* Actually copy the value returned into the appropriate location. */
if (retval && retval != result)
- retval = build2 (INIT_EXPR, TREE_TYPE (result), result, retval);
+ retval = cp_build_init_expr (result, retval);
if (tree set = maybe_set_retval_sentinel ())
retval = build2 (COMPOUND_EXPR, void_type_node, retval, set);
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index d5236d1..2644472 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -649,7 +649,7 @@ split_nonconstant_init_1 (tree dest, tree init, bool last,
else
{
build_init:
- code = build2 (INIT_EXPR, inner_type, sub, value);
+ code = cp_build_init_expr (sub, value);
}
code = build_stmt (input_location, EXPR_STMT, code);
add_stmt (code);
@@ -764,7 +764,7 @@ split_nonconstant_init (tree dest, tree init)
}
else if (init)
{
- tree ie = build2 (INIT_EXPR, void_type_node, dest, init);
+ tree ie = cp_build_init_expr (dest, init);
code = add_stmt_to_compound (ie, code);
}
}
@@ -773,7 +773,7 @@ split_nonconstant_init (tree dest, tree init)
code = build_vec_init (dest, NULL_TREE, init, /*value-init*/false,
/*from array*/1, tf_warning_or_error);
else
- code = build2 (INIT_EXPR, TREE_TYPE (dest), dest, init);
+ code = cp_build_init_expr (dest, init);
return code;
}
@@ -1464,6 +1464,7 @@ digest_nsdmi_init (tree decl, tree init, tsubst_flags_t complain)
&& CP_AGGREGATE_TYPE_P (type))
init = reshape_init (type, init, complain);
init = digest_init_flags (type, init, flags, complain);
+ set_target_expr_eliding (init);
/* We may have temporary materialization in a NSDMI, if the initializer
has something like A{} in it. Digesting the {} could have introduced
@@ -1542,6 +1543,7 @@ massage_init_elt (tree type, tree init, int nested, int flags,
tree t = fold_non_dependent_init (init, complain);
if (TREE_CONSTANT (t))
init = t;
+ set_target_expr_eliding (init);
}
return init;
}
@@ -1771,6 +1773,13 @@ process_init_constructor_record (tree type, tree init, int nested, int flags,
{
gcc_assert (ce->value);
next = massage_init_elt (fldtype, next, nested, flags, complain);
+ /* We can't actually elide the temporary when initializing a
+ potentially-overlapping field from a function that returns by
+ value. */
+ if (ce->index
+ && TREE_CODE (next) == TARGET_EXPR
+ && unsafe_copy_elision_p (ce->index, next))
+ TARGET_EXPR_ELIDING_P (next) = false;
++idx;
}
}
@@ -1804,6 +1813,9 @@ process_init_constructor_record (tree type, tree init, int nested, int flags,
a class, just build one up; if it's an array, recurse. */
next = build_constructor (init_list_type_node, NULL);
next = massage_init_elt (fldtype, next, nested, flags, complain);
+ if (TREE_CODE (next) == TARGET_EXPR
+ && unsafe_copy_elision_p (field, next))
+ TARGET_EXPR_ELIDING_P (next) = false;
/* Warn when some struct elements are implicitly initialized. */
if ((complain & tf_warning)
@@ -2727,3 +2739,41 @@ require_complete_eh_spec_types (tree fntype, tree decl)
}
}
}
+
+/* Record that any TARGET_EXPR in T are going to be elided in
+ cp_gimplify_init_expr (or sooner). */
+
+void
+set_target_expr_eliding (tree t)
+{
+ if (!t)
+ return;
+ switch (TREE_CODE (t))
+ {
+ case TARGET_EXPR:
+ TARGET_EXPR_ELIDING_P (t) = true;
+ break;
+ case COMPOUND_EXPR:
+ set_target_expr_eliding (TREE_OPERAND (t, 1));
+ break;
+ case COND_EXPR:
+ set_target_expr_eliding (TREE_OPERAND (t, 1));
+ set_target_expr_eliding (TREE_OPERAND (t, 2));
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Call the above in the process of building an INIT_EXPR. */
+
+tree
+cp_build_init_expr (location_t loc, tree target, tree init)
+{
+ set_target_expr_eliding (init);
+ tree ie = build2_loc (loc, INIT_EXPR, TREE_TYPE (target),
+ target, init);
+ TREE_SIDE_EFFECTS (ie) = true;
+ return ie;
+}