diff options
author | Martin Liska <mliska@suse.cz> | 2022-10-08 10:19:23 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-10-08 10:19:23 +0200 |
commit | d9e7934d25da4a78ffef1f738206aa1d897911df (patch) | |
tree | 1bd1697c14259e095f4b4790946eae7df0c5a2e3 /gcc/cp | |
parent | da0970e441345f8349522ff1abac5c223044ebb1 (diff) | |
parent | 6ffbf87ca66f4ed9cd79cff675fabe2109e46e85 (diff) | |
download | gcc-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/ChangeLog | 151 | ||||
-rw-r--r-- | gcc/cp/Make-lang.in | 2 | ||||
-rw-r--r-- | gcc/cp/call.cc | 60 | ||||
-rw-r--r-- | gcc/cp/constexpr.cc | 90 | ||||
-rw-r--r-- | gcc/cp/coroutines.cc | 48 | ||||
-rw-r--r-- | gcc/cp/cp-gimplify.cc | 92 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 17 | ||||
-rw-r--r-- | gcc/cp/decl.cc | 2 | ||||
-rw-r--r-- | gcc/cp/except.cc | 2 | ||||
-rw-r--r-- | gcc/cp/init.cc | 50 | ||||
-rw-r--r-- | gcc/cp/lex.cc | 4 | ||||
-rw-r--r-- | gcc/cp/method.cc | 6 | ||||
-rw-r--r-- | gcc/cp/module.cc | 43 | ||||
-rw-r--r-- | gcc/cp/name-lookup.cc | 2 | ||||
-rw-r--r-- | gcc/cp/parser.cc | 117 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 184 | ||||
-rw-r--r-- | gcc/cp/semantics.cc | 87 | ||||
-rw-r--r-- | gcc/cp/tree.cc | 16 | ||||
-rw-r--r-- | gcc/cp/typeck.cc | 6 | ||||
-rw-r--r-- | gcc/cp/typeck2.cc | 56 |
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; +} |