| /* Report error messages, build initializers, and perform |
| some front-end optimizations for C++ compiler. |
| Copyright (C) 1987-2022 Free Software Foundation, Inc. |
| Hacked by Michael Tiemann (tiemann@cygnus.com) |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GCC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| |
| /* This file is part of the C++ front end. |
| It contains routines to build C++ expressions given their operands, |
| including computing the types of the result, C and C++ specific error |
| checks, and some optimization. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "cp-tree.h" |
| #include "stor-layout.h" |
| #include "varasm.h" |
| #include "intl.h" |
| #include "gcc-rich-location.h" |
| #include "target.h" |
| |
| static tree |
| process_init_constructor (tree type, tree init, int nested, int flags, |
| tsubst_flags_t complain); |
| |
| |
| /* Print an error message stemming from an attempt to use |
| BASETYPE as a base class for TYPE. */ |
| |
| tree |
| error_not_base_type (tree basetype, tree type) |
| { |
| if (TREE_CODE (basetype) == FUNCTION_DECL) |
| basetype = DECL_CONTEXT (basetype); |
| error ("type %qT is not a base type for type %qT", basetype, type); |
| return error_mark_node; |
| } |
| |
| tree |
| binfo_or_else (tree base, tree type) |
| { |
| tree binfo = lookup_base (type, base, ba_unique, |
| NULL, tf_warning_or_error); |
| |
| if (binfo == error_mark_node) |
| return NULL_TREE; |
| else if (!binfo) |
| error_not_base_type (base, type); |
| return binfo; |
| } |
| |
| /* According to ARM $7.1.6, "A `const' object may be initialized, but its |
| value may not be changed thereafter. */ |
| |
| void |
| cxx_readonly_error (location_t loc, tree arg, enum lvalue_use errstring) |
| { |
| |
| /* This macro is used to emit diagnostics to ensure that all format |
| strings are complete sentences, visible to gettext and checked at |
| compile time. */ |
| |
| #define ERROR_FOR_ASSIGNMENT(LOC, AS, ASM, IN, DE, ARG) \ |
| do { \ |
| switch (errstring) \ |
| { \ |
| case lv_assign: \ |
| error_at (LOC, AS, ARG); \ |
| break; \ |
| case lv_asm: \ |
| error_at (LOC, ASM, ARG); \ |
| break; \ |
| case lv_increment: \ |
| error_at (LOC, IN, ARG); \ |
| break; \ |
| case lv_decrement: \ |
| error_at (LOC, DE, ARG); \ |
| break; \ |
| default: \ |
| gcc_unreachable (); \ |
| } \ |
| } while (0) |
| |
| /* Handle C++-specific things first. */ |
| |
| if (VAR_P (arg) |
| && DECL_LANG_SPECIFIC (arg) |
| && DECL_IN_AGGR_P (arg) |
| && !TREE_STATIC (arg)) |
| ERROR_FOR_ASSIGNMENT (loc, |
| G_("assignment of constant field %qD"), |
| G_("constant field %qD used as %<asm%> output"), |
| G_("increment of constant field %qD"), |
| G_("decrement of constant field %qD"), |
| arg); |
| else if (INDIRECT_REF_P (arg) |
| && TYPE_REF_P (TREE_TYPE (TREE_OPERAND (arg, 0))) |
| && (VAR_P (TREE_OPERAND (arg, 0)) |
| || TREE_CODE (TREE_OPERAND (arg, 0)) == PARM_DECL)) |
| ERROR_FOR_ASSIGNMENT (loc, |
| G_("assignment of read-only reference %qD"), |
| G_("read-only reference %qD used as %<asm%> output"), |
| G_("increment of read-only reference %qD"), |
| G_("decrement of read-only reference %qD"), |
| TREE_OPERAND (arg, 0)); |
| else |
| readonly_error (loc, arg, errstring); |
| } |
| |
| /* If TYPE has abstract virtual functions, issue an error about trying |
| to create an object of that type. DECL is the object declared, or |
| NULL_TREE if the declaration is unavailable, in which case USE specifies |
| the kind of invalid use. Returns 1 if an error occurred; zero if |
| all was well. */ |
| |
| static int |
| abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use, |
| tsubst_flags_t complain) |
| { |
| vec<tree, va_gc> *pure; |
| |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| decl = NULL_TREE; |
| use = ACU_ARRAY; |
| type = strip_array_types (type); |
| } |
| |
| /* This function applies only to classes. Any other entity can never |
| be abstract. */ |
| if (!CLASS_TYPE_P (type)) |
| return 0; |
| type = TYPE_MAIN_VARIANT (type); |
| |
| #if 0 |
| /* Instantiation here seems to be required by the standard, |
| but breaks e.g. boost::bind. FIXME! */ |
| /* In SFINAE, non-N3276 context, force instantiation. */ |
| if (!(complain & (tf_error|tf_decltype))) |
| complete_type (type); |
| #endif |
| |
| if (!TYPE_SIZE (type)) |
| /* TYPE is being defined, and during that time |
| CLASSTYPE_PURE_VIRTUALS holds the inline friends. */ |
| return 0; |
| |
| pure = CLASSTYPE_PURE_VIRTUALS (type); |
| if (!pure) |
| return 0; |
| |
| if (!(complain & tf_error)) |
| return 1; |
| |
| auto_diagnostic_group d; |
| if (decl) |
| { |
| if (VAR_P (decl)) |
| error ("cannot declare variable %q+D to be of abstract " |
| "type %qT", decl, type); |
| else if (TREE_CODE (decl) == PARM_DECL) |
| { |
| if (DECL_NAME (decl)) |
| error ("cannot declare parameter %q+D to be of abstract type %qT", |
| decl, type); |
| else |
| error ("cannot declare parameter to be of abstract type %qT", |
| type); |
| } |
| else if (TREE_CODE (decl) == FIELD_DECL) |
| error ("cannot declare field %q+D to be of abstract type %qT", |
| decl, type); |
| else if (TREE_CODE (decl) == FUNCTION_DECL |
| && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) |
| error ("invalid abstract return type for member function %q+#D", decl); |
| else if (TREE_CODE (decl) == FUNCTION_DECL) |
| error ("invalid abstract return type for function %q+#D", decl); |
| else if (identifier_p (decl)) |
| /* Here we do not have location information. */ |
| error ("invalid abstract type %qT for %qE", type, decl); |
| else |
| error ("invalid abstract type for %q+D", decl); |
| } |
| else switch (use) |
| { |
| case ACU_ARRAY: |
| error ("creating array of %qT, which is an abstract class type", type); |
| break; |
| case ACU_CAST: |
| error ("invalid cast to abstract class type %qT", type); |
| break; |
| case ACU_NEW: |
| error ("invalid new-expression of abstract class type %qT", type); |
| break; |
| case ACU_RETURN: |
| error ("invalid abstract return type %qT", type); |
| break; |
| case ACU_PARM: |
| error ("invalid abstract parameter type %qT", type); |
| break; |
| case ACU_THROW: |
| error ("expression of abstract class type %qT cannot " |
| "be used in throw-expression", type); |
| break; |
| case ACU_CATCH: |
| error ("cannot declare %<catch%> parameter to be of abstract " |
| "class type %qT", type); |
| break; |
| default: |
| error ("cannot allocate an object of abstract type %qT", type); |
| } |
| |
| /* Only go through this once. */ |
| if (pure->length ()) |
| { |
| unsigned ix; |
| tree fn; |
| |
| inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)), |
| " because the following virtual functions are pure within %qT:", |
| type); |
| |
| FOR_EACH_VEC_ELT (*pure, ix, fn) |
| if (! DECL_CLONED_FUNCTION_P (fn) |
| || DECL_COMPLETE_DESTRUCTOR_P (fn)) |
| inform (DECL_SOURCE_LOCATION (fn), " %#qD", fn); |
| |
| /* Now truncate the vector. This leaves it non-null, so we know |
| there are pure virtuals, but empty so we don't list them out |
| again. */ |
| pure->truncate (0); |
| } |
| |
| return 1; |
| } |
| |
| int |
| abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain) |
| { |
| return abstract_virtuals_error_sfinae (decl, type, ACU_UNKNOWN, complain); |
| } |
| |
| int |
| abstract_virtuals_error_sfinae (abstract_class_use use, tree type, |
| tsubst_flags_t complain) |
| { |
| return abstract_virtuals_error_sfinae (NULL_TREE, type, use, complain); |
| } |
| |
| |
| /* Wrapper for the above function in the common case of wanting errors. */ |
| |
| int |
| abstract_virtuals_error (tree decl, tree type) |
| { |
| return abstract_virtuals_error_sfinae (decl, type, tf_warning_or_error); |
| } |
| |
| int |
| abstract_virtuals_error (abstract_class_use use, tree type) |
| { |
| return abstract_virtuals_error_sfinae (use, type, tf_warning_or_error); |
| } |
| |
| /* Print an inform about the declaration of the incomplete type TYPE. */ |
| |
| void |
| cxx_incomplete_type_inform (const_tree type) |
| { |
| if (!TYPE_MAIN_DECL (type)) |
| return; |
| |
| location_t loc = DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)); |
| tree ptype = strip_top_quals (CONST_CAST_TREE (type)); |
| |
| if (current_class_type |
| && TYPE_BEING_DEFINED (current_class_type) |
| && same_type_p (ptype, current_class_type)) |
| inform (loc, "definition of %q#T is not complete until " |
| "the closing brace", ptype); |
| else if (!TYPE_TEMPLATE_INFO (ptype)) |
| inform (loc, "forward declaration of %q#T", ptype); |
| else |
| inform (loc, "declaration of %q#T", ptype); |
| } |
| |
| /* Print an error message for invalid use of an incomplete type. |
| VALUE is the expression that was used (or 0 if that isn't known) |
| and TYPE is the type that was invalid. DIAG_KIND indicates the |
| type of diagnostic (see diagnostic.def). */ |
| |
| void |
| cxx_incomplete_type_diagnostic (location_t loc, const_tree value, |
| const_tree type, diagnostic_t diag_kind) |
| { |
| bool is_decl = false, complained = false; |
| |
| gcc_assert (diag_kind == DK_WARNING |
| || diag_kind == DK_PEDWARN |
| || diag_kind == DK_ERROR); |
| |
| /* Avoid duplicate error message. */ |
| if (TREE_CODE (type) == ERROR_MARK) |
| return; |
| |
| if (value) |
| { |
| STRIP_ANY_LOCATION_WRAPPER (value); |
| |
| if (VAR_P (value) |
| || TREE_CODE (value) == PARM_DECL |
| || TREE_CODE (value) == FIELD_DECL) |
| { |
| complained = emit_diagnostic (diag_kind, DECL_SOURCE_LOCATION (value), 0, |
| "%qD has incomplete type", value); |
| is_decl = true; |
| } |
| } |
| retry: |
| /* We must print an error message. Be clever about what it says. */ |
| |
| switch (TREE_CODE (type)) |
| { |
| case RECORD_TYPE: |
| case UNION_TYPE: |
| case ENUMERAL_TYPE: |
| if (!is_decl) |
| complained = emit_diagnostic (diag_kind, loc, 0, |
| "invalid use of incomplete type %q#T", |
| type); |
| if (complained) |
| cxx_incomplete_type_inform (type); |
| break; |
| |
| case VOID_TYPE: |
| emit_diagnostic (diag_kind, loc, 0, |
| "invalid use of %qT", type); |
| break; |
| |
| case ARRAY_TYPE: |
| if (TYPE_DOMAIN (type)) |
| { |
| type = TREE_TYPE (type); |
| goto retry; |
| } |
| emit_diagnostic (diag_kind, loc, 0, |
| "invalid use of array with unspecified bounds"); |
| break; |
| |
| case OFFSET_TYPE: |
| bad_member: |
| { |
| tree member = TREE_OPERAND (value, 1); |
| if (is_overloaded_fn (member)) |
| member = get_first_fn (member); |
| |
| if (DECL_FUNCTION_MEMBER_P (member) |
| && ! flag_ms_extensions) |
| { |
| gcc_rich_location richloc (loc); |
| /* If "member" has no arguments (other than "this"), then |
| add a fix-it hint. */ |
| if (type_num_arguments (TREE_TYPE (member)) == 1) |
| richloc.add_fixit_insert_after ("()"); |
| emit_diagnostic (diag_kind, &richloc, 0, |
| "invalid use of member function %qD " |
| "(did you forget the %<()%> ?)", member); |
| } |
| else |
| emit_diagnostic (diag_kind, loc, 0, |
| "invalid use of member %qD " |
| "(did you forget the %<&%> ?)", member); |
| } |
| break; |
| |
| case TEMPLATE_TYPE_PARM: |
| if (is_auto (type)) |
| { |
| if (CLASS_PLACEHOLDER_TEMPLATE (type)) |
| emit_diagnostic (diag_kind, loc, 0, |
| "invalid use of placeholder %qT", type); |
| else |
| emit_diagnostic (diag_kind, loc, 0, |
| "invalid use of %qT", type); |
| } |
| else |
| emit_diagnostic (diag_kind, loc, 0, |
| "invalid use of template type parameter %qT", type); |
| break; |
| |
| case BOUND_TEMPLATE_TEMPLATE_PARM: |
| emit_diagnostic (diag_kind, loc, 0, |
| "invalid use of template template parameter %qT", |
| TYPE_NAME (type)); |
| break; |
| |
| case TYPE_PACK_EXPANSION: |
| emit_diagnostic (diag_kind, loc, 0, |
| "invalid use of pack expansion %qT", type); |
| break; |
| |
| case TYPENAME_TYPE: |
| case DECLTYPE_TYPE: |
| emit_diagnostic (diag_kind, loc, 0, |
| "invalid use of dependent type %qT", type); |
| break; |
| |
| case LANG_TYPE: |
| if (type == init_list_type_node) |
| { |
| emit_diagnostic (diag_kind, loc, 0, |
| "invalid use of brace-enclosed initializer list"); |
| break; |
| } |
| gcc_assert (type == unknown_type_node); |
| if (value && TREE_CODE (value) == COMPONENT_REF) |
| goto bad_member; |
| else if (value && TREE_CODE (value) == ADDR_EXPR) |
| emit_diagnostic (diag_kind, loc, 0, |
| "address of overloaded function with no contextual " |
| "type information"); |
| else if (value && TREE_CODE (value) == OVERLOAD) |
| emit_diagnostic (diag_kind, loc, 0, |
| "overloaded function with no contextual type information"); |
| else |
| emit_diagnostic (diag_kind, loc, 0, |
| "insufficient contextual information to determine type"); |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| /* Print an error message for invalid use of an incomplete type. |
| VALUE is the expression that was used (or 0 if that isn't known) |
| and TYPE is the type that was invalid. */ |
| |
| void |
| cxx_incomplete_type_error (location_t loc, const_tree value, const_tree type) |
| { |
| cxx_incomplete_type_diagnostic (loc, value, type, DK_ERROR); |
| } |
| |
| |
| /* We've just initialized subobject SUB; also insert a TARGET_EXPR with an |
| EH-only cleanup for SUB. Because of EH region nesting issues, we need to |
| make the cleanup conditional on a flag that we will clear once the object is |
| fully initialized, so push a new flag onto FLAGS. */ |
| |
| static void |
| maybe_push_temp_cleanup (tree sub, vec<tree,va_gc> **flags) |
| { |
| if (!flag_exceptions) |
| return; |
| if (tree cleanup |
| = cxx_maybe_build_cleanup (sub, tf_warning_or_error)) |
| { |
| tree tx = get_target_expr (boolean_true_node); |
| tree flag = TARGET_EXPR_SLOT (tx); |
| CLEANUP_EH_ONLY (tx) = true; |
| TARGET_EXPR_CLEANUP (tx) = build3 (COND_EXPR, void_type_node, |
| flag, cleanup, void_node); |
| add_stmt (tx); |
| vec_safe_push (*flags, flag); |
| } |
| } |
| |
| /* The recursive part of split_nonconstant_init. DEST is an lvalue |
| expression to which INIT should be assigned. INIT is a CONSTRUCTOR. |
| Return true if the whole of the value was initialized by the |
| generated statements. */ |
| |
| static bool |
| split_nonconstant_init_1 (tree dest, tree init, bool last, |
| vec<tree,va_gc> **flags) |
| { |
| unsigned HOST_WIDE_INT idx, tidx = HOST_WIDE_INT_M1U; |
| tree field_index, value; |
| tree type = TREE_TYPE (dest); |
| tree inner_type = NULL; |
| bool array_type_p = false; |
| bool complete_p = true; |
| HOST_WIDE_INT num_split_elts = 0; |
| tree last_split_elt = NULL_TREE; |
| |
| switch (TREE_CODE (type)) |
| { |
| case ARRAY_TYPE: |
| inner_type = TREE_TYPE (type); |
| array_type_p = true; |
| if ((TREE_SIDE_EFFECTS (init) |
| && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) |
| || vla_type_p (type)) |
| { |
| if (!TYPE_DOMAIN (type) |
| && TREE_CODE (init) == CONSTRUCTOR |
| && CONSTRUCTOR_NELTS (init)) |
| { |
| /* Flexible array. */ |
| cp_complete_array_type (&type, init, /*default*/true); |
| dest = build1 (VIEW_CONVERT_EXPR, type, dest); |
| } |
| |
| /* For an array, we only need/want a single cleanup region rather |
| than one per element. build_vec_init will handle it. */ |
| tree code = build_vec_init (dest, NULL_TREE, init, false, 1, |
| tf_warning_or_error, flags); |
| add_stmt (code); |
| return true; |
| } |
| /* FALLTHRU */ |
| |
| case RECORD_TYPE: |
| case UNION_TYPE: |
| case QUAL_UNION_TYPE: |
| FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx, |
| field_index, value) |
| { |
| /* The current implementation of this algorithm assumes that |
| the field was set for all the elements. This is usually done |
| by process_init_constructor. */ |
| gcc_assert (field_index); |
| |
| if (!array_type_p) |
| inner_type = TREE_TYPE (field_index); |
| |
| tree sub; |
| if (array_type_p) |
| sub = build4 (ARRAY_REF, inner_type, dest, field_index, |
| NULL_TREE, NULL_TREE); |
| else |
| sub = build3 (COMPONENT_REF, inner_type, dest, field_index, |
| NULL_TREE); |
| |
| bool elt_last = last && idx == CONSTRUCTOR_NELTS (init) - 1; |
| |
| /* We need to see sub-array TARGET_EXPR before cp_fold_r so we can |
| handle cleanup flags properly. */ |
| gcc_checking_assert (!target_expr_needs_replace (value)); |
| |
| if (TREE_CODE (value) == CONSTRUCTOR) |
| { |
| if (!split_nonconstant_init_1 (sub, value, elt_last, flags) |
| /* For flexible array member with initializer we |
| can't remove the initializer, because only the |
| initializer determines how many elements the |
| flexible array member has. */ |
| || (!array_type_p |
| && TREE_CODE (inner_type) == ARRAY_TYPE |
| && TYPE_DOMAIN (inner_type) == NULL |
| && TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE |
| && COMPLETE_TYPE_P (TREE_TYPE (value)) |
| && !integer_zerop (TYPE_SIZE (TREE_TYPE (value))) |
| && elt_last |
| && TYPE_HAS_TRIVIAL_DESTRUCTOR |
| (strip_array_types (inner_type)))) |
| complete_p = false; |
| else |
| { |
| /* Mark element for removal. */ |
| last_split_elt = field_index; |
| CONSTRUCTOR_ELT (init, idx)->index = NULL_TREE; |
| if (idx < tidx) |
| tidx = idx; |
| num_split_elts++; |
| } |
| } |
| else if (tree vi = get_vec_init_expr (value)) |
| { |
| add_stmt (expand_vec_init_expr (sub, vi, tf_warning_or_error, |
| flags)); |
| |
| /* Mark element for removal. */ |
| last_split_elt = field_index; |
| CONSTRUCTOR_ELT (init, idx)->index = NULL_TREE; |
| if (idx < tidx) |
| tidx = idx; |
| num_split_elts++; |
| } |
| else if (!initializer_constant_valid_p (value, inner_type)) |
| { |
| tree code; |
| |
| /* Push cleanups for any preceding members with constant |
| initialization. */ |
| if (CLASS_TYPE_P (type)) |
| for (tree prev = (last_split_elt ? |
| DECL_CHAIN (last_split_elt) |
| : TYPE_FIELDS (type)); |
| ; prev = DECL_CHAIN (prev)) |
| { |
| prev = next_initializable_field (prev); |
| if (prev == field_index) |
| break; |
| tree ptype = TREE_TYPE (prev); |
| if (type_build_dtor_call (ptype)) |
| { |
| tree pcref = build3 (COMPONENT_REF, ptype, dest, prev, |
| NULL_TREE); |
| maybe_push_temp_cleanup (pcref, flags); |
| } |
| } |
| |
| /* Mark element for removal. */ |
| CONSTRUCTOR_ELT (init, idx)->index = NULL_TREE; |
| if (idx < tidx) |
| tidx = idx; |
| |
| if (TREE_CODE (field_index) == RANGE_EXPR) |
| { |
| /* Use build_vec_init to initialize a range. */ |
| tree low = TREE_OPERAND (field_index, 0); |
| tree hi = TREE_OPERAND (field_index, 1); |
| sub = build4 (ARRAY_REF, inner_type, dest, low, |
| NULL_TREE, NULL_TREE); |
| sub = cp_build_addr_expr (sub, tf_warning_or_error); |
| tree max = size_binop (MINUS_EXPR, hi, low); |
| code = build_vec_init (sub, max, value, false, 0, |
| tf_warning_or_error); |
| add_stmt (code); |
| if (tree_fits_shwi_p (max)) |
| num_split_elts += tree_to_shwi (max); |
| } |
| else |
| { |
| /* We may need to add a copy constructor call if |
| the field has [[no_unique_address]]. */ |
| if (unsafe_return_slot_p (sub)) |
| { |
| /* But not if the initializer is an implicit ctor call |
| we just built in digest_init. */ |
| if (TREE_CODE (value) == TARGET_EXPR |
| && TARGET_EXPR_LIST_INIT_P (value) |
| && make_safe_copy_elision (sub, value)) |
| goto build_init; |
| |
| tree name = (DECL_FIELD_IS_BASE (field_index) |
| ? base_ctor_identifier |
| : complete_ctor_identifier); |
| releasing_vec args = make_tree_vector_single (value); |
| code = build_special_member_call |
| (sub, name, &args, inner_type, |
| LOOKUP_NORMAL, tf_warning_or_error); |
| } |
| else |
| { |
| build_init: |
| code = build2 (INIT_EXPR, inner_type, sub, value); |
| } |
| code = build_stmt (input_location, EXPR_STMT, code); |
| add_stmt (code); |
| if (!elt_last) |
| maybe_push_temp_cleanup (sub, flags); |
| } |
| |
| last_split_elt = field_index; |
| num_split_elts++; |
| } |
| } |
| if (num_split_elts == 1) |
| CONSTRUCTOR_ELTS (init)->ordered_remove (tidx); |
| else if (num_split_elts > 1) |
| { |
| /* Perform the delayed ordered removal of non-constant elements |
| we split out. */ |
| for (idx = tidx; idx < CONSTRUCTOR_NELTS (init); ++idx) |
| if (CONSTRUCTOR_ELT (init, idx)->index == NULL_TREE) |
| ; |
| else |
| { |
| *CONSTRUCTOR_ELT (init, tidx) = *CONSTRUCTOR_ELT (init, idx); |
| ++tidx; |
| } |
| vec_safe_truncate (CONSTRUCTOR_ELTS (init), tidx); |
| } |
| break; |
| |
| case VECTOR_TYPE: |
| if (!initializer_constant_valid_p (init, type)) |
| { |
| tree code; |
| tree cons = copy_node (init); |
| CONSTRUCTOR_ELTS (init) = NULL; |
| code = build2 (MODIFY_EXPR, type, dest, cons); |
| code = build_stmt (input_location, EXPR_STMT, code); |
| add_stmt (code); |
| num_split_elts += CONSTRUCTOR_NELTS (init); |
| } |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| /* The rest of the initializer is now a constant. */ |
| TREE_CONSTANT (init) = 1; |
| TREE_SIDE_EFFECTS (init) = 0; |
| |
| /* We didn't split out anything. */ |
| if (num_split_elts == 0) |
| return false; |
| |
| return complete_p && complete_ctor_at_level_p (TREE_TYPE (init), |
| num_split_elts, inner_type); |
| } |
| |
| /* A subroutine of store_init_value. Splits non-constant static |
| initializer INIT into a constant part and generates code to |
| perform the non-constant part of the initialization to DEST. |
| Returns the code for the runtime init. */ |
| |
| tree |
| split_nonconstant_init (tree dest, tree init) |
| { |
| tree code; |
| |
| if (TREE_CODE (init) == TARGET_EXPR) |
| init = TARGET_EXPR_INITIAL (init); |
| if (TREE_CODE (init) == CONSTRUCTOR) |
| { |
| /* Subobject initializers are not full-expressions. */ |
| auto fe = (make_temp_override |
| (current_stmt_tree ()->stmts_are_full_exprs_p, 0)); |
| |
| init = cp_fully_fold_init (init); |
| code = push_stmt_list (); |
| |
| /* If the complete object is an array, build_vec_init's cleanup is |
| enough. Otherwise, collect flags for disabling subobject |
| cleanups once the complete object is fully constructed. */ |
| vec<tree, va_gc> *flags = nullptr; |
| if (TREE_CODE (TREE_TYPE (dest)) != ARRAY_TYPE) |
| flags = make_tree_vector (); |
| |
| if (split_nonconstant_init_1 (dest, init, true, &flags)) |
| init = NULL_TREE; |
| |
| for (tree f : flags) |
| { |
| /* See maybe_push_temp_cleanup. */ |
| tree d = f; |
| tree i = boolean_false_node; |
| if (TREE_CODE (f) == TREE_LIST) |
| { |
| /* To disable a build_vec_init cleanup, set |
| iterator = maxindex. */ |
| d = TREE_PURPOSE (f); |
| i = TREE_VALUE (f); |
| ggc_free (f); |
| } |
| add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (d), d, i)); |
| } |
| release_tree_vector (flags); |
| |
| code = pop_stmt_list (code); |
| if (VAR_P (dest) && !is_local_temp (dest)) |
| { |
| DECL_INITIAL (dest) = init; |
| TREE_READONLY (dest) = 0; |
| } |
| else if (init) |
| { |
| tree ie = build2 (INIT_EXPR, void_type_node, dest, init); |
| code = add_stmt_to_compound (ie, code); |
| } |
| } |
| else if (TREE_CODE (init) == STRING_CST |
| && array_of_runtime_bound_p (TREE_TYPE (dest))) |
| 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); |
| |
| return code; |
| } |
| |
| /* Perform appropriate conversions on the initial value of a variable, |
| store it in the declaration DECL, |
| and print any error messages that are appropriate. |
| If the init is invalid, store an ERROR_MARK. |
| |
| C++: Note that INIT might be a TREE_LIST, which would mean that it is |
| a base class initializer for some aggregate type, hopefully compatible |
| with DECL. If INIT is a single element, and DECL is an aggregate |
| type, we silently convert INIT into a TREE_LIST, allowing a constructor |
| to be called. |
| |
| If INIT is a TREE_LIST and there is no constructor, turn INIT |
| into a CONSTRUCTOR and use standard initialization techniques. |
| Perhaps a warning should be generated? |
| |
| Returns code to be executed if initialization could not be performed |
| for static variable. In that case, caller must emit the code. */ |
| |
| tree |
| store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags) |
| { |
| tree value, type; |
| |
| /* If variable's type was invalidly declared, just ignore it. */ |
| |
| type = TREE_TYPE (decl); |
| if (TREE_CODE (type) == ERROR_MARK) |
| return NULL_TREE; |
| |
| if (MAYBE_CLASS_TYPE_P (type)) |
| { |
| if (TREE_CODE (init) == TREE_LIST) |
| { |
| error ("constructor syntax used, but no constructor declared " |
| "for type %qT", type); |
| init = build_constructor_from_list (init_list_type_node, nreverse (init)); |
| } |
| } |
| |
| /* End of special C++ code. */ |
| |
| if (flags & LOOKUP_ALREADY_DIGESTED) |
| value = init; |
| else |
| { |
| if (TREE_STATIC (decl)) |
| flags |= LOOKUP_ALLOW_FLEXARRAY_INIT; |
| /* Digest the specified initializer into an expression. */ |
| value = digest_init_flags (type, init, flags, tf_warning_or_error); |
| } |
| |
| /* Look for braced array initializers for character arrays and |
| recursively convert them into STRING_CSTs. */ |
| value = braced_lists_to_strings (type, value); |
| |
| current_ref_temp_count = 0; |
| value = extend_ref_init_temps (decl, value, cleanups); |
| |
| /* In C++11 constant expression is a semantic, not syntactic, property. |
| In C++98, make sure that what we thought was a constant expression at |
| template definition time is still constant and otherwise perform this |
| as optimization, e.g. to fold SIZEOF_EXPRs in the initializer. */ |
| if (decl_maybe_constant_var_p (decl) || TREE_STATIC (decl)) |
| { |
| bool const_init; |
| tree oldval = value; |
| if (DECL_DECLARED_CONSTEXPR_P (decl) |
| || (DECL_IN_AGGR_P (decl) |
| && DECL_INITIALIZED_IN_CLASS_P (decl))) |
| { |
| value = fold_non_dependent_expr (value, tf_warning_or_error, |
| /*manifestly_const_eval=*/true, |
| decl); |
| /* Diagnose a non-constant initializer for constexpr variable or |
| non-inline in-class-initialized static data member. */ |
| if (!require_constant_expression (value)) |
| value = error_mark_node; |
| else if (processing_template_decl) |
| /* In a template we might not have done the necessary |
| transformations to make value actually constant, |
| e.g. extend_ref_init_temps. */ |
| value = maybe_constant_init (value, decl, true); |
| else |
| value = cxx_constant_init (value, decl); |
| } |
| else |
| value = fold_non_dependent_init (value, tf_warning_or_error, |
| /*manifestly_const_eval=*/true, decl); |
| if (TREE_CODE (value) == CONSTRUCTOR && cp_has_mutable_p (type)) |
| /* Poison this CONSTRUCTOR so it can't be copied to another |
| constexpr variable. */ |
| CONSTRUCTOR_MUTABLE_POISON (value) = true; |
| const_init = (reduced_constant_expression_p (value) |
| || error_operand_p (value)); |
| DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init; |
| /* FIXME setting TREE_CONSTANT on refs breaks the back end. */ |
| if (!TYPE_REF_P (type)) |
| TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl); |
| if (!const_init) |
| { |
| /* [dcl.constinit]/2 "If a variable declared with the constinit |
| specifier has dynamic initialization, the program is |
| ill-formed." */ |
| if (DECL_DECLARED_CONSTINIT_P (decl)) |
| { |
| error_at (location_of (decl), |
| "%<constinit%> variable %qD does not have a constant " |
| "initializer", decl); |
| if (require_constant_expression (value)) |
| cxx_constant_init (value, decl); |
| value = error_mark_node; |
| } |
| else |
| value = oldval; |
| } |
| } |
| /* Don't fold initializers of automatic variables in constexpr functions, |
| that might fold away something that needs to be diagnosed at constexpr |
| evaluation time. */ |
| if (!current_function_decl |
| || !DECL_DECLARED_CONSTEXPR_P (current_function_decl) |
| || TREE_STATIC (decl)) |
| value = cp_fully_fold_init (value); |
| |
| /* Handle aggregate NSDMI in non-constant initializers, too. */ |
| value = replace_placeholders (value, decl); |
| |
| /* A COMPOUND_LITERAL_P CONSTRUCTOR is the syntactic form; by the time we get |
| here it should have been digested into an actual value for the type. */ |
| gcc_checking_assert (TREE_CODE (value) != CONSTRUCTOR |
| || processing_template_decl |
| || TREE_CODE (type) == VECTOR_TYPE |
| || !TREE_HAS_CONSTRUCTOR (value)); |
| |
| /* If the initializer is not a constant, fill in DECL_INITIAL with |
| the bits that are constant, and then return an expression that |
| will perform the dynamic initialization. */ |
| if (value != error_mark_node |
| && !processing_template_decl |
| && (TREE_SIDE_EFFECTS (value) |
| || vla_type_p (type) |
| || ! reduced_constant_expression_p (value))) |
| return split_nonconstant_init (decl, value); |
| |
| /* DECL may change value; purge caches. */ |
| clear_cv_and_fold_caches (); |
| |
| /* If the value is a constant, just put it in DECL_INITIAL. If DECL |
| is an automatic variable, the middle end will turn this into a |
| dynamic initialization later. */ |
| DECL_INITIAL (decl) = value; |
| return NULL_TREE; |
| } |
| |
| |
| /* Give diagnostic about narrowing conversions within { }, or as part of |
| a converted constant expression. If CONST_ONLY, only check |
| constants. */ |
| |
| bool |
| check_narrowing (tree type, tree init, tsubst_flags_t complain, |
| bool const_only/*= false*/) |
| { |
| tree ftype = unlowered_expr_type (init); |
| bool ok = true; |
| REAL_VALUE_TYPE d; |
| |
| if (((!warn_narrowing || !(complain & tf_warning)) |
| && cxx_dialect == cxx98) |
| || !ARITHMETIC_TYPE_P (type) |
| /* Don't emit bogus warnings with e.g. value-dependent trees. */ |
| || instantiation_dependent_expression_p (init)) |
| return ok; |
| |
| if (BRACE_ENCLOSED_INITIALIZER_P (init) |
| && TREE_CODE (type) == COMPLEX_TYPE) |
| { |
| tree elttype = TREE_TYPE (type); |
| if (CONSTRUCTOR_NELTS (init) > 0) |
| ok &= check_narrowing (elttype, CONSTRUCTOR_ELT (init, 0)->value, |
| complain); |
| if (CONSTRUCTOR_NELTS (init) > 1) |
| ok &= check_narrowing (elttype, CONSTRUCTOR_ELT (init, 1)->value, |
| complain); |
| return ok; |
| } |
| |
| /* Even non-dependent expressions can still have template |
| codes like CAST_EXPR, so use *_non_dependent_expr to cope. */ |
| init = fold_non_dependent_expr (init, complain, /*manifest*/true); |
| if (init == error_mark_node) |
| return ok; |
| |
| /* If we were asked to only check constants, return early. */ |
| if (const_only && !TREE_CONSTANT (init)) |
| return ok; |
| |
| if (CP_INTEGRAL_TYPE_P (type) |
| && TREE_CODE (ftype) == REAL_TYPE) |
| ok = false; |
| else if (INTEGRAL_OR_ENUMERATION_TYPE_P (ftype) |
| && CP_INTEGRAL_TYPE_P (type)) |
| { |
| if (TREE_CODE (ftype) == ENUMERAL_TYPE) |
| /* Check for narrowing based on the values of the enumeration. */ |
| ftype = ENUM_UNDERLYING_TYPE (ftype); |
| if ((tree_int_cst_lt (TYPE_MAX_VALUE (type), |
| TYPE_MAX_VALUE (ftype)) |
| || tree_int_cst_lt (TYPE_MIN_VALUE (ftype), |
| TYPE_MIN_VALUE (type))) |
| && (TREE_CODE (init) != INTEGER_CST |
| || !int_fits_type_p (init, type))) |
| ok = false; |
| } |
| /* [dcl.init.list]#7.2: "from long double to double or float, or from |
| double to float". */ |
| else if (TREE_CODE (ftype) == REAL_TYPE |
| && TREE_CODE (type) == REAL_TYPE) |
| { |
| if ((same_type_p (ftype, long_double_type_node) |
| && (same_type_p (type, double_type_node) |
| || same_type_p (type, float_type_node))) |
| || (same_type_p (ftype, double_type_node) |
| && same_type_p (type, float_type_node)) |
| || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype))) |
| { |
| if (TREE_CODE (init) == REAL_CST) |
| { |
| /* Issue 703: Loss of precision is OK as long as the value is |
| within the representable range of the new type. */ |
| REAL_VALUE_TYPE r; |
| d = TREE_REAL_CST (init); |
| real_convert (&r, TYPE_MODE (type), &d); |
| if (real_isinf (&r)) |
| ok = false; |
| } |
| else |
| ok = false; |
| } |
| } |
| else if (INTEGRAL_OR_ENUMERATION_TYPE_P (ftype) |
| && TREE_CODE (type) == REAL_TYPE) |
| { |
| ok = false; |
| if (TREE_CODE (init) == INTEGER_CST) |
| { |
| d = real_value_from_int_cst (0, init); |
| if (exact_real_truncate (TYPE_MODE (type), &d)) |
| ok = true; |
| } |
| } |
| else if (TREE_CODE (type) == BOOLEAN_TYPE |
| && (TYPE_PTR_P (ftype) || TYPE_PTRMEM_P (ftype))) |
| /* C++20 P1957R2: converting from a pointer type or a pointer-to-member |
| type to bool should be considered narrowing. This is a DR so is not |
| limited to C++20 only. */ |
| ok = false; |
| |
| bool almost_ok = ok; |
| if (!ok && !CONSTANT_CLASS_P (init) && (complain & tf_warning_or_error)) |
| { |
| tree folded = cp_fully_fold (init); |
| if (TREE_CONSTANT (folded) && check_narrowing (type, folded, tf_none)) |
| almost_ok = true; |
| } |
| |
| if (!ok) |
| { |
| location_t loc = cp_expr_loc_or_input_loc (init); |
| if (cxx_dialect == cxx98) |
| { |
| if (complain & tf_warning) |
| warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE " |
| "from %qH to %qI is ill-formed in C++11", |
| init, ftype, type); |
| ok = true; |
| } |
| else if (!CONSTANT_CLASS_P (init)) |
| { |
| if (complain & tf_warning_or_error) |
| { |
| auto_diagnostic_group d; |
| if ((!almost_ok || pedantic) |
| && pedwarn (loc, OPT_Wnarrowing, |
| "narrowing conversion of %qE from %qH to %qI", |
| init, ftype, type) |
| && almost_ok) |
| inform (loc, " the expression has a constant value but is not " |
| "a C++ constant-expression"); |
| ok = true; |
| } |
| } |
| else if (complain & tf_error) |
| { |
| int savederrorcount = errorcount; |
| global_dc->pedantic_errors = 1; |
| auto s = make_temp_override (global_dc->dc_warn_system_headers, true); |
| pedwarn (loc, OPT_Wnarrowing, |
| "narrowing conversion of %qE from %qH to %qI", |
| init, ftype, type); |
| if (errorcount == savederrorcount) |
| ok = true; |
| global_dc->pedantic_errors = flag_pedantic_errors; |
| } |
| } |
| |
| return ok; |
| } |
| |
| /* True iff TYPE is a C++20 "ordinary" character type. */ |
| |
| bool |
| ordinary_char_type_p (tree type) |
| { |
| type = TYPE_MAIN_VARIANT (type); |
| return (type == char_type_node |
| || type == signed_char_type_node |
| || type == unsigned_char_type_node); |
| } |
| |
| /* True iff the string literal INIT has a type suitable for initializing array |
| TYPE. */ |
| |
| bool |
| array_string_literal_compatible_p (tree type, tree init) |
| { |
| tree to_char_type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); |
| tree from_char_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init))); |
| |
| if (to_char_type == from_char_type) |
| return true; |
| /* The array element type does not match the initializing string |
| literal element type; this is only allowed when both types are |
| ordinary character type. There are no string literals of |
| signed or unsigned char type in the language, but we can get |
| them internally from converting braced-init-lists to |
| STRING_CST. */ |
| if (ordinary_char_type_p (to_char_type) |
| && ordinary_char_type_p (from_char_type)) |
| return true; |
| return false; |
| } |
| |
| /* Process the initializer INIT for a variable of type TYPE, emitting |
| diagnostics for invalid initializers and converting the initializer as |
| appropriate. |
| |
| For aggregate types, it assumes that reshape_init has already run, thus the |
| initializer will have the right shape (brace elision has been undone). |
| |
| NESTED is non-zero iff we are being called for an element of a CONSTRUCTOR, |
| 2 iff the element of a CONSTRUCTOR is inside another CONSTRUCTOR. */ |
| |
| static tree |
| digest_init_r (tree type, tree init, int nested, int flags, |
| tsubst_flags_t complain) |
| { |
| enum tree_code code = TREE_CODE (type); |
| |
| if (error_operand_p (init)) |
| return error_mark_node; |
| |
| gcc_assert (init); |
| |
| /* We must strip the outermost array type when completing the type, |
| because the its bounds might be incomplete at the moment. */ |
| if (!complete_type_or_maybe_complain (code == ARRAY_TYPE |
| ? TREE_TYPE (type) : type, NULL_TREE, |
| complain)) |
| return error_mark_node; |
| |
| location_t loc = cp_expr_loc_or_input_loc (init); |
| |
| tree stripped_init = init; |
| |
| if (BRACE_ENCLOSED_INITIALIZER_P (init) |
| && CONSTRUCTOR_IS_PAREN_INIT (init)) |
| flags |= LOOKUP_AGGREGATE_PAREN_INIT; |
| |
| /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue |
| (g++.old-deja/g++.law/casts2.C). */ |
| if (TREE_CODE (init) == NON_LVALUE_EXPR) |
| stripped_init = TREE_OPERAND (init, 0); |
| |
| stripped_init = tree_strip_any_location_wrapper (stripped_init); |
| |
| /* Initialization of an array of chars from a string constant. The initializer |
| can be optionally enclosed in braces, but reshape_init has already removed |
| them if they were present. */ |
| if (code == ARRAY_TYPE) |
| { |
| if (nested && !TYPE_DOMAIN (type)) |
| /* C++ flexible array members have a null domain. */ |
| { |
| if (flags & LOOKUP_ALLOW_FLEXARRAY_INIT) |
| pedwarn (loc, OPT_Wpedantic, |
| "initialization of a flexible array member"); |
| else |
| { |
| if (complain & tf_error) |
| error_at (loc, "non-static initialization of" |
| " a flexible array member"); |
| return error_mark_node; |
| } |
| } |
| |
| tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type)); |
| if (char_type_p (typ1) |
| && TREE_CODE (stripped_init) == STRING_CST) |
| { |
| if (!array_string_literal_compatible_p (type, init)) |
| { |
| if (complain & tf_error) |
| error_at (loc, "cannot initialize array of %qT from " |
| "a string literal with type array of %qT", |
| typ1, |
| TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)))); |
| return error_mark_node; |
| } |
| |
| if (nested == 2 && !TYPE_DOMAIN (type)) |
| { |
| if (complain & tf_error) |
| error_at (loc, "initialization of flexible array member " |
| "in a nested context"); |
| return error_mark_node; |
| } |
| |
| if (type != TREE_TYPE (init) |
| && !variably_modified_type_p (type, NULL_TREE)) |
| { |
| init = copy_node (init); |
| TREE_TYPE (init) = type; |
| /* If we have a location wrapper, then also copy the wrapped |
| node, and update the copy's type. */ |
| if (location_wrapper_p (init)) |
| { |
| stripped_init = copy_node (stripped_init); |
| TREE_OPERAND (init, 0) = stripped_init; |
| TREE_TYPE (stripped_init) = type; |
| } |
| } |
| if (TYPE_DOMAIN (type) && TREE_CONSTANT (TYPE_SIZE (type))) |
| { |
| /* Not a flexible array member. */ |
| int size = TREE_INT_CST_LOW (TYPE_SIZE (type)); |
| size = (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT; |
| /* In C it is ok to subtract 1 from the length of the string |
| because it's ok to ignore the terminating null char that is |
| counted in the length of the constant, but in C++ this would |
| be invalid. */ |
| if (size < TREE_STRING_LENGTH (stripped_init)) |
| { |
| permerror (loc, "initializer-string for %qT is too long", |
| type); |
| |
| init = build_string (size, |
| TREE_STRING_POINTER (stripped_init)); |
| TREE_TYPE (init) = type; |
| } |
| } |
| return init; |
| } |
| } |
| |
| /* Handle scalar types (including conversions) and references. */ |
| if ((code != COMPLEX_TYPE || BRACE_ENCLOSED_INITIALIZER_P (stripped_init)) |
| && (SCALAR_TYPE_P (type) || code == REFERENCE_TYPE)) |
| { |
| /* Narrowing is OK when initializing an aggregate from |
| a parenthesized list. */ |
| if (nested && !(flags & LOOKUP_AGGREGATE_PAREN_INIT)) |
| flags |= LOOKUP_NO_NARROWING; |
| init = convert_for_initialization (0, type, init, flags, |
| ICR_INIT, NULL_TREE, 0, |
| complain); |
| |
| return init; |
| } |
| |
| /* Come here only for aggregates: records, arrays, unions, complex numbers |
| and vectors. */ |
| gcc_assert (code == ARRAY_TYPE |
| || VECTOR_TYPE_P (type) |
| || code == RECORD_TYPE |
| || code == UNION_TYPE |
| || code == OPAQUE_TYPE |
| || code == COMPLEX_TYPE); |
| |
| /* "If T is a class type and the initializer list has a single |
| element of type cv U, where U is T or a class derived from T, |
| the object is initialized from that element." */ |
| if (cxx_dialect >= cxx11 |
| && BRACE_ENCLOSED_INITIALIZER_P (stripped_init) |
| && !CONSTRUCTOR_IS_DESIGNATED_INIT (stripped_init) |
| && CONSTRUCTOR_NELTS (stripped_init) == 1 |
| && ((CLASS_TYPE_P (type) && !CLASSTYPE_NON_AGGREGATE (type)) |
| || VECTOR_TYPE_P (type))) |
| { |
| tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value; |
| if (reference_related_p (type, TREE_TYPE (elt))) |
| { |
| /* In C++17, aggregates can have bases, thus participate in |
| aggregate initialization. In the following case: |
| |
| struct B { int c; }; |
| struct D : B { }; |
| D d{{D{{42}}}}; |
| |
| there's an extra set of braces, so the D temporary initializes |
| the first element of d, which is the B base subobject. The base |
| of type B is copy-initialized from the D temporary, causing |
| object slicing. */ |
| tree field = next_initializable_field (TYPE_FIELDS (type)); |
| if (field && DECL_FIELD_IS_BASE (field)) |
| { |
| if (warning_at (loc, 0, "initializing a base class of type %qT " |
| "results in object slicing", TREE_TYPE (field))) |
| inform (loc, "remove %<{ }%> around initializer"); |
| } |
| else if (flag_checking) |
| /* We should have fixed this in reshape_init. */ |
| gcc_unreachable (); |
| } |
| } |
| |
| if (SIMPLE_TARGET_EXPR_P (stripped_init)) |
| stripped_init = TARGET_EXPR_INITIAL (stripped_init); |
| |
| if (BRACE_ENCLOSED_INITIALIZER_P (stripped_init) |
| && !TYPE_NON_AGGREGATE_CLASS (type)) |
| return process_init_constructor (type, stripped_init, nested, flags, |
| complain); |
| else |
| { |
| if (COMPOUND_LITERAL_P (stripped_init) && code == ARRAY_TYPE) |
| { |
| if (complain & tf_error) |
| error_at (loc, "cannot initialize aggregate of type %qT with " |
| "a compound literal", type); |
| |
| return error_mark_node; |
| } |
| |
| if (code == ARRAY_TYPE |
| && !BRACE_ENCLOSED_INITIALIZER_P (stripped_init)) |
| { |
| /* Allow the result of build_array_copy and of |
| build_value_init_noctor. */ |
| if ((TREE_CODE (stripped_init) == VEC_INIT_EXPR |
| || TREE_CODE (stripped_init) == CONSTRUCTOR) |
| && (same_type_ignoring_top_level_qualifiers_p |
| (type, TREE_TYPE (init)))) |
| return init; |
| |
| if (complain & tf_error) |
| error_at (loc, "array must be initialized with a brace-enclosed" |
| " initializer"); |
| return error_mark_node; |
| } |
| |
| return convert_for_initialization (NULL_TREE, type, init, |
| flags, |
| ICR_INIT, NULL_TREE, 0, |
| complain); |
| } |
| } |
| |
| tree |
| digest_init (tree type, tree init, tsubst_flags_t complain) |
| { |
| return digest_init_r (type, init, 0, LOOKUP_IMPLICIT, complain); |
| } |
| |
| tree |
| digest_init_flags (tree type, tree init, int flags, tsubst_flags_t complain) |
| { |
| return digest_init_r (type, init, 0, flags, complain); |
| } |
| |
| /* Process the initializer INIT for an NSDMI DECL (a FIELD_DECL). */ |
| tree |
| digest_nsdmi_init (tree decl, tree init, tsubst_flags_t complain) |
| { |
| gcc_assert (TREE_CODE (decl) == FIELD_DECL); |
| |
| tree type = TREE_TYPE (decl); |
| if (DECL_BIT_FIELD_TYPE (decl)) |
| type = DECL_BIT_FIELD_TYPE (decl); |
| int flags = LOOKUP_IMPLICIT; |
| if (DIRECT_LIST_INIT_P (init)) |
| { |
| flags = LOOKUP_NORMAL; |
| complain |= tf_no_cleanup; |
| } |
| if (BRACE_ENCLOSED_INITIALIZER_P (init) |
| && CP_AGGREGATE_TYPE_P (type)) |
| init = reshape_init (type, init, complain); |
| init = digest_init_flags (type, init, flags, complain); |
| return init; |
| } |
| |
| /* Set of flags used within process_init_constructor to describe the |
| initializers. */ |
| #define PICFLAG_ERRONEOUS 1 |
| #define PICFLAG_NOT_ALL_CONSTANT 2 |
| #define PICFLAG_NOT_ALL_SIMPLE 4 |
| #define PICFLAG_SIDE_EFFECTS 8 |
| #define PICFLAG_VEC_INIT 16 |
| |
| /* Given an initializer INIT, return the flag (PICFLAG_*) which better |
| describe it. */ |
| |
| static int |
| picflag_from_initializer (tree init) |
| { |
| if (init == error_mark_node) |
| return PICFLAG_ERRONEOUS; |
| else if (!TREE_CONSTANT (init)) |
| { |
| if (TREE_SIDE_EFFECTS (init)) |
| return PICFLAG_SIDE_EFFECTS; |
| else |
| return PICFLAG_NOT_ALL_CONSTANT; |
| } |
| else if (!initializer_constant_valid_p (init, TREE_TYPE (init))) |
| return PICFLAG_NOT_ALL_SIMPLE; |
| return 0; |
| } |
| |
| /* Adjust INIT for going into a CONSTRUCTOR. */ |
| |
| static tree |
| massage_init_elt (tree type, tree init, int nested, int flags, |
| tsubst_flags_t complain) |
| { |
| int new_flags = LOOKUP_IMPLICIT; |
| if (flags & LOOKUP_ALLOW_FLEXARRAY_INIT) |
| new_flags |= LOOKUP_ALLOW_FLEXARRAY_INIT; |
| if (flags & LOOKUP_AGGREGATE_PAREN_INIT) |
| new_flags |= LOOKUP_AGGREGATE_PAREN_INIT; |
| init = digest_init_r (type, init, nested ? 2 : 1, new_flags, complain); |
| /* When we defer constant folding within a statement, we may want to |
| defer this folding as well. Don't call this on CONSTRUCTORs because |
| their elements have already been folded, and we must avoid folding |
| the result of get_nsdmi. */ |
| if (TREE_CODE (init) != CONSTRUCTOR) |
| { |
| tree t = fold_non_dependent_init (init, complain); |
| if (TREE_CONSTANT (t)) |
| init = t; |
| } |
| return init; |
| } |
| |
| /* Subroutine of process_init_constructor, which will process an initializer |
| INIT for an array or vector of type TYPE. Returns the flags (PICFLAG_*) |
| which describe the initializers. */ |
| |
| static int |
| process_init_constructor_array (tree type, tree init, int nested, int flags, |
| tsubst_flags_t complain) |
| { |
| unsigned HOST_WIDE_INT i, len = 0; |
| int picflags = 0; |
| bool unbounded = false; |
| constructor_elt *ce; |
| vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init); |
| |
| gcc_assert (TREE_CODE (type) == ARRAY_TYPE |
| || VECTOR_TYPE_P (type)); |
| |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| /* C++ flexible array members have a null domain. */ |
| tree domain = TYPE_DOMAIN (type); |
| if (domain && TREE_CONSTANT (TYPE_MAX_VALUE (domain))) |
| len = wi::ext (wi::to_offset (TYPE_MAX_VALUE (domain)) |
| - wi::to_offset (TYPE_MIN_VALUE (domain)) + 1, |
| TYPE_PRECISION (TREE_TYPE (domain)), |
| TYPE_SIGN (TREE_TYPE (domain))).to_uhwi (); |
| else |
| unbounded = true; /* Take as many as there are. */ |
| |
| if (nested == 2 && !domain && !vec_safe_is_empty (v)) |
| { |
| if (complain & tf_error) |
| error_at (cp_expr_loc_or_input_loc (init), |
| "initialization of flexible array member " |
| "in a nested context"); |
| return PICFLAG_ERRONEOUS; |
| } |
| } |
| else |
| /* Vectors are like simple fixed-size arrays. */ |
| unbounded = !TYPE_VECTOR_SUBPARTS (type).is_constant (&len); |
| |
| /* There must not be more initializers than needed. */ |
| if (!unbounded && vec_safe_length (v) > len) |
| { |
| if (complain & tf_error) |
| error ("too many initializers for %qT", type); |
| else |
| return PICFLAG_ERRONEOUS; |
| } |
| |
| FOR_EACH_VEC_SAFE_ELT (v, i, ce) |
| { |
| if (!ce->index) |
| ce->index = size_int (i); |
| else if (!check_array_designated_initializer (ce, i)) |
| ce->index = error_mark_node; |
| gcc_assert (ce->value); |
| ce->value |
| = massage_init_elt (TREE_TYPE (type), ce->value, nested, flags, |
| complain); |
| |
| gcc_checking_assert |
| (ce->value == error_mark_node |
| || (same_type_ignoring_top_level_qualifiers_p |
| (strip_array_types (TREE_TYPE (type)), |
| strip_array_types (TREE_TYPE (ce->value))))); |
| |
| picflags |= picflag_from_initializer (ce->value); |
| /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer |
| CONSTRUCTOR. */ |
| if (TREE_CODE (ce->value) == CONSTRUCTOR |
| && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value)) |
| { |
| CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1; |
| CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value) = 0; |
| } |
| } |
| |
| /* No more initializers. If the array is unbounded, we are done. Otherwise, |
| we must add initializers ourselves. */ |
| if (!unbounded) |
| for (; i < len; ++i) |
| { |
| tree next; |
| |
| if (type_build_ctor_call (TREE_TYPE (type))) |
| { |
| /* If this type needs constructors run for default-initialization, |
| we can't rely on the back end to do it for us, so make the |
| initialization explicit by list-initializing from T{}. */ |
| next = build_constructor (init_list_type_node, NULL); |
| next = massage_init_elt (TREE_TYPE (type), next, nested, flags, |
| complain); |
| if (initializer_zerop (next)) |
| /* The default zero-initialization is fine for us; don't |
| add anything to the CONSTRUCTOR. */ |
| next = NULL_TREE; |
| } |
| else if (!zero_init_p (TREE_TYPE (type))) |
| next = build_zero_init (TREE_TYPE (type), |
| /*nelts=*/NULL_TREE, |
| /*static_storage_p=*/false); |
| else |
| /* The default zero-initialization is fine for us; don't |
| add anything to the CONSTRUCTOR. */ |
| next = NULL_TREE; |
| |
| if (next) |
| { |
| if (next != error_mark_node |
| && ! seen_error () // Improves error-recovery on anew5.C. |
| && (initializer_constant_valid_p (next, TREE_TYPE (next)) |
| != null_pointer_node)) |
| { |
| /* Use VEC_INIT_EXPR for non-constant initialization of |
| trailing elements with no explicit initializers. */ |
| picflags |= PICFLAG_VEC_INIT; |
| break; |
| } |
| |
| picflags |= picflag_from_initializer (next); |
| /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer |
| CONSTRUCTOR. */ |
| if (TREE_CODE (next) == CONSTRUCTOR |
| && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next)) |
| { |
| CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1; |
| CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next) = 0; |
| } |
| if (len > i+1) |
| { |
| tree range = build2 (RANGE_EXPR, size_type_node, |
| build_int_cst (size_type_node, i), |
| build_int_cst (size_type_node, len - 1)); |
| CONSTRUCTOR_APPEND_ELT (v, range, next); |
| break; |
| } |
| else |
| CONSTRUCTOR_APPEND_ELT (v, size_int (i), next); |
| } |
| else |
| /* Don't bother checking all the other elements. */ |
| break; |
| } |
| |
| CONSTRUCTOR_ELTS (init) = v; |
| return picflags; |
| } |
| |
| /* Subroutine of process_init_constructor, which will process an initializer |
| INIT for a class of type TYPE. Returns the flags (PICFLAG_*) which describe |
| the initializers. */ |
| |
| static int |
| process_init_constructor_record (tree type, tree init, int nested, int flags, |
| tsubst_flags_t complain) |
| { |
| vec<constructor_elt, va_gc> *v = NULL; |
| tree field; |
| int skipped = 0; |
| |
| gcc_assert (TREE_CODE (type) == RECORD_TYPE); |
| gcc_assert (!CLASSTYPE_VBASECLASSES (type)); |
| gcc_assert (!TYPE_BINFO (type) |
| || cxx_dialect >= cxx17 |
| || !BINFO_N_BASE_BINFOS (TYPE_BINFO (type))); |
| gcc_assert (!TYPE_POLYMORPHIC_P (type)); |
| |
| restart: |
| int picflags = 0; |
| unsigned HOST_WIDE_INT idx = 0; |
| int designator_skip = -1; |
| /* Generally, we will always have an index for each initializer (which is |
| a FIELD_DECL, put by reshape_init), but compound literals don't go trough |
| reshape_init. So we need to handle both cases. */ |
| for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) |
| { |
| tree next; |
| |
| if (TREE_CODE (field) != FIELD_DECL |
| || (DECL_ARTIFICIAL (field) |
| && !(cxx_dialect >= cxx17 && DECL_FIELD_IS_BASE (field)))) |
| continue; |
| |
| if (DECL_UNNAMED_BIT_FIELD (field)) |
| continue; |
| |
| /* If this is a bitfield, first convert to the declared type. */ |
| tree fldtype = TREE_TYPE (field); |
| if (DECL_BIT_FIELD_TYPE (field)) |
| fldtype = DECL_BIT_FIELD_TYPE (field); |
| if (fldtype == error_mark_node) |
| return PICFLAG_ERRONEOUS; |
| |
| next = NULL_TREE; |
| if (idx < CONSTRUCTOR_NELTS (init)) |
| { |
| constructor_elt *ce = &(*CONSTRUCTOR_ELTS (init))[idx]; |
| if (ce->index) |
| { |
| /* We can have either a FIELD_DECL or an IDENTIFIER_NODE. The |
| latter case can happen in templates where lookup has to be |
| deferred. */ |
| gcc_assert (TREE_CODE (ce->index) == FIELD_DECL |
| || identifier_p (ce->index)); |
| if (ce->index == field || ce->index == DECL_NAME (field)) |
| next = ce->value; |
| else |
| { |
| ce = NULL; |
| if (designator_skip == -1) |
| designator_skip = 1; |
| } |
| } |
| else |
| { |
| designator_skip = 0; |
| next = ce->value; |
| } |
| |
| if (ce) |
| { |
| gcc_assert (ce->value); |
| next = massage_init_elt (fldtype, next, nested, flags, complain); |
| ++idx; |
| } |
| } |
| if (next == error_mark_node) |
| /* We skip initializers for empty bases/fields, so skipping an invalid |
| one could make us accept invalid code. */ |
| return PICFLAG_ERRONEOUS; |
| else if (next) |
| /* Already handled above. */; |
| else if (DECL_INITIAL (field)) |
| { |
| if (skipped > 0) |
| { |
| /* We're using an NSDMI past a field with implicit |
| zero-init. Go back and make it explicit. */ |
| skipped = -1; |
| vec_safe_truncate (v, 0); |
| goto restart; |
| } |
| /* C++14 aggregate NSDMI. */ |
| next = get_nsdmi (field, /*ctor*/false, complain); |
| if (!CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) |
| && find_placeholders (next)) |
| CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1; |
| } |
| else if (type_build_ctor_call (fldtype)) |
| { |
| /* If this type needs constructors run for |
| default-initialization, we can't rely on the back end to do it |
| for us, so build up TARGET_EXPRs. If the type in question is |
| 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); |
| |
| /* Warn when some struct elements are implicitly initialized. */ |
| if ((complain & tf_warning) |
| && !cp_unevaluated_operand |
| && !EMPTY_CONSTRUCTOR_P (init)) |
| warning (OPT_Wmissing_field_initializers, |
| "missing initializer for member %qD", field); |
| } |
| else |
| { |
| if (TYPE_REF_P (fldtype)) |
| { |
| if (complain & tf_error) |
| error ("member %qD is uninitialized reference", field); |
| else |
| return PICFLAG_ERRONEOUS; |
| } |
| else if (CLASSTYPE_REF_FIELDS_NEED_INIT (fldtype)) |
| { |
| if (complain & tf_error) |
| error ("member %qD with uninitialized reference fields", field); |
| else |
| return PICFLAG_ERRONEOUS; |
| } |
| /* Do nothing for flexible array members since they need not have any |
| elements. Don't worry about 'skipped' because a flexarray has to |
| be the last field. */ |
| else if (TREE_CODE (fldtype) == ARRAY_TYPE && !TYPE_DOMAIN (fldtype)) |
| continue; |
| |
| /* Warn when some struct elements are implicitly initialized |
| to zero. */ |
| if ((complain & tf_warning) |
| && !cp_unevaluated_operand |
| && !EMPTY_CONSTRUCTOR_P (init)) |
| warning (OPT_Wmissing_field_initializers, |
| "missing initializer for member %qD", field); |
| |
| if (!zero_init_p (fldtype) || skipped < 0) |
| { |
| if (TYPE_REF_P (fldtype)) |
| next = build_zero_cst (fldtype); |
| else |
| next = build_zero_init (fldtype, /*nelts=*/NULL_TREE, |
| /*static_storage_p=*/false); |
| } |
| else |
| { |
| /* The default zero-initialization is fine for us; don't |
| add anything to the CONSTRUCTOR. */ |
| skipped = 1; |
| continue; |
| } |
| } |
| |
| if (is_empty_field (field) |
| && !TREE_SIDE_EFFECTS (next)) |
| /* Don't add trivial initialization of an empty base/field to the |
| constructor, as they might not be ordered the way the back-end |
| expects. */ |
| continue; |
| |
| /* If this is a bitfield, now convert to the lowered type. */ |
| if (fldtype != TREE_TYPE (field)) |
| next = cp_convert_and_check (TREE_TYPE (field), next, complain); |
| picflags |= picflag_from_initializer (next); |
| /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer CONSTRUCTOR. */ |
| if (TREE_CODE (next) == CONSTRUCTOR |
| && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next)) |
| { |
| CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1; |
| CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next) = 0; |
| } |
| CONSTRUCTOR_APPEND_ELT (v, field, next); |
| } |
| |
| if (idx < CONSTRUCTOR_NELTS (init)) |
| { |
| if (complain & tf_error) |
| { |
| constructor_elt *ce = &(*CONSTRUCTOR_ELTS (init))[idx]; |
| /* For better diagnostics, try to find out if it is really |
| the case of too many initializers or if designators are |
| in incorrect order. */ |
| if (designator_skip == 1 && ce->index) |
| { |
| gcc_assert (TREE_CODE (ce->index) == FIELD_DECL |
| || identifier_p (ce->index)); |
| for (field = TYPE_FIELDS (type); |
| field; field = DECL_CHAIN (field)) |
| { |
| if (TREE_CODE (field) != FIELD_DECL |
| || (DECL_ARTIFICIAL (field) |
| && !(cxx_dialect >= cxx17 |
| && DECL_FIELD_IS_BASE (field)))) |
| continue; |
| |
| if (DECL_UNNAMED_BIT_FIELD (field)) |
| continue; |
| |
| if (ce->index == field || ce->index == DECL_NAME (field)) |
| break; |
| } |
| } |
| if (field) |
| error ("designator order for field %qD does not match declaration " |
| "order in %qT", field, type); |
| else |
| error ("too many initializers for %qT", type); |
| } |
| else |
| return PICFLAG_ERRONEOUS; |
| } |
| |
| CONSTRUCTOR_ELTS (init) = v; |
| return picflags; |
| } |
| |
| /* Subroutine of process_init_constructor, which will process a single |
| initializer INIT for a union of type TYPE. Returns the flags (PICFLAG_*) |
| which describe the initializer. */ |
| |
| static int |
| process_init_constructor_union (tree type, tree init, int nested, int flags, |
| tsubst_flags_t complain) |
| { |
| constructor_elt *ce; |
| int len; |
| |
| /* If the initializer was empty, use the union's NSDMI if it has one. |
| Otherwise use default zero initialization. */ |
| if (vec_safe_is_empty (CONSTRUCTOR_ELTS (init))) |
| { |
| for (tree field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) |
| { |
| if (TREE_CODE (field) == FIELD_DECL |
| && DECL_INITIAL (field) != NULL_TREE) |
| { |
| tree val = get_nsdmi (field, /*in_ctor=*/false, complain); |
| if (!CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) |
| && find_placeholders (val)) |
| CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1; |
| CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (init), field, val); |
| break; |
| } |
| } |
| |
| if (vec_safe_is_empty (CONSTRUCTOR_ELTS (init))) |
| return 0; |
| } |
| |
| len = CONSTRUCTOR_ELTS (init)->length (); |
| if (len > 1) |
| { |
| if (!(complain & tf_error)) |
| return PICFLAG_ERRONEOUS; |
| error ("too many initializers for %qT", type); |
| CONSTRUCTOR_ELTS (init)->block_remove (1, len-1); |
| } |
| |
| ce = &(*CONSTRUCTOR_ELTS (init))[0]; |
| |
| /* If this element specifies a field, initialize via that field. */ |
| if (ce->index) |
| { |
| if (TREE_CODE (ce->index) == FIELD_DECL) |
| ; |
| else if (identifier_p (ce->index)) |
| { |
| /* This can happen within a cast, see g++.dg/opt/cse2.C. */ |
| tree name = ce->index; |
| tree field; |
| for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) |
| if (DECL_NAME (field) == name) |
| break; |
| if (!field) |
| { |
| if (complain & tf_error) |
| error ("no field %qD found in union being initialized", |
| field); |
| ce->value = error_mark_node; |
| } |
| ce->index = field; |
| } |
| else |
| { |
| gcc_assert (TREE_CODE (ce->index) == INTEGER_CST |
| || TREE_CODE (ce->index) == RANGE_EXPR); |
| if (complain & tf_error) |
| error ("index value instead of field name in union initializer"); |
| ce->value = error_mark_node; |
| } |
| } |
| else |
| { |
| /* Find the first named field. ANSI decided in September 1990 |
| that only named fields count here. */ |
| tree field = TYPE_FIELDS (type); |
| while (field && (!DECL_NAME (field) || TREE_CODE (field) != FIELD_DECL)) |
| field = TREE_CHAIN (field); |
| if (field == NULL_TREE) |
| { |
| if (complain & tf_error) |
| error ("too many initializers for %qT", type); |
| ce->value = error_mark_node; |
| } |
| ce->index = field; |
| } |
| |
| if (ce->value && ce->value != error_mark_node) |
| ce->value = massage_init_elt (TREE_TYPE (ce->index), ce->value, nested, |
| flags, complain); |
| |
| /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer CONSTRUCTOR. */ |
| if (ce->value |
| && TREE_CODE (ce->value) == CONSTRUCTOR |
| && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value)) |
| { |
| CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1; |
| CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value) = 0; |
| } |
| return picflag_from_initializer (ce->value); |
| } |
| |
| /* Process INIT, a constructor for a variable of aggregate type TYPE. The |
| constructor is a brace-enclosed initializer, and will be modified in-place. |
| |
| Each element is converted to the right type through digest_init, and |
| missing initializers are added following the language rules (zero-padding, |
| etc.). |
| |
| After the execution, the initializer will have TREE_CONSTANT if all elts are |
| constant, and TREE_STATIC set if, in addition, all elts are simple enough |
| constants that the assembler and linker can compute them. |
| |
| The function returns the initializer itself, or error_mark_node in case |
| of error. */ |
| |
| static tree |
| process_init_constructor (tree type, tree init, int nested, int flags, |
| tsubst_flags_t complain) |
| { |
| int picflags; |
| |
| gcc_assert (BRACE_ENCLOSED_INITIALIZER_P (init)); |
| |
| if (TREE_CODE (type) == ARRAY_TYPE || VECTOR_TYPE_P (type)) |
| picflags = process_init_constructor_array (type, init, nested, flags, |
| complain); |
| else if (TREE_CODE (type) == RECORD_TYPE) |
| picflags = process_init_constructor_record (type, init, nested, flags, |
| complain); |
| else if (TREE_CODE (type) == UNION_TYPE) |
| picflags = process_init_constructor_union (type, init, nested, flags, |
| complain); |
| else |
| gcc_unreachable (); |
| |
| if (picflags & PICFLAG_ERRONEOUS) |
| return error_mark_node; |
| |
| TREE_TYPE (init) = type; |
| if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == NULL_TREE) |
| cp_complete_array_type (&TREE_TYPE (init), init, /*do_default=*/0); |
| if (picflags & PICFLAG_SIDE_EFFECTS) |
| { |
| TREE_CONSTANT (init) = false; |
| TREE_SIDE_EFFECTS (init) = true; |
| } |
| else if (picflags & PICFLAG_NOT_ALL_CONSTANT) |
| { |
| /* Make sure TREE_CONSTANT isn't set from build_constructor. */ |
| TREE_CONSTANT (init) = false; |
| TREE_SIDE_EFFECTS (init) = false; |
| } |
| else |
| { |
| TREE_CONSTANT (init) = 1; |
| TREE_SIDE_EFFECTS (init) = false; |
| if (!(picflags & PICFLAG_NOT_ALL_SIMPLE)) |
| TREE_STATIC (init) = 1; |
| } |
| if (picflags & PICFLAG_VEC_INIT) |
| { |
| /* Defer default-initialization of array elements with no corresponding |
| initializer-clause until later so we can use a loop. */ |
| TREE_TYPE (init) = init_list_type_node; |
| init = build_vec_init_expr (type, init, complain); |
| init = get_target_expr (init); |
| } |
| return init; |
| } |
| |
| /* Given a structure or union value DATUM, construct and return |
| the structure or union component which results from narrowing |
| that value to the base specified in BASETYPE. For example, given the |
| hierarchy |
| |
| class L { int ii; }; |
| class A : L { ... }; |
| class B : L { ... }; |
| class C : A, B { ... }; |
| |
| and the declaration |
| |
| C x; |
| |
| then the expression |
| |
| x.A::ii refers to the ii member of the L part of |
| the A part of the C object named by X. In this case, |
| DATUM would be x, and BASETYPE would be A. |
| |
| I used to think that this was nonconformant, that the standard specified |
| that first we look up ii in A, then convert x to an L& and pull out the |
| ii part. But in fact, it does say that we convert x to an A&; A here |
| is known as the "naming class". (jason 2000-12-19) |
| |
| BINFO_P points to a variable initialized either to NULL_TREE or to the |
| binfo for the specific base subobject we want to convert to. */ |
| |
| tree |
| build_scoped_ref (tree datum, tree basetype, tree* binfo_p) |
| { |
| tree binfo; |
| |
| if (datum == error_mark_node) |
| return error_mark_node; |
| if (*binfo_p) |
| binfo = *binfo_p; |
| else |
| binfo = lookup_base (TREE_TYPE (datum), basetype, ba_check, |
| NULL, tf_warning_or_error); |
| |
| if (!binfo || binfo == error_mark_node) |
| { |
| *binfo_p = NULL_TREE; |
| if (!binfo) |
| error_not_base_type (basetype, TREE_TYPE (datum)); |
| return error_mark_node; |
| } |
| |
| *binfo_p = binfo; |
| return build_base_path (PLUS_EXPR, datum, binfo, 1, |
| tf_warning_or_error); |
| } |
| |
| /* Build a reference to an object specified by the C++ `->' operator. |
| Usually this just involves dereferencing the object, but if the |
| `->' operator is overloaded, then such overloads must be |
| performed until an object which does not have the `->' operator |
| overloaded is found. An error is reported when circular pointer |
| delegation is detected. */ |
| |
| tree |
| build_x_arrow (location_t loc, tree expr, tsubst_flags_t complain) |
| { |
| tree orig_expr = expr; |
| tree type = TREE_TYPE (expr); |
| tree last_rval = NULL_TREE; |
| vec<tree, va_gc> *types_memoized = NULL; |
| |
| if (type == error_mark_node) |
| return error_mark_node; |
| |
| if (processing_template_decl) |
| { |
| tree ttype = NULL_TREE; |
| if (type && TYPE_PTR_P (type)) |
| ttype = TREE_TYPE (type); |
| if (ttype && !dependent_scope_p (ttype)) |
| /* Pointer to current instantiation, don't treat as dependent. */; |
| else if (type_dependent_expression_p (expr)) |
| { |
| expr = build_min_nt_loc (loc, ARROW_EXPR, expr); |
| TREE_TYPE (expr) = ttype; |
| return expr; |
| } |
| expr = build_non_dependent_expr (expr); |
| } |
| |
| if (MAYBE_CLASS_TYPE_P (type)) |
| { |
| struct tinst_level *actual_inst = current_instantiation (); |
| tree fn = NULL; |
| |
| while ((expr = build_new_op (loc, COMPONENT_REF, |
| LOOKUP_NORMAL, expr, NULL_TREE, NULL_TREE, |
| NULL_TREE, &fn, complain))) |
| { |
| if (expr == error_mark_node) |
| return error_mark_node; |
| |
| /* This provides a better instantiation backtrace in case of |
| error. */ |
| if (fn && DECL_USE_TEMPLATE (fn)) |
| push_tinst_level_loc (fn, |
| (current_instantiation () != actual_inst) |
| ? DECL_SOURCE_LOCATION (fn) |
| : input_location); |
| fn = NULL; |
| |
| if (vec_member (TREE_TYPE (expr), types_memoized)) |
| { |
| if (complain & tf_error) |
| error ("circular pointer delegation detected"); |
| return error_mark_node; |
| } |
| |
| vec_safe_push (types_memoized, TREE_TYPE (expr)); |
| last_rval = expr; |
| } |
| |
| while (current_instantiation () != actual_inst) |
| pop_tinst_level (); |
| |
| if (last_rval == NULL_TREE) |
| { |
| if (complain & tf_error) |
| error ("base operand of %<->%> has non-pointer type %qT", type); |
| return error_mark_node; |
| } |
| |
| if (TYPE_REF_P (TREE_TYPE (last_rval))) |
| last_rval = convert_from_reference (last_rval); |
| } |
| else |
| { |
| last_rval = decay_conversion (expr, complain); |
| if (last_rval == error_mark_node) |
| return error_mark_node; |
| } |
| |
| if (TYPE_PTR_P (TREE_TYPE (last_rval))) |
| { |
| if (processing_template_decl) |
| { |
| expr = build_min (ARROW_EXPR, TREE_TYPE (TREE_TYPE (last_rval)), |
| orig_expr); |
| TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (last_rval); |
| return expr; |
| } |
| |
| return cp_build_indirect_ref (loc, last_rval, RO_ARROW, complain); |
| } |
| |
| if (complain & tf_error) |
| { |
| if (types_memoized) |
| error ("result of %<operator->()%> yields non-pointer result"); |
| else |
| error ("base operand of %<->%> is not a pointer"); |
| } |
| return error_mark_node; |
| } |
| |
| /* Return an expression for "DATUM .* COMPONENT". DATUM has not |
| already been checked out to be of aggregate type. */ |
| |
| tree |
| build_m_component_ref (tree datum, tree component, tsubst_flags_t complain) |
| { |
| tree ptrmem_type; |
| tree objtype; |
| tree type; |
| tree binfo; |
| tree ctype; |
| |
| datum = mark_lvalue_use (datum); |
| component = mark_rvalue_use (component); |
| |
| if (error_operand_p (datum) || error_operand_p (component)) |
| return error_mark_node; |
| |
| ptrmem_type = TREE_TYPE (component); |
| if (!TYPE_PTRMEM_P (ptrmem_type)) |
| { |
| if (complain & tf_error) |
| error ("%qE cannot be used as a member pointer, since it is of " |
| "type %qT", component, ptrmem_type); |
| return error_mark_node; |
| } |
| |
| objtype = TYPE_MAIN_VARIANT (TREE_TYPE (datum)); |
| if (! MAYBE_CLASS_TYPE_P (objtype)) |
| { |
| if (complain & tf_error) |
| error ("cannot apply member pointer %qE to %qE, which is of " |
| "non-class type %qT", component, datum, objtype); |
| return error_mark_node; |
| } |
| |
| type = TYPE_PTRMEM_POINTED_TO_TYPE (ptrmem_type); |
| ctype = complete_type (TYPE_PTRMEM_CLASS_TYPE (ptrmem_type)); |
| |
| if (!COMPLETE_TYPE_P (ctype)) |
| { |
| if (!same_type_p (ctype, objtype)) |
| goto mismatch; |
| binfo = NULL; |
| } |
| else |
| { |
| binfo = lookup_base (objtype, ctype, ba_check, NULL, complain); |
| |
| if (!binfo) |
| { |
| mismatch: |
| if (complain & tf_error) |
| error ("pointer to member type %qT incompatible with object " |
| "type %qT", type, objtype); |
| return error_mark_node; |
| } |
| else if (binfo == error_mark_node) |
| return error_mark_node; |
| } |
| |
| if (TYPE_PTRDATAMEM_P (ptrmem_type)) |
| { |
| bool is_lval = real_lvalue_p (datum); |
| tree ptype; |
| |
| /* Compute the type of the field, as described in [expr.ref]. |
| There's no such thing as a mutable pointer-to-member, so |
| things are not as complex as they are for references to |
| non-static data members. */ |
| type = cp_build_qualified_type (type, |
| (cp_type_quals (type) |
| | cp_type_quals (TREE_TYPE (datum)))); |
| |
| datum = build_address (datum); |
| |
| /* Convert object to the correct base. */ |
| if (binfo) |
| { |
| datum = build_base_path (PLUS_EXPR, datum, binfo, 1, complain); |
| if (datum == error_mark_node) |
| return error_mark_node; |
| } |
| |
| /* Build an expression for "object + offset" where offset is the |
| value stored in the pointer-to-data-member. */ |
| ptype = build_pointer_type (type); |
| datum = fold_build_pointer_plus (fold_convert (ptype, datum), component); |
| datum = cp_build_fold_indirect_ref (datum); |
| if (datum == error_mark_node) |
| return error_mark_node; |
| |
| /* If the object expression was an rvalue, return an rvalue. */ |
| if (!is_lval) |
| datum = move (datum); |
| return datum; |
| } |
| else |
| { |
| /* 5.5/6: In a .* expression whose object expression is an rvalue, the |
| program is ill-formed if the second operand is a pointer to member |
| function with ref-qualifier & (for C++20: unless its cv-qualifier-seq |
| is const). In a .* expression whose object expression is an lvalue, |
| the program is ill-formed if the second operand is a pointer to member |
| function with ref-qualifier &&. */ |
| if (FUNCTION_REF_QUALIFIED (type)) |
| { |
| bool lval = lvalue_p (datum); |
| if (lval && FUNCTION_RVALUE_QUALIFIED (type)) |
| { |
| if (complain & tf_error) |
| error ("pointer-to-member-function type %qT requires an rvalue", |
| ptrmem_type); |
| return error_mark_node; |
| } |
| else if (!lval && !FUNCTION_RVALUE_QUALIFIED (type)) |
| { |
| if ((type_memfn_quals (type) |
| & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)) |
| != TYPE_QUAL_CONST) |
| { |
| if (complain & tf_error) |
| error ("pointer-to-member-function type %qT requires " |
| "an lvalue", ptrmem_type); |
| return error_mark_node; |
| } |
| else if (cxx_dialect < cxx20) |
| { |
| if (complain & tf_warning_or_error) |
| pedwarn (input_location, OPT_Wpedantic, |
| "pointer-to-member-function type %qT requires " |
| "an lvalue before C++20", ptrmem_type); |
| else |
| return error_mark_node; |
| } |
| } |
| } |
| return build2 (OFFSET_REF, type, datum, component); |
| } |
| } |
| |
| /* Return a tree node for the expression TYPENAME '(' PARMS ')'. */ |
| |
| static tree |
| build_functional_cast_1 (location_t loc, tree exp, tree parms, |
| tsubst_flags_t complain) |
| { |
| /* This is either a call to a constructor, |
| or a C cast in C++'s `functional' notation. */ |
| |
| /* The type to which we are casting. */ |
| tree type; |
| |
| if (error_operand_p (exp) || parms == error_mark_node) |
| return error_mark_node; |
| |
| if (TREE_CODE (exp) == TYPE_DECL) |
| { |
| type = TREE_TYPE (exp); |
| |
| if (DECL_ARTIFICIAL (exp)) |
| cp_handle_deprecated_or_unavailable (type); |
| } |
| else |
| type = exp; |
| |
| /* We need to check this explicitly, since value-initialization of |
| arrays is allowed in other situations. */ |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| if (complain & tf_error) |
| error_at (loc, "functional cast to array type %qT", type); |
| return error_mark_node; |
| } |
| |
| if (tree anode = type_uses_auto (type)) |
| { |
| tree init; |
| if (CLASS_PLACEHOLDER_TEMPLATE (anode)) |
| init = parms; |
| /* C++23 auto(x). */ |
| else if (!AUTO_IS_DECLTYPE (anode) |
| && list_length (parms) == 1) |
| { |
| init = TREE_VALUE (parms); |
| if (is_constrained_auto (anode)) |
| { |
| if (complain & tf_error) |
| error_at (loc, "%<auto(x)%> cannot be constrained"); |
| return error_mark_node; |
| } |
| else if (cxx_dialect < cxx23) |
| pedwarn (loc, OPT_Wc__23_extensions, |
| "%<auto(x)%> only available with " |
| "%<-std=c++2b%> or %<-std=gnu++2b%>"); |
| } |
| else |
| { |
| if (complain & tf_error) |
| error_at (loc, "invalid use of %qT", anode); |
| return error_mark_node; |
| } |
| type = do_auto_deduction (type, init, anode, complain, |
| adc_variable_type); |
| if (type == error_mark_node) |
| return error_mark_node; |
| } |
| |
| if (processing_template_decl) |
| { |
| tree t; |
| |
| /* Diagnose this even in a template. We could also try harder |
| to give all the usual errors when the type and args are |
| non-dependent... */ |
| if (TYPE_REF_P (type) && !parms) |
| { |
| if (complain & tf_error) |
| error_at (loc, "invalid value-initialization of reference type"); |
| return error_mark_node; |
| } |
| |
| t = build_min (CAST_EXPR, type, parms); |
| /* We don't know if it will or will not have side effects. */ |
| TREE_SIDE_EFFECTS (t) = 1; |
| return t; |
| } |
| |
| if (! MAYBE_CLASS_TYPE_P (type)) |
| { |
| if (parms == NULL_TREE) |
| { |
| if (VOID_TYPE_P (type)) |
| return void_node; |
| return build_value_init (cv_unqualified (type), complain); |
| } |
| |
| /* This must build a C cast. */ |
| parms = build_x_compound_expr_from_list (parms, ELK_FUNC_CAST, complain); |
| return cp_build_c_cast (loc, type, parms, complain); |
| } |
| |
| /* Prepare to evaluate as a call to a constructor. If this expression |
| is actually used, for example, |
| |
| return X (arg1, arg2, ...); |
| |
| then the slot being initialized will be filled in. */ |
| |
| if (!complete_type_or_maybe_complain (type, NULL_TREE, complain)) |
| return error_mark_node; |
| if (abstract_virtuals_error_sfinae (ACU_CAST, type, complain)) |
| return error_mark_node; |
| |
| /* [expr.type.conv] |
| |
| If the expression list is a single-expression, the type |
| conversion is equivalent (in definedness, and if defined in |
| meaning) to the corresponding cast expression. */ |
| if (parms && TREE_CHAIN (parms) == NULL_TREE) |
| return cp_build_c_cast (loc, type, TREE_VALUE (parms), complain); |
| |
| /* [expr.type.conv] |
| |
| The expression T(), where T is a simple-type-specifier for a |
| non-array complete object type or the (possibly cv-qualified) |
| void type, creates an rvalue of the specified type, which is |
| value-initialized. */ |
| |
| if (parms == NULL_TREE) |
| { |
| exp = build_value_init (type, complain); |
| exp = get_target_expr_sfinae (exp, complain); |
| return exp; |
| } |
| |
| /* Call the constructor. */ |
| releasing_vec parmvec; |
| for (; parms != NULL_TREE; parms = TREE_CHAIN (parms)) |
| vec_safe_push (parmvec, TREE_VALUE (parms)); |
| exp = build_special_member_call (NULL_TREE, complete_ctor_identifier, |
| &parmvec, type, LOOKUP_NORMAL, complain); |
| |
| if (exp == error_mark_node) |
| return error_mark_node; |
| |
| return build_cplus_new (type, exp, complain); |
| } |
| |
| tree |
| build_functional_cast (location_t loc, tree exp, tree parms, |
| tsubst_flags_t complain) |
| { |
| tree result = build_functional_cast_1 (loc, exp, parms, complain); |
| protected_set_expr_location (result, loc); |
| return result; |
| } |
| |
| |
| /* Add new exception specifier SPEC, to the LIST we currently have. |
| If it's already in LIST then do nothing. |
| Moan if it's bad and we're allowed to. COMPLAIN < 0 means we |
| know what we're doing. */ |
| |
| tree |
| add_exception_specifier (tree list, tree spec, tsubst_flags_t complain) |
| { |
| bool ok; |
| tree core = spec; |
| bool is_ptr; |
| diagnostic_t diag_type = DK_UNSPECIFIED; /* none */ |
| |
| if (spec == error_mark_node) |
| return list; |
| |
| gcc_assert (spec && (!list || TREE_VALUE (list))); |
| |
| /* [except.spec] 1, type in an exception specifier shall not be |
| incomplete, or pointer or ref to incomplete other than pointer |
| to cv void. */ |
| is_ptr = TYPE_PTR_P (core); |
| if (is_ptr || TYPE_REF_P (core)) |
| core = TREE_TYPE (core); |
| if (complain < 0) |
| ok = true; |
| else if (VOID_TYPE_P (core)) |
| ok = is_ptr; |
| else if (TREE_CODE (core) == TEMPLATE_TYPE_PARM) |
| ok = true; |
| else if (processing_template_decl) |
| ok = true; |
| else if (!verify_type_context (input_location, TCTX_EXCEPTIONS, core, |
| !(complain & tf_error))) |
| return error_mark_node; |
| else |
| { |
| ok = true; |
| /* 15.4/1 says that types in an exception specifier must be complete, |
| but it seems more reasonable to only require this on definitions |
| and calls. So just give a pedwarn at this point; we will give an |
| error later if we hit one of those two cases. */ |
| if (!COMPLETE_TYPE_P (complete_type (core))) |
| diag_type = DK_PEDWARN; /* pedwarn */ |
| } |
| |
| if (ok) |
| { |
| tree probe; |
| |
| for (probe = list; probe; probe = TREE_CHAIN (probe)) |
| if (same_type_p (TREE_VALUE (probe), spec)) |
| break; |
| if (!probe) |
| list = tree_cons (NULL_TREE, spec, list); |
| } |
| else |
| diag_type = DK_ERROR; /* error */ |
| |
| if (diag_type != DK_UNSPECIFIED |
| && (complain & tf_warning_or_error)) |
| cxx_incomplete_type_diagnostic (NULL_TREE, core, diag_type); |
| |
| return list; |
| } |
| |
| /* Like nothrow_spec_p, but don't abort on deferred noexcept. */ |
| |
| static bool |
| nothrow_spec_p_uninst (const_tree spec) |
| { |
| if (DEFERRED_NOEXCEPT_SPEC_P (spec)) |
| return false; |
| return nothrow_spec_p (spec); |
| } |
| |
| /* Combine the two exceptions specifier lists LIST and ADD, and return |
| their union. */ |
| |
| tree |
| merge_exception_specifiers (tree list, tree add) |
| { |
| tree noex, orig_list; |
| |
| if (list == error_mark_node || add == error_mark_node) |
| return error_mark_node; |
| |
| /* No exception-specifier or noexcept(false) are less strict than |
| anything else. Prefer the newer variant (LIST). */ |
| if (!list || list == noexcept_false_spec) |
| return list; |
| else if (!add || add == noexcept_false_spec) |
| return add; |
| |
| /* noexcept(true) and throw() are stricter than anything else. |
| As above, prefer the more recent one (LIST). */ |
| if (nothrow_spec_p_uninst (add)) |
| return list; |
| |
| /* Two implicit noexcept specs (e.g. on a destructor) are equivalent. */ |
| if (UNEVALUATED_NOEXCEPT_SPEC_P (add) |
| && UNEVALUATED_NOEXCEPT_SPEC_P (list)) |
| return list; |
| /* We should have instantiated other deferred noexcept specs by now. */ |
| gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (add)); |
| |
| if (nothrow_spec_p_uninst (list)) |
| return add; |
| noex = TREE_PURPOSE (list); |
| gcc_checking_assert (!TREE_PURPOSE (add) |
| || errorcount || !flag_exceptions |
| || cp_tree_equal (noex, TREE_PURPOSE (add))); |
| |
| /* Combine the dynamic-exception-specifiers, if any. */ |
| orig_list = list; |
| for (; add && TREE_VALUE (add); add = TREE_CHAIN (add)) |
| { |
| tree spec = TREE_VALUE (add); |
| tree probe; |
| |
| for (probe = orig_list; probe && TREE_VALUE (probe); |
| probe = TREE_CHAIN (probe)) |
| if (same_type_p (TREE_VALUE (probe), spec)) |
| break; |
| if (!probe) |
| { |
| spec = build_tree_list (NULL_TREE, spec); |
| TREE_CHAIN (spec) = list; |
| list = spec; |
| } |
| } |
| |
| /* Keep the noexcept-specifier at the beginning of the list. */ |
| if (noex != TREE_PURPOSE (list)) |
| list = tree_cons (noex, TREE_VALUE (list), TREE_CHAIN (list)); |
| |
| return list; |
| } |
| |
| /* Subroutine of build_call. Ensure that each of the types in the |
| exception specification is complete. Technically, 15.4/1 says that |
| they need to be complete when we see a declaration of the function, |
| but we should be able to get away with only requiring this when the |
| function is defined or called. See also add_exception_specifier. */ |
| |
| void |
| require_complete_eh_spec_types (tree fntype, tree decl) |
| { |
| tree raises; |
| /* Don't complain about calls to op new. */ |
| if (decl && DECL_ARTIFICIAL (decl)) |
| return; |
| for (raises = TYPE_RAISES_EXCEPTIONS (fntype); raises; |
| raises = TREE_CHAIN (raises)) |
| { |
| tree type = TREE_VALUE (raises); |
| if (type && !COMPLETE_TYPE_P (type)) |
| { |
| if (decl) |
| error |
| ("call to function %qD which throws incomplete type %q#T", |
| decl, type); |
| else |
| error ("call to function which throws incomplete type %q#T", |
| decl); |
| } |
| } |
| } |