/* Perform the semantic phase of constexpr parsing, i.e., the process of building tree structure, checking semantic consistency, and building RTL. These routines are used both during actual parsing and during the instantiation of template functions. Copyright (C) 1998-2014 Free Software Foundation, Inc. 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 . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "tree.h" #include "varasm.h" #include "cp-tree.h" #include "c-family/c-objc.h" #include "tree-iterator.h" #include "gimplify.h" #include "builtins.h" #include "tree-inline.h" static bool verify_constant (tree, bool, bool *, bool *); #define VERIFY_CONSTANT(X) \ do { \ if (verify_constant ((X), ctx->quiet, non_constant_p, overflow_p)) \ return t; \ } while (0) /* Returns true iff FUN is an instantiation of a constexpr function template or a defaulted constexpr function. */ bool is_instantiation_of_constexpr (tree fun) { return ((DECL_TEMPLOID_INSTANTIATION (fun) && DECL_DECLARED_CONSTEXPR_P (DECL_TI_TEMPLATE (fun))) || (DECL_DEFAULTED_FN (fun) && DECL_DECLARED_CONSTEXPR_P (fun))); } /* Return true if T is a literal type. */ bool literal_type_p (tree t) { if (SCALAR_TYPE_P (t) || TREE_CODE (t) == VECTOR_TYPE || TREE_CODE (t) == REFERENCE_TYPE) return true; if (CLASS_TYPE_P (t)) { t = complete_type (t); gcc_assert (COMPLETE_TYPE_P (t) || errorcount); return CLASSTYPE_LITERAL_P (t); } if (TREE_CODE (t) == ARRAY_TYPE) return literal_type_p (strip_array_types (t)); return false; } /* If DECL is a variable declared `constexpr', require its type be literal. Return the DECL if OK, otherwise NULL. */ tree ensure_literal_type_for_constexpr_object (tree decl) { tree type = TREE_TYPE (decl); if (VAR_P (decl) && (DECL_DECLARED_CONSTEXPR_P (decl) || var_in_constexpr_fn (decl)) && !processing_template_decl) { tree stype = strip_array_types (type); if (CLASS_TYPE_P (stype) && !COMPLETE_TYPE_P (complete_type (stype))) /* Don't complain here, we'll complain about incompleteness when we try to initialize the variable. */; else if (!literal_type_p (type)) { if (DECL_DECLARED_CONSTEXPR_P (decl)) error ("the type %qT of constexpr variable %qD is not literal", type, decl); else { error ("variable %qD of non-literal type %qT in % " "function", decl, type); cp_function_chain->invalid_constexpr = true; } explain_non_literal_class (type); return NULL; } } return decl; } /* Representation of entries in the constexpr function definition table. */ struct GTY((for_user)) constexpr_fundef { tree decl; tree body; }; struct constexpr_fundef_hasher : ggc_hasher { static hashval_t hash (constexpr_fundef *); static bool equal (constexpr_fundef *, constexpr_fundef *); }; /* This table holds all constexpr function definitions seen in the current translation unit. */ static GTY (()) hash_table *constexpr_fundef_table; /* Utility function used for managing the constexpr function table. Return true if the entries pointed to by P and Q are for the same constexpr function. */ inline bool constexpr_fundef_hasher::equal (constexpr_fundef *lhs, constexpr_fundef *rhs) { return lhs->decl == rhs->decl; } /* Utility function used for managing the constexpr function table. Return a hash value for the entry pointed to by Q. */ inline hashval_t constexpr_fundef_hasher::hash (constexpr_fundef *fundef) { return DECL_UID (fundef->decl); } /* Return a previously saved definition of function FUN. */ static constexpr_fundef * retrieve_constexpr_fundef (tree fun) { constexpr_fundef fundef = { NULL, NULL }; if (constexpr_fundef_table == NULL) return NULL; fundef.decl = fun; return constexpr_fundef_table->find (&fundef); } /* Check whether the parameter and return types of FUN are valid for a constexpr function, and complain if COMPLAIN. */ static bool is_valid_constexpr_fn (tree fun, bool complain) { bool ret = true; if (DECL_INHERITED_CTOR_BASE (fun) && TREE_CODE (fun) == TEMPLATE_DECL) { ret = false; if (complain) error ("inherited constructor %qD is not constexpr", get_inherited_ctor (fun)); } else { for (tree parm = FUNCTION_FIRST_USER_PARM (fun); parm != NULL_TREE; parm = TREE_CHAIN (parm)) if (!literal_type_p (TREE_TYPE (parm))) { ret = false; if (complain) { error ("invalid type for parameter %d of constexpr " "function %q+#D", DECL_PARM_INDEX (parm), fun); explain_non_literal_class (TREE_TYPE (parm)); } } } if (!DECL_CONSTRUCTOR_P (fun)) { tree rettype = TREE_TYPE (TREE_TYPE (fun)); if (!literal_type_p (rettype)) { ret = false; if (complain) { error ("invalid return type %qT of constexpr function %q+D", rettype, fun); explain_non_literal_class (rettype); } } if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun) && !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun))) { ret = false; if (complain) { error ("enclosing class of constexpr non-static member " "function %q+#D is not a literal type", fun); explain_non_literal_class (DECL_CONTEXT (fun)); } } } else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun))) { ret = false; if (complain) error ("%q#T has virtual base classes", DECL_CONTEXT (fun)); } return ret; } /* Subroutine of build_data_member_initialization. MEMBER is a COMPONENT_REF for a member of an anonymous aggregate, INIT is the initializer for that member, and VEC_OUTER is the vector of constructor elements for the class whose constructor we are processing. Add the initializer to the vector and return true to indicate success. */ static bool build_anon_member_initialization (tree member, tree init, vec **vec_outer) { /* MEMBER presents the relevant fields from the inside out, but we need to build up the initializer from the outside in so that we can reuse previously built CONSTRUCTORs if this is, say, the second field in an anonymous struct. So we use a vec as a stack. */ auto_vec fields; do { fields.safe_push (TREE_OPERAND (member, 1)); member = TREE_OPERAND (member, 0); } while (ANON_AGGR_TYPE_P (TREE_TYPE (member)) && TREE_CODE (member) == COMPONENT_REF); /* VEC has the constructor elements vector for the context of FIELD. If FIELD is an anonymous aggregate, we will push inside it. */ vec **vec = vec_outer; tree field; while (field = fields.pop(), ANON_AGGR_TYPE_P (TREE_TYPE (field))) { tree ctor; /* If there is already an outer constructor entry for the anonymous aggregate FIELD, use it; otherwise, insert one. */ if (vec_safe_is_empty (*vec) || (*vec)->last().index != field) { ctor = build_constructor (TREE_TYPE (field), NULL); CONSTRUCTOR_APPEND_ELT (*vec, field, ctor); } else ctor = (*vec)->last().value; vec = &CONSTRUCTOR_ELTS (ctor); } /* Now we're at the innermost field, the one that isn't an anonymous aggregate. Add its initializer to the CONSTRUCTOR and we're done. */ gcc_assert (fields.is_empty()); CONSTRUCTOR_APPEND_ELT (*vec, field, init); return true; } /* Subroutine of build_constexpr_constructor_member_initializers. The expression tree T represents a data member initialization in a (constexpr) constructor definition. Build a pairing of the data member with its initializer, and prepend that pair to the existing initialization pair INITS. */ static bool build_data_member_initialization (tree t, vec **vec) { tree member, init; if (TREE_CODE (t) == CLEANUP_POINT_EXPR) t = TREE_OPERAND (t, 0); if (TREE_CODE (t) == EXPR_STMT) t = TREE_OPERAND (t, 0); if (t == error_mark_node) return false; if (TREE_CODE (t) == STATEMENT_LIST) { tree_stmt_iterator i; for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) { if (! build_data_member_initialization (tsi_stmt (i), vec)) return false; } return true; } if (TREE_CODE (t) == CLEANUP_STMT) { /* We can't see a CLEANUP_STMT in a constructor for a literal class, but we can in a constexpr constructor for a non-literal class. Just ignore it; either all the initialization will be constant, in which case the cleanup can't run, or it can't be constexpr. Still recurse into CLEANUP_BODY. */ return build_data_member_initialization (CLEANUP_BODY (t), vec); } if (TREE_CODE (t) == CONVERT_EXPR) t = TREE_OPERAND (t, 0); if (TREE_CODE (t) == INIT_EXPR /* vptr initialization shows up as a MODIFY_EXPR. In C++14 we only use what this function builds for cx_check_missing_mem_inits, and assignment in the ctor body doesn't count. */ || (cxx_dialect < cxx14 && TREE_CODE (t) == MODIFY_EXPR)) { member = TREE_OPERAND (t, 0); init = break_out_target_exprs (TREE_OPERAND (t, 1)); } else if (TREE_CODE (t) == CALL_EXPR) { tree fn = get_callee_fndecl (t); if (!fn || !DECL_CONSTRUCTOR_P (fn)) /* We're only interested in calls to subobject constructors. */ return true; member = CALL_EXPR_ARG (t, 0); /* We don't use build_cplus_new here because it complains about abstract bases. Leaving the call unwrapped means that it has the wrong type, but cxx_eval_constant_expression doesn't care. */ init = break_out_target_exprs (t); } else if (TREE_CODE (t) == BIND_EXPR) return build_data_member_initialization (BIND_EXPR_BODY (t), vec); else /* Don't add anything else to the CONSTRUCTOR. */ return true; if (INDIRECT_REF_P (member)) member = TREE_OPERAND (member, 0); if (TREE_CODE (member) == NOP_EXPR) { tree op = member; STRIP_NOPS (op); if (TREE_CODE (op) == ADDR_EXPR) { gcc_assert (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (TREE_TYPE (op)), TREE_TYPE (TREE_TYPE (member)))); /* Initializing a cv-qualified member; we need to look through the const_cast. */ member = op; } else if (op == current_class_ptr && (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (TREE_TYPE (member)), current_class_type))) /* Delegating constructor. */ member = op; else { /* This is an initializer for an empty base; keep it for now so we can check it in cxx_eval_bare_aggregate. */ gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (member)))); } } if (TREE_CODE (member) == ADDR_EXPR) member = TREE_OPERAND (member, 0); if (TREE_CODE (member) == COMPONENT_REF) { tree aggr = TREE_OPERAND (member, 0); if (TREE_CODE (aggr) != COMPONENT_REF) /* Normal member initialization. */ member = TREE_OPERAND (member, 1); else if (ANON_AGGR_TYPE_P (TREE_TYPE (aggr))) /* Initializing a member of an anonymous union. */ return build_anon_member_initialization (member, init, vec); else /* We're initializing a vtable pointer in a base. Leave it as COMPONENT_REF so we remember the path to get to the vfield. */ gcc_assert (TREE_TYPE (member) == vtbl_ptr_type_node); } CONSTRUCTOR_APPEND_ELT (*vec, member, init); return true; } /* Subroutine of check_constexpr_ctor_body_1 and constexpr_fn_retval. In C++11 mode checks that the TYPE_DECLs in the BIND_EXPR_VARS of a BIND_EXPR conform to 7.1.5/3/4 on typedef and alias declarations. */ static bool check_constexpr_bind_expr_vars (tree t) { gcc_assert (TREE_CODE (t) == BIND_EXPR); for (tree var = BIND_EXPR_VARS (t); var; var = DECL_CHAIN (var)) if (TREE_CODE (var) == TYPE_DECL && DECL_IMPLICIT_TYPEDEF_P (var)) return false; return true; } /* Subroutine of check_constexpr_ctor_body. */ static bool check_constexpr_ctor_body_1 (tree last, tree list) { switch (TREE_CODE (list)) { case DECL_EXPR: if (TREE_CODE (DECL_EXPR_DECL (list)) == USING_DECL) return true; return false; case CLEANUP_POINT_EXPR: return check_constexpr_ctor_body (last, TREE_OPERAND (list, 0), /*complain=*/false); case BIND_EXPR: if (!check_constexpr_bind_expr_vars (list) || !check_constexpr_ctor_body (last, BIND_EXPR_BODY (list), /*complain=*/false)) return false; return true; case USING_STMT: case STATIC_ASSERT: return true; default: return false; } } /* Make sure that there are no statements after LAST in the constructor body represented by LIST. */ bool check_constexpr_ctor_body (tree last, tree list, bool complain) { /* C++14 doesn't require a constexpr ctor to have an empty body. */ if (cxx_dialect >= cxx14) return true; bool ok = true; if (TREE_CODE (list) == STATEMENT_LIST) { tree_stmt_iterator i = tsi_last (list); for (; !tsi_end_p (i); tsi_prev (&i)) { tree t = tsi_stmt (i); if (t == last) break; if (!check_constexpr_ctor_body_1 (last, t)) { ok = false; break; } } } else if (list != last && !check_constexpr_ctor_body_1 (last, list)) ok = false; if (!ok) { if (complain) error ("constexpr constructor does not have empty body"); DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false; } return ok; } /* V is a vector of constructor elements built up for the base and member initializers of a constructor for TYPE. They need to be in increasing offset order, which they might not be yet if TYPE has a primary base which is not first in the base-clause or a vptr and at least one base all of which are non-primary. */ static vec * sort_constexpr_mem_initializers (tree type, vec *v) { tree pri = CLASSTYPE_PRIMARY_BINFO (type); tree field_type; unsigned i; constructor_elt *ce; if (pri) field_type = BINFO_TYPE (pri); else if (TYPE_CONTAINS_VPTR_P (type)) field_type = vtbl_ptr_type_node; else return v; /* Find the element for the primary base or vptr and move it to the beginning of the vec. */ for (i = 0; vec_safe_iterate (v, i, &ce); ++i) if (TREE_TYPE (ce->index) == field_type) break; if (i > 0 && i < vec_safe_length (v)) { vec &vref = *v; constructor_elt elt = vref[i]; for (; i > 0; --i) vref[i] = vref[i-1]; vref[0] = elt; } return v; } /* Build compile-time evalable representations of member-initializer list for a constexpr constructor. */ static tree build_constexpr_constructor_member_initializers (tree type, tree body) { vec *vec = NULL; bool ok = true; if (TREE_CODE (body) == MUST_NOT_THROW_EXPR || TREE_CODE (body) == EH_SPEC_BLOCK) body = TREE_OPERAND (body, 0); if (TREE_CODE (body) == STATEMENT_LIST) body = STATEMENT_LIST_HEAD (body)->stmt; body = BIND_EXPR_BODY (body); if (TREE_CODE (body) == CLEANUP_POINT_EXPR) { body = TREE_OPERAND (body, 0); if (TREE_CODE (body) == EXPR_STMT) body = TREE_OPERAND (body, 0); if (TREE_CODE (body) == INIT_EXPR && (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (TREE_OPERAND (body, 0)), current_class_type))) { /* Trivial copy. */ return TREE_OPERAND (body, 1); } ok = build_data_member_initialization (body, &vec); } else if (TREE_CODE (body) == STATEMENT_LIST) { tree_stmt_iterator i; for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i)) { ok = build_data_member_initialization (tsi_stmt (i), &vec); if (!ok) break; } } else if (TREE_CODE (body) == TRY_BLOCK) { error ("body of % constructor cannot be " "a function-try-block"); return error_mark_node; } else if (EXPR_P (body)) ok = build_data_member_initialization (body, &vec); else gcc_assert (errorcount > 0); if (ok) { if (vec_safe_length (vec) > 0) { /* In a delegating constructor, return the target. */ constructor_elt *ce = &(*vec)[0]; if (ce->index == current_class_ptr) { body = ce->value; vec_free (vec); return body; } } vec = sort_constexpr_mem_initializers (type, vec); return build_constructor (type, vec); } else return error_mark_node; } /* Subroutine of register_constexpr_fundef. BODY is the body of a function declared to be constexpr, or a sub-statement thereof. Returns the return value if suitable, error_mark_node for a statement not allowed in a constexpr function, or NULL_TREE if no return value was found. */ static tree constexpr_fn_retval (tree body) { switch (TREE_CODE (body)) { case STATEMENT_LIST: { tree_stmt_iterator i; tree expr = NULL_TREE; for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i)) { tree s = constexpr_fn_retval (tsi_stmt (i)); if (s == error_mark_node) return error_mark_node; else if (s == NULL_TREE) /* Keep iterating. */; else if (expr) /* Multiple return statements. */ return error_mark_node; else expr = s; } return expr; } case RETURN_EXPR: return break_out_target_exprs (TREE_OPERAND (body, 0)); case DECL_EXPR: { tree decl = DECL_EXPR_DECL (body); if (TREE_CODE (decl) == USING_DECL /* Accept __func__, __FUNCTION__, and __PRETTY_FUNCTION__. */ || DECL_ARTIFICIAL (decl)) return NULL_TREE; return error_mark_node; } case CLEANUP_POINT_EXPR: return constexpr_fn_retval (TREE_OPERAND (body, 0)); case BIND_EXPR: if (!check_constexpr_bind_expr_vars (body)) return error_mark_node; return constexpr_fn_retval (BIND_EXPR_BODY (body)); case USING_STMT: return NULL_TREE; default: return error_mark_node; } } /* Subroutine of register_constexpr_fundef. BODY is the DECL_SAVED_TREE of FUN; do the necessary transformations to turn it into a single expression that we can store in the hash table. */ static tree massage_constexpr_body (tree fun, tree body) { if (DECL_CONSTRUCTOR_P (fun)) body = build_constexpr_constructor_member_initializers (DECL_CONTEXT (fun), body); else if (cxx_dialect < cxx14) { if (TREE_CODE (body) == EH_SPEC_BLOCK) body = EH_SPEC_STMTS (body); if (TREE_CODE (body) == MUST_NOT_THROW_EXPR) body = TREE_OPERAND (body, 0); body = constexpr_fn_retval (body); } return body; } /* FUN is a constexpr constructor with massaged body BODY. Return true if some bases/fields are uninitialized, and complain if COMPLAIN. */ static bool cx_check_missing_mem_inits (tree fun, tree body, bool complain) { bool bad; tree field; unsigned i, nelts; tree ctype; if (TREE_CODE (body) != CONSTRUCTOR) return false; nelts = CONSTRUCTOR_NELTS (body); ctype = DECL_CONTEXT (fun); field = TYPE_FIELDS (ctype); if (TREE_CODE (ctype) == UNION_TYPE) { if (nelts == 0 && next_initializable_field (field)) { if (complain) error ("% constructor for union %qT must " "initialize exactly one non-static data member", ctype); return true; } return false; } bad = false; for (i = 0; i <= nelts; ++i) { tree index; if (i == nelts) index = NULL_TREE; else { index = CONSTRUCTOR_ELT (body, i)->index; /* Skip base and vtable inits. */ if (TREE_CODE (index) != FIELD_DECL || DECL_ARTIFICIAL (index)) continue; } for (; field != index; field = DECL_CHAIN (field)) { tree ftype; if (TREE_CODE (field) != FIELD_DECL || (DECL_C_BIT_FIELD (field) && !DECL_NAME (field)) || DECL_ARTIFICIAL (field)) continue; ftype = strip_array_types (TREE_TYPE (field)); if (type_has_constexpr_default_constructor (ftype)) { /* It's OK to skip a member with a trivial constexpr ctor. A constexpr ctor that isn't trivial should have been added in by now. */ gcc_checking_assert (!TYPE_HAS_COMPLEX_DFLT (ftype) || errorcount != 0); continue; } if (!complain) return true; error ("member %qD must be initialized by mem-initializer " "in % constructor", field); inform (DECL_SOURCE_LOCATION (field), "declared here"); bad = true; } if (field == NULL_TREE) break; field = DECL_CHAIN (field); } return bad; } /* We are processing the definition of the constexpr function FUN. Check that its BODY fulfills the propriate requirements and enter it in the constexpr function definition table. For constructor BODY is actually the TREE_LIST of the member-initializer list. */ tree register_constexpr_fundef (tree fun, tree body) { constexpr_fundef entry; constexpr_fundef **slot; if (!is_valid_constexpr_fn (fun, !DECL_GENERATED_P (fun))) return NULL; body = massage_constexpr_body (fun, body); if (body == NULL_TREE || body == error_mark_node) { if (!DECL_CONSTRUCTOR_P (fun)) error ("body of constexpr function %qD not a return-statement", fun); return NULL; } if (!potential_rvalue_constant_expression (body)) { if (!DECL_GENERATED_P (fun)) require_potential_rvalue_constant_expression (body); return NULL; } if (DECL_CONSTRUCTOR_P (fun) && cx_check_missing_mem_inits (fun, body, !DECL_GENERATED_P (fun))) return NULL; /* Create the constexpr function table if necessary. */ if (constexpr_fundef_table == NULL) constexpr_fundef_table = hash_table::create_ggc (101); entry.decl = fun; entry.body = body; slot = constexpr_fundef_table->find_slot (&entry, INSERT); gcc_assert (*slot == NULL); *slot = ggc_alloc (); **slot = entry; return fun; } /* FUN is a non-constexpr function called in a context that requires a constant expression. If it comes from a constexpr template, explain why the instantiation isn't constexpr. */ void explain_invalid_constexpr_fn (tree fun) { static hash_set *diagnosed; tree body; location_t save_loc; /* Only diagnose defaulted functions or instantiations. */ if (!DECL_DEFAULTED_FN (fun) && !is_instantiation_of_constexpr (fun)) return; if (diagnosed == NULL) diagnosed = new hash_set; if (diagnosed->add (fun)) /* Already explained. */ return; save_loc = input_location; input_location = DECL_SOURCE_LOCATION (fun); inform (0, "%q+D is not usable as a constexpr function because:", fun); /* First check the declaration. */ if (is_valid_constexpr_fn (fun, true)) { /* Then if it's OK, the body. */ if (!DECL_DECLARED_CONSTEXPR_P (fun)) explain_implicit_non_constexpr (fun); else { body = massage_constexpr_body (fun, DECL_SAVED_TREE (fun)); require_potential_rvalue_constant_expression (body); if (DECL_CONSTRUCTOR_P (fun)) cx_check_missing_mem_inits (fun, body, true); } } input_location = save_loc; } /* Objects of this type represent calls to constexpr functions along with the bindings of parameters to their arguments, for the purpose of compile time evaluation. */ struct GTY((for_user)) constexpr_call { /* Description of the constexpr function definition. */ constexpr_fundef *fundef; /* Parameter bindings environment. A TREE_LIST where each TREE_PURPOSE is a parameter _DECL and the TREE_VALUE is the value of the parameter. Note: This arrangement is made to accommodate the use of iterative_hash_template_arg (see pt.c). If you change this representation, also change the hash calculation in cxx_eval_call_expression. */ tree bindings; /* Result of the call. NULL means the call is being evaluated. error_mark_node means that the evaluation was erroneous; otherwise, the actuall value of the call. */ tree result; /* The hash of this call; we remember it here to avoid having to recalculate it when expanding the hash table. */ hashval_t hash; }; struct constexpr_call_hasher : ggc_hasher { static hashval_t hash (constexpr_call *); static bool equal (constexpr_call *, constexpr_call *); }; /* The constexpr expansion context. CALL is the current function expansion, CTOR is the current aggregate initializer, OBJECT is the object being initialized by CTOR, either a VAR_DECL or a _REF. VALUES is a map of values of variables initialized within the expression. */ struct constexpr_ctx { constexpr_call *call; hash_map *values; tree ctor; tree object; bool quiet; bool strict; }; /* A table of all constexpr calls that have been evaluated by the compiler in this translation unit. */ static GTY (()) hash_table *constexpr_call_table; static tree cxx_eval_constant_expression (const constexpr_ctx *, tree, bool, bool *, bool *, tree * = NULL); /* Compute a hash value for a constexpr call representation. */ inline hashval_t constexpr_call_hasher::hash (constexpr_call *info) { return info->hash; } /* Return true if the objects pointed to by P and Q represent calls to the same constexpr function with the same arguments. Otherwise, return false. */ bool constexpr_call_hasher::equal (constexpr_call *lhs, constexpr_call *rhs) { tree lhs_bindings; tree rhs_bindings; if (lhs == rhs) return 1; if (!constexpr_fundef_hasher::equal (lhs->fundef, rhs->fundef)) return 0; lhs_bindings = lhs->bindings; rhs_bindings = rhs->bindings; while (lhs_bindings != NULL && rhs_bindings != NULL) { tree lhs_arg = TREE_VALUE (lhs_bindings); tree rhs_arg = TREE_VALUE (rhs_bindings); gcc_assert (TREE_TYPE (lhs_arg) == TREE_TYPE (rhs_arg)); if (!cp_tree_equal (lhs_arg, rhs_arg)) return 0; lhs_bindings = TREE_CHAIN (lhs_bindings); rhs_bindings = TREE_CHAIN (rhs_bindings); } return lhs_bindings == rhs_bindings; } /* Initialize the constexpr call table, if needed. */ static void maybe_initialize_constexpr_call_table (void) { if (constexpr_call_table == NULL) constexpr_call_table = hash_table::create_ggc (101); } /* We have an expression tree T that represents a call, either CALL_EXPR or AGGR_INIT_EXPR. If the call is lexically to a named function, retrun the _DECL for that function. */ static tree get_function_named_in_call (tree t) { tree fun = NULL; switch (TREE_CODE (t)) { case CALL_EXPR: fun = CALL_EXPR_FN (t); break; case AGGR_INIT_EXPR: fun = AGGR_INIT_EXPR_FN (t); break; default: gcc_unreachable(); break; } if (fun && TREE_CODE (fun) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (fun, 0)) == FUNCTION_DECL) fun = TREE_OPERAND (fun, 0); return fun; } /* We have an expression tree T that represents a call, either CALL_EXPR or AGGR_INIT_EXPR. Return the Nth argument. */ static inline tree get_nth_callarg (tree t, int n) { switch (TREE_CODE (t)) { case CALL_EXPR: return CALL_EXPR_ARG (t, n); case AGGR_INIT_EXPR: return AGGR_INIT_EXPR_ARG (t, n); default: gcc_unreachable (); return NULL; } } /* Look up the binding of the function parameter T in a constexpr function call context CALL. */ static tree lookup_parameter_binding (const constexpr_call *call, tree t) { tree b = purpose_member (t, call->bindings); return TREE_VALUE (b); } /* Attempt to evaluate T which represents a call to a builtin function. We assume here that all builtin functions evaluate to scalar types represented by _CST nodes. */ static tree cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { const int nargs = call_expr_nargs (t); tree *args = (tree *) alloca (nargs * sizeof (tree)); tree new_call; int i; for (i = 0; i < nargs; ++i) { args[i] = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, i), addr, non_constant_p, overflow_p); if (ctx->quiet && *non_constant_p) return t; } if (*non_constant_p) return t; new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t), CALL_EXPR_FN (t), nargs, args); VERIFY_CONSTANT (new_call); return new_call; } /* TEMP is the constant value of a temporary object of type TYPE. Adjust the type of the value to match. */ static tree adjust_temp_type (tree type, tree temp) { if (TREE_TYPE (temp) == type) return temp; /* Avoid wrapping an aggregate value in a NOP_EXPR. */ if (TREE_CODE (temp) == CONSTRUCTOR) return build_constructor (type, CONSTRUCTOR_ELTS (temp)); gcc_assert (scalarish_type_p (type)); return cp_fold_convert (type, temp); } /* True if we want to use the new handling of constexpr calls based on DECL_SAVED_TREE. */ #define use_new_call true /* Subroutine of cxx_eval_call_expression. We are processing a call expression (either CALL_EXPR or AGGR_INIT_EXPR) in the context of CTX. Evaluate all arguments and bind their values to correspondings parameters, making up the NEW_CALL context. */ static void cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, constexpr_call *new_call, bool *non_constant_p, bool *overflow_p) { const int nargs = call_expr_nargs (t); tree fun = new_call->fundef->decl; tree parms = DECL_ARGUMENTS (fun); int i; tree *p = &new_call->bindings; for (i = 0; i < nargs; ++i) { tree x, arg; tree type = parms ? TREE_TYPE (parms) : void_type_node; x = get_nth_callarg (t, i); /* For member function, the first argument is a pointer to the implied object. For a constructor, it might still be a dummy object, in which case we get the real argument from ctx. */ if (i == 0 && DECL_CONSTRUCTOR_P (fun) && is_dummy_object (x)) { x = ctx->object; x = cp_build_addr_expr (x, tf_warning_or_error); } bool addr = false; if (parms && DECL_BY_REFERENCE (parms) && !use_new_call) { /* cp_genericize made this a reference for argument passing, but we don't want to treat it like one for C++11 constexpr evaluation. C++14 constexpr evaluation uses the genericized DECL_SAVED_TREE. */ gcc_assert (TREE_CODE (type) == REFERENCE_TYPE); gcc_assert (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE); type = TREE_TYPE (type); x = convert_from_reference (x); addr = true; } arg = cxx_eval_constant_expression (ctx, x, addr, non_constant_p, overflow_p); /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p && ctx->quiet) return; /* Just discard ellipsis args after checking their constantitude. */ if (!parms) continue; if (*non_constant_p) /* Don't try to adjust the type of non-constant args. */ goto next; /* Make sure the binding has the same type as the parm. */ if (TREE_CODE (type) != REFERENCE_TYPE) arg = adjust_temp_type (type, arg); *p = build_tree_list (parms, arg); p = &TREE_CHAIN (*p); next: parms = TREE_CHAIN (parms); } } /* Variables and functions to manage constexpr call expansion context. These do not need to be marked for PCH or GC. */ /* FIXME remember and print actual constant arguments. */ static vec call_stack = vNULL; static int call_stack_tick; static int last_cx_error_tick; static bool push_cx_call_context (tree call) { ++call_stack_tick; if (!EXPR_HAS_LOCATION (call)) SET_EXPR_LOCATION (call, input_location); call_stack.safe_push (call); if (call_stack.length () > (unsigned) max_constexpr_depth) return false; return true; } static void pop_cx_call_context (void) { ++call_stack_tick; call_stack.pop (); } vec cx_error_context (void) { vec r = vNULL; if (call_stack_tick != last_cx_error_tick && !call_stack.is_empty ()) r = call_stack; last_cx_error_tick = call_stack_tick; return r; } /* Subroutine of cxx_eval_constant_expression. Evaluate the call expression tree T in the context of OLD_CALL expression evaluation. */ static tree cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { location_t loc = EXPR_LOC_OR_LOC (t, input_location); tree fun = get_function_named_in_call (t); tree result; constexpr_call new_call = { NULL, NULL, NULL, 0 }; constexpr_call **slot; constexpr_call *entry; bool depth_ok; if (TREE_CODE (fun) != FUNCTION_DECL) { /* Might be a constexpr function pointer. */ fun = cxx_eval_constant_expression (ctx, fun, /*addr*/false, non_constant_p, overflow_p); STRIP_NOPS (fun); if (TREE_CODE (fun) == ADDR_EXPR) fun = TREE_OPERAND (fun, 0); } if (TREE_CODE (fun) != FUNCTION_DECL) { if (!ctx->quiet && !*non_constant_p) error_at (loc, "expression %qE does not designate a constexpr " "function", fun); *non_constant_p = true; return t; } if (DECL_CLONED_FUNCTION_P (fun)) fun = DECL_CLONED_FUNCTION (fun); if (is_builtin_fn (fun)) return cxx_eval_builtin_function_call (ctx, t, addr, non_constant_p, overflow_p); if (!DECL_DECLARED_CONSTEXPR_P (fun)) { if (!ctx->quiet) { error_at (loc, "call to non-constexpr function %qD", fun); explain_invalid_constexpr_fn (fun); } *non_constant_p = true; return t; } /* Shortcut trivial constructor/op=. */ if (trivial_fn_p (fun)) { if (call_expr_nargs (t) == 2) { tree arg = convert_from_reference (get_nth_callarg (t, 1)); return cxx_eval_constant_expression (ctx, arg, addr, non_constant_p, overflow_p); } else if (TREE_CODE (t) == AGGR_INIT_EXPR && AGGR_INIT_ZERO_FIRST (t)) return build_zero_init (DECL_CONTEXT (fun), NULL_TREE, false); } /* If in direct recursive call, optimize definition search. */ if (ctx && ctx->call && ctx->call->fundef->decl == fun) new_call.fundef = ctx->call->fundef; else { new_call.fundef = retrieve_constexpr_fundef (fun); if (new_call.fundef == NULL || new_call.fundef->body == NULL) { if (!ctx->quiet) { if (DECL_INITIAL (fun)) { /* The definition of fun was somehow unsuitable. */ error_at (loc, "%qD called in a constant expression", fun); explain_invalid_constexpr_fn (fun); } else error_at (loc, "%qD used before its definition", fun); } *non_constant_p = true; return t; } } constexpr_ctx new_ctx = *ctx; if (DECL_CONSTRUCTOR_P (fun) && !ctx->object && TREE_CODE (t) == AGGR_INIT_EXPR) { /* We want to have an initialization target for an AGGR_INIT_EXPR. If we don't already have one in CTX, use the AGGR_INIT_EXPR_SLOT. */ new_ctx.object = AGGR_INIT_EXPR_SLOT (t); tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL); CONSTRUCTOR_NO_IMPLICIT_ZERO (ctor) = true; ctx->values->put (new_ctx.object, ctor); ctx = &new_ctx; } cxx_bind_parameters_in_call (ctx, t, &new_call, non_constant_p, overflow_p); if (*non_constant_p) return t; depth_ok = push_cx_call_context (t); new_call.hash = iterative_hash_template_arg (new_call.bindings, constexpr_fundef_hasher::hash (new_call.fundef)); /* If we have seen this call before, we are done. */ maybe_initialize_constexpr_call_table (); slot = constexpr_call_table->find_slot (&new_call, INSERT); entry = *slot; if (entry == NULL) { /* We need to keep a pointer to the entry, not just the slot, as the slot can move in the call to cxx_eval_builtin_function_call. */ *slot = entry = ggc_alloc (); *entry = new_call; } /* Calls which are in progress have their result set to NULL so that we can detect circular dependencies. */ else if (entry->result == NULL) { if (!ctx->quiet) error ("call has circular dependency"); *non_constant_p = true; entry->result = result = error_mark_node; } if (!depth_ok) { if (!ctx->quiet) error ("constexpr evaluation depth exceeds maximum of %d (use " "-fconstexpr-depth= to increase the maximum)", max_constexpr_depth); *non_constant_p = true; entry->result = result = error_mark_node; } else { result = entry->result; if (!result || result == error_mark_node) { if (!use_new_call) { new_ctx.call = &new_call; result = (cxx_eval_constant_expression (&new_ctx, new_call.fundef->body, addr, non_constant_p, overflow_p)); } else { if (DECL_SAVED_TREE (fun) == NULL_TREE && (DECL_CONSTRUCTOR_P (fun) || DECL_DESTRUCTOR_P (fun))) /* The maybe-in-charge 'tor had its DECL_SAVED_TREE cleared, try the first clone. */ fun = DECL_CHAIN (fun); gcc_assert (DECL_SAVED_TREE (fun)); tree parms, res; /* Unshare the whole function body. */ tree body = copy_fn (fun, parms, res); /* Associate the bindings with the remapped parms. */ tree bound = new_call.bindings; tree remapped = parms; while (bound) { tree oparm = TREE_PURPOSE (bound); tree arg = TREE_VALUE (bound); gcc_assert (DECL_NAME (remapped) == DECL_NAME (oparm)); ctx->values->put (remapped, arg); bound = TREE_CHAIN (bound); remapped = DECL_CHAIN (remapped); } /* Add the RESULT_DECL to the values map, too. */ tree slot = NULL_TREE; if (DECL_BY_REFERENCE (res)) { slot = AGGR_INIT_EXPR_SLOT (t); tree addr = build_address (slot); addr = build_nop (TREE_TYPE (res), addr); ctx->values->put (res, addr); ctx->values->put (slot, NULL_TREE); } else ctx->values->put (res, NULL_TREE); tree jump_target = NULL_TREE; cxx_eval_constant_expression (ctx, body, addr, non_constant_p, overflow_p, &jump_target); if (DECL_CONSTRUCTOR_P (fun)) /* This can be null for a subobject constructor call, in which case what we care about is the initialization side-effects rather than the value. We could get at the value by evaluating *this, but we don't bother; there's no need to put such a call in the hash table. */ result = addr ? ctx->object : ctx->ctor; else { result = *ctx->values->get (slot ? slot : res); if (result == NULL_TREE && !*non_constant_p) { if (!ctx->quiet) error ("constexpr call flows off the end " "of the function"); *non_constant_p = true; } } /* Remove the parms/result from the values map. Is it worth bothering to do this when the map itself is only live for one constexpr evaluation? If so, maybe also clear out other vars from call, maybe in BIND_EXPR handling? */ ctx->values->remove (res); if (slot) ctx->values->remove (slot); for (tree parm = parms; parm; parm = TREE_CHAIN (parm)) ctx->values->remove (parm); } } if (result == error_mark_node) *non_constant_p = true; if (*non_constant_p) entry->result = result = error_mark_node; else if (result) { /* If this was a call to initialize an object, set the type of the CONSTRUCTOR to the type of that object. */ if (DECL_CONSTRUCTOR_P (fun) && !use_new_call) { tree ob_arg = get_nth_callarg (t, 0); STRIP_NOPS (ob_arg); gcc_assert (TYPE_PTR_P (TREE_TYPE (ob_arg)) && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (ob_arg)))); result = adjust_temp_type (TREE_TYPE (TREE_TYPE (ob_arg)), result); } entry->result = result; } else result = void_node; } pop_cx_call_context (); return unshare_expr (result); } /* FIXME speed this up, it's taking 16% of compile time on sieve testcase. */ bool reduced_constant_expression_p (tree t) { switch (TREE_CODE (t)) { case PTRMEM_CST: /* Even if we can't lower this yet, it's constant. */ return true; case CONSTRUCTOR: /* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR. */ tree elt; unsigned HOST_WIDE_INT idx; FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (t), idx, elt) if (!reduced_constant_expression_p (elt)) return false; return true; default: /* FIXME are we calling this too much? */ return initializer_constant_valid_p (t, TREE_TYPE (t)) != NULL_TREE; } } /* Some expressions may have constant operands but are not constant themselves, such as 1/0. Call this function (or rather, the macro following it) to check for that condition. We only call this in places that require an arithmetic constant, not in places where we might have a non-constant expression that can be a component of a constant expression, such as the address of a constexpr variable that might be dereferenced later. */ static bool verify_constant (tree t, bool allow_non_constant, bool *non_constant_p, bool *overflow_p) { if (!*non_constant_p && !reduced_constant_expression_p (t)) { if (!allow_non_constant) error ("%q+E is not a constant expression", t); *non_constant_p = true; } if (TREE_OVERFLOW_P (t)) { if (!allow_non_constant) { permerror (input_location, "overflow in constant expression"); /* If we're being permissive (and are in an enforcing context), ignore the overflow. */ if (flag_permissive) return *non_constant_p; } *overflow_p = true; } return *non_constant_p; } /* Subroutine of cxx_eval_constant_expression. Attempt to reduce the unary expression tree T to a compile time value. If successful, return the value. Otherwise issue a diagnostic and return error_mark_node. */ static tree cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { tree r; tree orig_arg = TREE_OPERAND (t, 0); tree arg = cxx_eval_constant_expression (ctx, orig_arg, addr, non_constant_p, overflow_p); VERIFY_CONSTANT (arg); location_t loc = EXPR_LOCATION (t); enum tree_code code = TREE_CODE (t); tree type = TREE_TYPE (t); r = fold_unary_loc (loc, code, type, arg); if (r == NULL_TREE) { if (arg == orig_arg) r = t; else r = build1_loc (loc, code, type, arg); } VERIFY_CONSTANT (r); return r; } /* Subroutine of cxx_eval_constant_expression. Like cxx_eval_unary_expression, except for binary expressions. */ static tree cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { tree r; tree orig_lhs = TREE_OPERAND (t, 0); tree orig_rhs = TREE_OPERAND (t, 1); tree lhs, rhs; lhs = cxx_eval_constant_expression (ctx, orig_lhs, addr, non_constant_p, overflow_p); VERIFY_CONSTANT (lhs); rhs = cxx_eval_constant_expression (ctx, orig_rhs, addr, non_constant_p, overflow_p); VERIFY_CONSTANT (rhs); location_t loc = EXPR_LOCATION (t); enum tree_code code = TREE_CODE (t); tree type = TREE_TYPE (t); r = fold_binary_loc (loc, code, type, lhs, rhs); if (r == NULL_TREE) { if (lhs == orig_lhs && rhs == orig_rhs) r = t; else r = build2_loc (loc, code, type, lhs, rhs); } VERIFY_CONSTANT (r); return r; } /* Subroutine of cxx_eval_constant_expression. Attempt to evaluate condition expressions. Dead branches are not looked into. */ static tree cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p, tree *jump_target) { tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), addr, non_constant_p, overflow_p); VERIFY_CONSTANT (val); /* Don't VERIFY_CONSTANT the other operands. */ if (integer_zerop (val)) return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2), addr, non_constant_p, overflow_p, jump_target); return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), addr, non_constant_p, overflow_p, jump_target); } /* Subroutine of cxx_eval_constant_expression. Attempt to reduce a reference to an array slot. */ static tree cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { tree oldary = TREE_OPERAND (t, 0); tree ary = cxx_eval_constant_expression (ctx, oldary, addr, non_constant_p, overflow_p); tree index, oldidx; HOST_WIDE_INT i; tree elem_type; unsigned len, elem_nchars = 1; if (*non_constant_p) return t; oldidx = TREE_OPERAND (t, 1); index = cxx_eval_constant_expression (ctx, oldidx, false, non_constant_p, overflow_p); VERIFY_CONSTANT (index); if (addr && ary == oldary && index == oldidx) return t; else if (addr) return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL); elem_type = TREE_TYPE (TREE_TYPE (ary)); if (TREE_CODE (ary) == CONSTRUCTOR) len = CONSTRUCTOR_NELTS (ary); else if (TREE_CODE (ary) == STRING_CST) { elem_nchars = (TYPE_PRECISION (elem_type) / TYPE_PRECISION (char_type_node)); len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars; } else { /* We can't do anything with other tree codes, so use VERIFY_CONSTANT to complain and fail. */ VERIFY_CONSTANT (ary); gcc_unreachable (); } if (compare_tree_int (index, len) >= 0) { if (tree_int_cst_lt (index, array_type_nelts_top (TREE_TYPE (ary)))) { /* If it's within the array bounds but doesn't have an explicit initializer, it's value-initialized. */ tree val = build_value_init (elem_type, tf_warning_or_error); return cxx_eval_constant_expression (ctx, val, addr, non_constant_p, overflow_p); } if (!ctx->quiet) error ("array subscript out of bound"); *non_constant_p = true; return t; } else if (tree_int_cst_lt (index, integer_zero_node)) { if (!ctx->quiet) error ("negative array subscript"); *non_constant_p = true; return t; } i = tree_to_shwi (index); if (TREE_CODE (ary) == CONSTRUCTOR) return (*CONSTRUCTOR_ELTS (ary))[i].value; else if (elem_nchars == 1) return build_int_cst (cv_unqualified (TREE_TYPE (TREE_TYPE (ary))), TREE_STRING_POINTER (ary)[i]); else { tree type = cv_unqualified (TREE_TYPE (TREE_TYPE (ary))); return native_interpret_expr (type, (const unsigned char *) TREE_STRING_POINTER (ary) + i * elem_nchars, elem_nchars); } /* Don't VERIFY_CONSTANT here. */ } /* Subroutine of cxx_eval_constant_expression. Attempt to reduce a field access of a value of class type. */ static tree cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { unsigned HOST_WIDE_INT i; tree field; tree value; tree part = TREE_OPERAND (t, 1); tree orig_whole = TREE_OPERAND (t, 0); tree whole = cxx_eval_constant_expression (ctx, orig_whole, addr, non_constant_p, overflow_p); if (whole == orig_whole) return t; if (addr) return fold_build3 (COMPONENT_REF, TREE_TYPE (t), whole, part, NULL_TREE); /* Don't VERIFY_CONSTANT here; we only want to check that we got a CONSTRUCTOR. */ if (!*non_constant_p && TREE_CODE (whole) != CONSTRUCTOR) { if (!ctx->quiet) error ("%qE is not a constant expression", orig_whole); *non_constant_p = true; } if (DECL_MUTABLE_P (part)) { if (!ctx->quiet) error ("mutable %qD is not usable in a constant expression", part); *non_constant_p = true; } if (*non_constant_p) return t; FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value) { if (field == part) { if (value) return value; else /* We're in the middle of initializing it. */ break; } } if (TREE_CODE (TREE_TYPE (whole)) == UNION_TYPE && CONSTRUCTOR_NELTS (whole) > 0) { /* DR 1188 says we don't have to deal with this. */ if (!ctx->quiet) error ("accessing %qD member instead of initialized %qD member in " "constant expression", part, CONSTRUCTOR_ELT (whole, 0)->index); *non_constant_p = true; return t; } if (CONSTRUCTOR_NO_IMPLICIT_ZERO (whole)) { /* 'whole' is part of the aggregate initializer we're currently building; if there's no initializer for this member yet, that's an error. */ if (!ctx->quiet) error ("accessing uninitialized member %qD", part); *non_constant_p = true; return t; } /* If there's no explicit init for this field, it's value-initialized. */ value = build_value_init (TREE_TYPE (t), tf_warning_or_error); return cxx_eval_constant_expression (ctx, value, addr, non_constant_p, overflow_p); } /* Subroutine of cxx_eval_constant_expression. Attempt to reduce a field access of a value of class type that is expressed as a BIT_FIELD_REF. */ static tree cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { tree orig_whole = TREE_OPERAND (t, 0); tree retval, fldval, utype, mask; bool fld_seen = false; HOST_WIDE_INT istart, isize; tree whole = cxx_eval_constant_expression (ctx, orig_whole, addr, non_constant_p, overflow_p); tree start, field, value; unsigned HOST_WIDE_INT i; if (whole == orig_whole) return t; /* Don't VERIFY_CONSTANT here; we only want to check that we got a CONSTRUCTOR. */ if (!*non_constant_p && TREE_CODE (whole) != VECTOR_CST && TREE_CODE (whole) != CONSTRUCTOR) { if (!ctx->quiet) error ("%qE is not a constant expression", orig_whole); *non_constant_p = true; } if (*non_constant_p) return t; if (TREE_CODE (whole) == VECTOR_CST) return fold_ternary (BIT_FIELD_REF, TREE_TYPE (t), whole, TREE_OPERAND (t, 1), TREE_OPERAND (t, 2)); start = TREE_OPERAND (t, 2); istart = tree_to_shwi (start); isize = tree_to_shwi (TREE_OPERAND (t, 1)); utype = TREE_TYPE (t); if (!TYPE_UNSIGNED (utype)) utype = build_nonstandard_integer_type (TYPE_PRECISION (utype), 1); retval = build_int_cst (utype, 0); FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value) { tree bitpos = bit_position (field); if (bitpos == start && DECL_SIZE (field) == TREE_OPERAND (t, 1)) return value; if (TREE_CODE (TREE_TYPE (field)) == INTEGER_TYPE && TREE_CODE (value) == INTEGER_CST && tree_fits_shwi_p (bitpos) && tree_fits_shwi_p (DECL_SIZE (field))) { HOST_WIDE_INT bit = tree_to_shwi (bitpos); HOST_WIDE_INT sz = tree_to_shwi (DECL_SIZE (field)); HOST_WIDE_INT shift; if (bit >= istart && bit + sz <= istart + isize) { fldval = fold_convert (utype, value); mask = build_int_cst_type (utype, -1); mask = fold_build2 (LSHIFT_EXPR, utype, mask, size_int (TYPE_PRECISION (utype) - sz)); mask = fold_build2 (RSHIFT_EXPR, utype, mask, size_int (TYPE_PRECISION (utype) - sz)); fldval = fold_build2 (BIT_AND_EXPR, utype, fldval, mask); shift = bit - istart; if (BYTES_BIG_ENDIAN) shift = TYPE_PRECISION (utype) - shift - sz; fldval = fold_build2 (LSHIFT_EXPR, utype, fldval, size_int (shift)); retval = fold_build2 (BIT_IOR_EXPR, utype, retval, fldval); fld_seen = true; } } } if (fld_seen) return fold_convert (TREE_TYPE (t), retval); gcc_unreachable (); return error_mark_node; } /* Subroutine of cxx_eval_constant_expression. Evaluate a short-circuited logical expression T in the context of a given constexpr CALL. BAILOUT_VALUE is the value for early return. CONTINUE_VALUE is used here purely for sanity check purposes. */ static tree cxx_eval_logical_expression (const constexpr_ctx *ctx, tree t, tree bailout_value, tree continue_value, bool addr, bool *non_constant_p, bool *overflow_p) { tree r; tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), addr, non_constant_p, overflow_p); VERIFY_CONSTANT (lhs); if (tree_int_cst_equal (lhs, bailout_value)) return lhs; gcc_assert (tree_int_cst_equal (lhs, continue_value)); r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), addr, non_constant_p, overflow_p); VERIFY_CONSTANT (r); return r; } /* REF is a COMPONENT_REF designating a particular field. V is a vector of CONSTRUCTOR elements to initialize (part of) an object containing that field. Return a pointer to the constructor_elt corresponding to the initialization of the field. */ static constructor_elt * base_field_constructor_elt (vec *v, tree ref) { tree aggr = TREE_OPERAND (ref, 0); tree field = TREE_OPERAND (ref, 1); HOST_WIDE_INT i; constructor_elt *ce; gcc_assert (TREE_CODE (ref) == COMPONENT_REF); if (TREE_CODE (aggr) == COMPONENT_REF) { constructor_elt *base_ce = base_field_constructor_elt (v, aggr); v = CONSTRUCTOR_ELTS (base_ce->value); } for (i = 0; vec_safe_iterate (v, i, &ce); ++i) if (ce->index == field) return ce; gcc_unreachable (); return NULL; } /* Some of the expressions fed to the constexpr mechanism are calls to constructors, which have type void. In that case, return the type being initialized by the constructor. */ static tree initialized_type (tree t) { if (TYPE_P (t)) return t; tree type = cv_unqualified (TREE_TYPE (t)); if (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR) { /* A constructor call has void type, so we need to look deeper. */ tree fn = get_function_named_in_call (t); if (fn && TREE_CODE (fn) == FUNCTION_DECL && DECL_CXX_CONSTRUCTOR_P (fn)) type = DECL_CONTEXT (fn); } return type; } /* We're about to initialize element INDEX of an array or class from VALUE. Set up NEW_CTX appropriately by adjusting .object to refer to the subobject and creating a new CONSTRUCTOR if the element is itself a class or array. */ static void init_subob_ctx (const constexpr_ctx *ctx, constexpr_ctx &new_ctx, tree index, tree &value) { new_ctx = *ctx; if (index && TREE_CODE (index) != INTEGER_CST && TREE_CODE (index) != FIELD_DECL) /* This won't have an element in the new CONSTRUCTOR. */ return; tree type = initialized_type (value); if (!AGGREGATE_TYPE_P (type) && !VECTOR_TYPE_P (type)) /* A non-aggregate member doesn't get its own CONSTRUCTOR. */ return; /* The sub-aggregate initializer might contain a placeholder; update object to refer to the subobject and ctor to refer to the (newly created) sub-initializer. */ if (ctx->object) new_ctx.object = build_ctor_subob_ref (index, type, ctx->object); tree elt = build_constructor (type, NULL); CONSTRUCTOR_NO_IMPLICIT_ZERO (elt) = true; new_ctx.ctor = elt; if (TREE_CODE (value) == TARGET_EXPR) /* Avoid creating another CONSTRUCTOR when we expand the TARGET_EXPR. */ value = TARGET_EXPR_INITIAL (value); } /* We're about to process an initializer for a class or array TYPE. Make sure that CTX is set up appropriately. */ static void verify_ctor_sanity (const constexpr_ctx *ctx, tree type) { /* We don't bother building a ctor for an empty base subobject. */ if (is_empty_class (type)) return; /* We're in the middle of an initializer that might involve placeholders; our caller should have created a CONSTRUCTOR for us to put the initializer into. We will either return that constructor or T. */ gcc_assert (ctx->ctor); gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (ctx->ctor))); gcc_assert (CONSTRUCTOR_NELTS (ctx->ctor) == 0); if (ctx->object) gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (ctx->object))); gcc_assert (!ctx->object || !DECL_P (ctx->object) || *(ctx->values->get (ctx->object)) == ctx->ctor); } /* Subroutine of cxx_eval_constant_expression. The expression tree T denotes a C-style array or a C-style aggregate. Reduce it to a constant expression. */ static tree cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { vec *v = CONSTRUCTOR_ELTS (t); bool changed = false; gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (t)); verify_ctor_sanity (ctx, TREE_TYPE (t)); vec **p = &CONSTRUCTOR_ELTS (ctx->ctor); vec_alloc (*p, vec_safe_length (v)); unsigned i; tree index, value; FOR_EACH_CONSTRUCTOR_ELT (v, i, index, value) { constexpr_ctx new_ctx; init_subob_ctx (ctx, new_ctx, index, value); if (new_ctx.ctor != ctx->ctor) /* If we built a new CONSTRUCTOR, attach it now so that other initializers can refer to it. */ CONSTRUCTOR_APPEND_ELT (*p, index, new_ctx.ctor); tree elt = cxx_eval_constant_expression (&new_ctx, value, addr, non_constant_p, overflow_p); /* Don't VERIFY_CONSTANT here. */ if (ctx->quiet && *non_constant_p) break; if (elt != value) changed = true; if (index && TREE_CODE (index) == COMPONENT_REF) { /* This is an initialization of a vfield inside a base subaggregate that we already initialized; push this initialization into the previous initialization. */ constructor_elt *inner = base_field_constructor_elt (*p, index); inner->value = elt; changed = true; } else if (index && (TREE_CODE (index) == NOP_EXPR || TREE_CODE (index) == POINTER_PLUS_EXPR)) { /* This is an initializer for an empty base; now that we've checked that it's constant, we can ignore it. */ gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (index)))); changed = true; } else if (new_ctx.ctor != ctx->ctor) { /* We appended this element above; update the value. */ gcc_assert ((*p)->last().index == index); (*p)->last().value = elt; } else CONSTRUCTOR_APPEND_ELT (*p, index, elt); } if (*non_constant_p || !changed) return t; t = ctx->ctor; /* We're done building this CONSTRUCTOR, so now we can interpret an element without an explicit initializer as value-initialized. */ CONSTRUCTOR_NO_IMPLICIT_ZERO (t) = false; if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE) t = fold (t); return t; } /* Subroutine of cxx_eval_constant_expression. The expression tree T is a VEC_INIT_EXPR which denotes the desired initialization of a non-static data member of array type. Reduce it to a CONSTRUCTOR. Note that apart from value-initialization (when VALUE_INIT is true), this is only intended to support value-initialization and the initializations done by defaulted constructors for classes with non-static data members of array type. In this case, VEC_INIT_EXPR_INIT will either be NULL_TREE for the default constructor, or a COMPONENT_REF for the copy/move constructor. */ static tree cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, bool value_init, bool addr, bool *non_constant_p, bool *overflow_p) { tree elttype = TREE_TYPE (atype); int max = tree_to_shwi (array_type_nelts (atype)); verify_ctor_sanity (ctx, atype); vec **p = &CONSTRUCTOR_ELTS (ctx->ctor); vec_alloc (*p, max + 1); bool pre_init = false; int i; /* For the default constructor, build up a call to the default constructor of the element type. We only need to handle class types here, as for a constructor to be constexpr, all members must be initialized, which for a defaulted default constructor means they must be of a class type with a constexpr default constructor. */ if (TREE_CODE (elttype) == ARRAY_TYPE) /* We only do this at the lowest level. */; else if (value_init) { init = build_value_init (elttype, tf_warning_or_error); pre_init = true; } else if (!init) { vec *argvec = make_tree_vector (); init = build_special_member_call (NULL_TREE, complete_ctor_identifier, &argvec, elttype, LOOKUP_NORMAL, tf_warning_or_error); release_tree_vector (argvec); init = build_aggr_init_expr (TREE_TYPE (init), init); pre_init = true; } for (i = 0; i <= max; ++i) { tree idx = build_int_cst (size_type_node, i); tree eltinit; constexpr_ctx new_ctx; init_subob_ctx (ctx, new_ctx, idx, pre_init ? init : elttype); if (new_ctx.ctor != ctx->ctor) CONSTRUCTOR_APPEND_ELT (*p, idx, new_ctx.ctor); if (TREE_CODE (elttype) == ARRAY_TYPE) { /* A multidimensional array; recurse. */ if (value_init || init == NULL_TREE) eltinit = NULL_TREE; else eltinit = cp_build_array_ref (input_location, init, idx, tf_warning_or_error); eltinit = cxx_eval_vec_init_1 (&new_ctx, elttype, eltinit, value_init, addr, non_constant_p, overflow_p); } else if (pre_init) { /* Initializing an element using value or default initialization we just pre-built above. */ eltinit = (cxx_eval_constant_expression (&new_ctx, init, addr, non_constant_p, overflow_p)); } else { /* Copying an element. */ gcc_assert (same_type_ignoring_top_level_qualifiers_p (atype, TREE_TYPE (init))); eltinit = cp_build_array_ref (input_location, init, idx, tf_warning_or_error); if (!real_lvalue_p (init)) eltinit = move (eltinit); eltinit = force_rvalue (eltinit, tf_warning_or_error); eltinit = (cxx_eval_constant_expression (&new_ctx, eltinit, addr, non_constant_p, overflow_p)); } if (*non_constant_p && !ctx->quiet) break; if (new_ctx.ctor != ctx->ctor) { /* We appended this element above; update the value. */ gcc_assert ((*p)->last().index == idx); (*p)->last().value = eltinit; } else CONSTRUCTOR_APPEND_ELT (*p, idx, eltinit); } if (!*non_constant_p) { init = ctx->ctor; CONSTRUCTOR_NO_IMPLICIT_ZERO (init) = false; } return init; } static tree cxx_eval_vec_init (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { tree atype = TREE_TYPE (t); tree init = VEC_INIT_EXPR_INIT (t); tree r = cxx_eval_vec_init_1 (ctx, atype, init, VEC_INIT_EXPR_VALUE_INIT (t), addr, non_constant_p, overflow_p); if (*non_constant_p) return t; else return r; } /* A less strict version of fold_indirect_ref_1, which requires cv-quals to match. We want to be less strict for simple *& folding; if we have a non-const temporary that we access through a const pointer, that should work. We handle this here rather than change fold_indirect_ref_1 because we're dealing with things like ADDR_EXPR of INTEGER_CST which don't really make sense outside of constant expression evaluation. Also we want to allow folding to COMPONENT_REF, which could cause trouble with TBAA in fold_indirect_ref_1. Try to keep this function synced with fold_indirect_ref_1. */ static tree cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) { tree sub, subtype; sub = op0; STRIP_NOPS (sub); subtype = TREE_TYPE (sub); if (!POINTER_TYPE_P (subtype)) return NULL_TREE; if (TREE_CODE (sub) == ADDR_EXPR) { tree op = TREE_OPERAND (sub, 0); tree optype = TREE_TYPE (op); /* *&CONST_DECL -> to the value of the const decl. */ if (TREE_CODE (op) == CONST_DECL) return DECL_INITIAL (op); /* *&p => p; make sure to handle *&"str"[cst] here. */ if (same_type_ignoring_top_level_qualifiers_p (optype, type)) { tree fop = fold_read_from_constant_string (op); if (fop) return fop; else return op; } /* *(foo *)&fooarray => fooarray[0] */ else if (TREE_CODE (optype) == ARRAY_TYPE && (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (optype)))) { tree type_domain = TYPE_DOMAIN (optype); tree min_val = size_zero_node; if (type_domain && TYPE_MIN_VALUE (type_domain)) min_val = TYPE_MIN_VALUE (type_domain); return build4_loc (loc, ARRAY_REF, type, op, min_val, NULL_TREE, NULL_TREE); } /* *(foo *)&complexfoo => __real__ complexfoo */ else if (TREE_CODE (optype) == COMPLEX_TYPE && (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (optype)))) return fold_build1_loc (loc, REALPART_EXPR, type, op); /* *(foo *)&vectorfoo => BIT_FIELD_REF */ else if (TREE_CODE (optype) == VECTOR_TYPE && (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (optype)))) { tree part_width = TYPE_SIZE (type); tree index = bitsize_int (0); return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width, index); } /* Also handle conversion to an empty base class, which is represented with a NOP_EXPR. */ else if (is_empty_class (type) && CLASS_TYPE_P (optype) && DERIVED_FROM_P (type, optype)) { *empty_base = true; return op; } /* *(foo *)&struct_with_foo_field => COMPONENT_REF */ else if (RECORD_OR_UNION_TYPE_P (optype)) { tree field = TYPE_FIELDS (optype); for (; field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL && integer_zerop (byte_position (field)) && (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field), type))) { return fold_build3 (COMPONENT_REF, type, op, field, NULL_TREE); break; } } } else if (TREE_CODE (sub) == POINTER_PLUS_EXPR && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST) { tree op00 = TREE_OPERAND (sub, 0); tree op01 = TREE_OPERAND (sub, 1); STRIP_NOPS (op00); if (TREE_CODE (op00) == ADDR_EXPR) { tree op00type; op00 = TREE_OPERAND (op00, 0); op00type = TREE_TYPE (op00); /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF */ if (TREE_CODE (op00type) == VECTOR_TYPE && (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (op00type)))) { HOST_WIDE_INT offset = tree_to_shwi (op01); tree part_width = TYPE_SIZE (type); unsigned HOST_WIDE_INT part_widthi = tree_to_shwi (part_width)/BITS_PER_UNIT; unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT; tree index = bitsize_int (indexi); if (offset / part_widthi < TYPE_VECTOR_SUBPARTS (op00type)) return fold_build3_loc (loc, BIT_FIELD_REF, type, op00, part_width, index); } /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ else if (TREE_CODE (op00type) == COMPLEX_TYPE && (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (op00type)))) { tree size = TYPE_SIZE_UNIT (type); if (tree_int_cst_equal (size, op01)) return fold_build1_loc (loc, IMAGPART_EXPR, type, op00); } /* ((foo *)&fooarray)[1] => fooarray[1] */ else if (TREE_CODE (op00type) == ARRAY_TYPE && (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (op00type)))) { tree type_domain = TYPE_DOMAIN (op00type); tree min_val = size_zero_node; if (type_domain && TYPE_MIN_VALUE (type_domain)) min_val = TYPE_MIN_VALUE (type_domain); op01 = size_binop_loc (loc, EXACT_DIV_EXPR, op01, TYPE_SIZE_UNIT (type)); op01 = size_binop_loc (loc, PLUS_EXPR, op01, min_val); return build4_loc (loc, ARRAY_REF, type, op00, op01, NULL_TREE, NULL_TREE); } /* Also handle conversion to an empty base class, which is represented with a NOP_EXPR. */ else if (is_empty_class (type) && CLASS_TYPE_P (op00type) && DERIVED_FROM_P (type, op00type)) { *empty_base = true; return op00; } /* ((foo *)&struct_with_foo_field)[1] => COMPONENT_REF */ else if (RECORD_OR_UNION_TYPE_P (op00type)) { tree field = TYPE_FIELDS (op00type); for (; field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL && tree_int_cst_equal (byte_position (field), op01) && (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field), type))) { return fold_build3 (COMPONENT_REF, type, op00, field, NULL_TREE); break; } } } } /* *(foo *)fooarrptr => (*fooarrptr)[0] */ else if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE && (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (TREE_TYPE (subtype))))) { tree type_domain; tree min_val = size_zero_node; tree newsub = cxx_fold_indirect_ref (loc, TREE_TYPE (subtype), sub, NULL); if (newsub) sub = newsub; else sub = build1_loc (loc, INDIRECT_REF, TREE_TYPE (subtype), sub); type_domain = TYPE_DOMAIN (TREE_TYPE (sub)); if (type_domain && TYPE_MIN_VALUE (type_domain)) min_val = TYPE_MIN_VALUE (type_domain); return build4_loc (loc, ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE); } return NULL_TREE; } static tree cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { tree orig_op0 = TREE_OPERAND (t, 0); tree op0 = cxx_eval_constant_expression (ctx, orig_op0, /*addr*/false, non_constant_p, overflow_p); bool empty_base = false; tree r; /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p) return t; r = cxx_fold_indirect_ref (EXPR_LOCATION (t), TREE_TYPE (t), op0, &empty_base); if (r) r = cxx_eval_constant_expression (ctx, r, addr, non_constant_p, overflow_p); else { tree sub = op0; STRIP_NOPS (sub); if (TREE_CODE (sub) == ADDR_EXPR) { /* We couldn't fold to a constant value. Make sure it's not something we should have been able to fold. */ gcc_assert (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t))); /* DR 1188 says we don't have to deal with this. */ if (!ctx->quiet) error ("accessing value of %qE through a %qT glvalue in a " "constant expression", build_fold_indirect_ref (sub), TREE_TYPE (t)); *non_constant_p = true; return t; } } /* If we're pulling out the value of an empty base, make sure that the whole object is constant and then return an empty CONSTRUCTOR. */ if (empty_base && !addr) { VERIFY_CONSTANT (r); r = build_constructor (TREE_TYPE (t), NULL); TREE_CONSTANT (r) = true; } if (r == NULL_TREE) { if (addr && op0 != orig_op0) return build1 (INDIRECT_REF, TREE_TYPE (t), op0); if (!addr) VERIFY_CONSTANT (t); return t; } return r; } /* Complain about R, a VAR_DECL, not being usable in a constant expression. Shared between potential_constant_expression and cxx_eval_constant_expression. */ static void non_const_var_error (tree r) { tree type = TREE_TYPE (r); error ("the value of %qD is not usable in a constant " "expression", r); /* Avoid error cascade. */ if (DECL_INITIAL (r) == error_mark_node) return; if (DECL_DECLARED_CONSTEXPR_P (r)) inform (DECL_SOURCE_LOCATION (r), "%qD used in its own initializer", r); else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type)) { if (!CP_TYPE_CONST_P (type)) inform (DECL_SOURCE_LOCATION (r), "%q#D is not const", r); else if (CP_TYPE_VOLATILE_P (type)) inform (DECL_SOURCE_LOCATION (r), "%q#D is volatile", r); else if (!DECL_INITIAL (r) || !TREE_CONSTANT (DECL_INITIAL (r))) inform (DECL_SOURCE_LOCATION (r), "%qD was not initialized with a constant " "expression", r); else gcc_unreachable (); } else { if (cxx_dialect >= cxx11 && !DECL_DECLARED_CONSTEXPR_P (r)) inform (DECL_SOURCE_LOCATION (r), "%qD was not declared %", r); else inform (DECL_SOURCE_LOCATION (r), "%qD does not have integral or enumeration type", r); } } /* Subroutine of cxx_eval_constant_expression. Like cxx_eval_unary_expression, except for trinary expressions. */ static tree cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { int i; tree args[3]; tree val; for (i = 0; i < 3; i++) { args[i] = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, i), addr, non_constant_p, overflow_p); VERIFY_CONSTANT (args[i]); } val = fold_ternary_loc (EXPR_LOCATION (t), TREE_CODE (t), TREE_TYPE (t), args[0], args[1], args[2]); if (val == NULL_TREE) return t; VERIFY_CONSTANT (val); return val; } bool var_in_constexpr_fn (tree t) { tree ctx = DECL_CONTEXT (t); return (cxx_dialect >= cxx14 && ctx && TREE_CODE (ctx) == FUNCTION_DECL && DECL_DECLARED_CONSTEXPR_P (ctx)); } /* Evaluate an INIT_EXPR or MODIFY_EXPR. */ static tree cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { constexpr_ctx new_ctx = *ctx; /* First we figure out where we're storing to. */ tree target = TREE_OPERAND (t, 0); target = cxx_eval_constant_expression (ctx, target, true, non_constant_p, overflow_p); if (*non_constant_p) return t; /* And then find the underlying variable. */ vec *refs = make_tree_vector(); tree object = NULL_TREE; for (tree probe = target; object == NULL_TREE; ) { switch (TREE_CODE (probe)) { case BIT_FIELD_REF: case COMPONENT_REF: case ARRAY_REF: vec_safe_push (refs, TREE_OPERAND (probe, 1)); vec_safe_push (refs, TREE_TYPE (probe)); probe = TREE_OPERAND (probe, 0); break; default: object = probe; gcc_assert (DECL_P (object)); } } /* And then find/build up our initializer for the path to the subobject we're initializing. */ tree *valp = ctx->values->get (object); if (!valp) { /* A constant-expression cannot modify objects from outside the constant-expression. */ if (!ctx->quiet) error ("modification of %qD is not a constant-expression", object); *non_constant_p = true; return t; } tree type = TREE_TYPE (object); while (!refs->is_empty()) { if (*valp == NULL_TREE) { *valp = build_constructor (type, NULL); CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp) = true; } constructor_elt ce; type = refs->pop(); ce.index = refs->pop(); ce.value = NULL_TREE; unsigned HOST_WIDE_INT idx = 0; constructor_elt *cep = NULL; for (idx = 0; vec_safe_iterate (CONSTRUCTOR_ELTS (*valp), idx, &cep); idx++) /* ??? slow */ if (cp_tree_equal (ce.index, cep->index)) break; if (!cep) cep = vec_safe_push (CONSTRUCTOR_ELTS (*valp), ce); valp = &cep->value; } release_tree_vector (refs); if ((AGGREGATE_TYPE_P (TREE_TYPE (t)) || VECTOR_TYPE_P (TREE_TYPE (t)))) { /* Create a new CONSTRUCTOR in case evaluation of the initializer wants to modify it. */ *valp = new_ctx.ctor = build_constructor (TREE_TYPE (t), NULL); CONSTRUCTOR_NO_IMPLICIT_ZERO (new_ctx.ctor) = true; new_ctx.object = target; } tree init = cxx_eval_constant_expression (&new_ctx, TREE_OPERAND (t, 1), false, non_constant_p, overflow_p); if (target == object) /* The hash table might have moved since the get earlier. */ ctx->values->put (object, init); else *valp = init; if (*non_constant_p) return t; else if (addr) return target; else return init; } /* Evaluate a ++ or -- expression. */ static tree cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p) { enum tree_code code = TREE_CODE (t); tree type = TREE_TYPE (t); tree op = TREE_OPERAND (t, 0); tree offset = TREE_OPERAND (t, 1); gcc_assert (TREE_CONSTANT (offset)); /* The operand as an lvalue. */ op = cxx_eval_constant_expression (ctx, op, true, non_constant_p, overflow_p); /* The operand as an rvalue. */ tree val = rvalue (op); val = cxx_eval_constant_expression (ctx, val, false, non_constant_p, overflow_p); VERIFY_CONSTANT (val); /* The modified value. */ bool inc = (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR); tree mod; if (POINTER_TYPE_P (type)) { /* The middle end requires pointers to use POINTER_PLUS_EXPR. */ offset = convert_to_ptrofftype (offset); if (!inc) offset = fold_build1 (NEGATE_EXPR, TREE_TYPE (offset), offset); mod = fold_build2 (POINTER_PLUS_EXPR, type, val, offset); } else mod = fold_build2 (inc ? PLUS_EXPR : MINUS_EXPR, type, val, offset); VERIFY_CONSTANT (mod); /* Storing the modified value. */ tree store = build2 (MODIFY_EXPR, type, op, mod); cxx_eval_constant_expression (ctx, store, true, non_constant_p, overflow_p); /* And the value of the expression. */ if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR) { /* Prefix ops are lvalues. */ if (addr) return op; else /* But we optimize when the caller wants an rvalue. */ return mod; } else /* Postfix ops are rvalues. */ return val; } /* Predicates for the meaning of *jump_target. */ static bool returns (tree *jump_target) { return *jump_target && TREE_CODE (*jump_target) == RETURN_EXPR; } static bool breaks (tree *jump_target) { return *jump_target && TREE_CODE (*jump_target) == LABEL_DECL && LABEL_DECL_BREAK (*jump_target); } static bool continues (tree *jump_target) { return *jump_target && TREE_CODE (*jump_target) == LABEL_DECL && LABEL_DECL_CONTINUE (*jump_target); } static bool switches (tree *jump_target) { return *jump_target && TREE_CODE (*jump_target) == INTEGER_CST; } /* Subroutine of cxx_eval_statement_list. Determine whether the statement at I matches *jump_target. If we're looking for a case label and we see the default label, copy I into DEFAULT_LABEL. */ static bool label_matches (tree *jump_target, tree_stmt_iterator i, tree_stmt_iterator& default_label) { tree stmt = tsi_stmt (i); switch (TREE_CODE (*jump_target)) { case LABEL_DECL: if (TREE_CODE (stmt) == LABEL_EXPR && LABEL_EXPR_LABEL (stmt) == *jump_target) return true; break; case INTEGER_CST: if (TREE_CODE (stmt) == CASE_LABEL_EXPR) { if (!CASE_LOW (stmt)) default_label = i; else if (tree_int_cst_equal (*jump_target, CASE_LOW (stmt))) return true; } break; default: gcc_unreachable (); } return false; } /* Evaluate a STATEMENT_LIST for side-effects. Handles various jump semantics, for switch, break, continue, and return. */ static tree cxx_eval_statement_list (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p, tree *jump_target) { tree_stmt_iterator i; tree_stmt_iterator default_label = tree_stmt_iterator(); tree local_target; /* In a statement-expression we want to return the last value. */ tree r = NULL_TREE; if (!jump_target) { local_target = NULL_TREE; jump_target = &local_target; } for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) { reenter: tree stmt = tsi_stmt (i); if (*jump_target) { if (TREE_CODE (stmt) == STATEMENT_LIST) /* The label we want might be inside. */; else if (label_matches (jump_target, i, default_label)) /* Found it. */ *jump_target = NULL_TREE; else continue; } r = cxx_eval_constant_expression (ctx, stmt, false, non_constant_p, overflow_p, jump_target); if (*non_constant_p) break; if (returns (jump_target) || breaks (jump_target)) break; } if (switches (jump_target) && !tsi_end_p (default_label)) { i = default_label; *jump_target = NULL_TREE; goto reenter; } return r; } /* Evaluate a LOOP_EXPR for side-effects. Handles break and return semantics; continue semantics are covered by cxx_eval_statement_list. */ static tree cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p, tree *jump_target) { tree body = TREE_OPERAND (t, 0); while (true) { cxx_eval_statement_list (ctx, body, non_constant_p, overflow_p, jump_target); if (returns (jump_target) || breaks (jump_target)) break; } if (breaks (jump_target)) *jump_target = NULL_TREE; return NULL_TREE; } /* Evaluate a SWITCH_EXPR for side-effects. Handles switch and break jump semantics. */ static tree cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p, tree *jump_target) { tree cond = TREE_OPERAND (t, 0); cond = cxx_eval_constant_expression (ctx, cond, false, non_constant_p, overflow_p); VERIFY_CONSTANT (cond); *jump_target = cond; tree body = TREE_OPERAND (t, 1); cxx_eval_statement_list (ctx, body, non_constant_p, overflow_p, jump_target); if (breaks (jump_target) || switches (jump_target)) *jump_target = NULL_TREE; return NULL_TREE; } /* Attempt to reduce the expression T to a constant value. On failure, issue diagnostic and return error_mark_node. */ /* FIXME unify with c_fully_fold */ /* FIXME overflow_p is too global */ static tree cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, bool addr, bool *non_constant_p, bool *overflow_p, tree *jump_target) { constexpr_ctx new_ctx; tree r = t; if (t == error_mark_node) { *non_constant_p = true; return t; } if (CONSTANT_CLASS_P (t)) { if (TREE_CODE (t) == PTRMEM_CST) t = cplus_expand_constant (t); else if (TREE_OVERFLOW (t) && (!flag_permissive || ctx->quiet)) *overflow_p = true; return t; } if (TREE_CODE (t) != NOP_EXPR && reduced_constant_expression_p (t)) return fold (t); switch (TREE_CODE (t)) { case RESULT_DECL: if (addr) return t; /* We ask for an rvalue for the RESULT_DECL when indirecting through an invisible reference. */ gcc_assert (DECL_BY_REFERENCE (t)); return (*ctx->values->get (t)); case VAR_DECL: if (addr) return t; /* else fall through. */ case CONST_DECL: if (ctx->strict) r = decl_really_constant_value (t); else r = decl_constant_value (t); if (TREE_CODE (r) == TARGET_EXPR && TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR) r = TARGET_EXPR_INITIAL (r); if (TREE_CODE (r) == VAR_DECL) if (tree *p = ctx->values->get (r)) r = *p; if (DECL_P (r)) { if (!ctx->quiet) non_const_var_error (r); *non_constant_p = true; } break; case FUNCTION_DECL: case TEMPLATE_DECL: case LABEL_DECL: case LABEL_EXPR: case CASE_LABEL_EXPR: return t; case PARM_DECL: if (!use_new_call && ctx && ctx->call && DECL_CONTEXT (t) == ctx->call->fundef->decl) r = lookup_parameter_binding (ctx->call, t); else if (addr && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE) /* glvalue use. */; else if (tree *p = ctx->values->get (r)) r = *p; else if (addr) /* Defer in case this is only used for its type. */; else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) /* Defer, there's no lvalue->rvalue conversion. */; else if (is_empty_class (TREE_TYPE (t))) { /* If the class is empty, we aren't actually loading anything. */ r = build_constructor (TREE_TYPE (t), NULL); TREE_CONSTANT (r) = true; } else { if (!ctx->quiet) error ("%qE is not a constant expression", t); *non_constant_p = true; } break; case CALL_EXPR: case AGGR_INIT_EXPR: r = cxx_eval_call_expression (ctx, t, addr, non_constant_p, overflow_p); break; case DECL_EXPR: { r = DECL_EXPR_DECL (t); if (AGGREGATE_TYPE_P (TREE_TYPE (r)) || VECTOR_TYPE_P (TREE_TYPE (r))) { new_ctx = *ctx; new_ctx.object = r; new_ctx.ctor = build_constructor (TREE_TYPE (r), NULL); CONSTRUCTOR_NO_IMPLICIT_ZERO (new_ctx.ctor) = true; new_ctx.values->put (r, new_ctx.ctor); ctx = &new_ctx; } if (tree init = DECL_INITIAL (r)) { init = cxx_eval_constant_expression (ctx, init, false, non_constant_p, overflow_p); ctx->values->put (r, init); } else if (ctx == &new_ctx) /* We gave it a CONSTRUCTOR above. */; else ctx->values->put (r, NULL_TREE); } break; case TARGET_EXPR: if (!literal_type_p (TREE_TYPE (t))) { if (!ctx->quiet) { error ("temporary of non-literal type %qT in a " "constant expression", TREE_TYPE (t)); explain_non_literal_class (TREE_TYPE (t)); } *non_constant_p = true; break; } if ((AGGREGATE_TYPE_P (TREE_TYPE (t)) || VECTOR_TYPE_P (TREE_TYPE (t)))) { /* We're being expanded without an explicit target, so start initializing a new object; expansion with an explicit target strips the TARGET_EXPR before we get here. */ new_ctx = *ctx; new_ctx.ctor = build_constructor (TREE_TYPE (t), NULL); CONSTRUCTOR_NO_IMPLICIT_ZERO (new_ctx.ctor) = true; new_ctx.object = TARGET_EXPR_SLOT (t); ctx->values->put (new_ctx.object, new_ctx.ctor); ctx = &new_ctx; } /* Pass false for 'addr' because this indicates initialization of a temporary. */ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), false, non_constant_p, overflow_p); if (!*non_constant_p) /* Adjust the type of the result to the type of the temporary. */ r = adjust_temp_type (TREE_TYPE (t), r); if (addr) { tree slot = TARGET_EXPR_SLOT (t); ctx->values->put (slot, r); return slot; } break; case INIT_EXPR: if (!use_new_call) { /* In C++11 constexpr evaluation we are looking for the value, not the side-effect of the initialization. */ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), false, non_constant_p, overflow_p); break; } /* else fall through */ case MODIFY_EXPR: r = cxx_eval_store_expression (ctx, t, addr, non_constant_p, overflow_p); break; case SCOPE_REF: r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), addr, non_constant_p, overflow_p); break; case RETURN_EXPR: r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), addr, non_constant_p, overflow_p); *jump_target = t; break; case SAVE_EXPR: /* Avoid evaluating a SAVE_EXPR more than once. */ if (tree *p = ctx->values->get (t)) r = *p; else { r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), addr, non_constant_p, overflow_p); ctx->values->put (t, r); } break; case NON_LVALUE_EXPR: case TRY_CATCH_EXPR: case CLEANUP_POINT_EXPR: case MUST_NOT_THROW_EXPR: case EXPR_STMT: case EH_SPEC_BLOCK: r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), addr, non_constant_p, overflow_p, jump_target); break; /* These differ from cxx_eval_unary_expression in that this doesn't check for a constant operand or result; an address can be constant without its operand being, and vice versa. */ case INDIRECT_REF: r = cxx_eval_indirect_ref (ctx, t, addr, non_constant_p, overflow_p); break; case ADDR_EXPR: { tree oldop = TREE_OPERAND (t, 0); tree op = cxx_eval_constant_expression (ctx, oldop, /*addr*/true, non_constant_p, overflow_p); /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p) return t; gcc_checking_assert (TREE_CODE (op) != CONSTRUCTOR); /* This function does more aggressive folding than fold itself. */ r = build_fold_addr_expr_with_type (op, TREE_TYPE (t)); if (TREE_CODE (r) == ADDR_EXPR && TREE_OPERAND (r, 0) == oldop) return t; break; } case REALPART_EXPR: case IMAGPART_EXPR: case CONJ_EXPR: case FIX_TRUNC_EXPR: case FLOAT_EXPR: case NEGATE_EXPR: case ABS_EXPR: case BIT_NOT_EXPR: case TRUTH_NOT_EXPR: case FIXED_CONVERT_EXPR: r = cxx_eval_unary_expression (ctx, t, addr, non_constant_p, overflow_p); break; case SIZEOF_EXPR: if (SIZEOF_EXPR_TYPE_P (t)) r = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (t, 0)), SIZEOF_EXPR, false); else if (TYPE_P (TREE_OPERAND (t, 0))) r = cxx_sizeof_or_alignof_type (TREE_OPERAND (t, 0), SIZEOF_EXPR, false); else r = cxx_sizeof_or_alignof_expr (TREE_OPERAND (t, 0), SIZEOF_EXPR, false); if (r == error_mark_node) r = size_one_node; VERIFY_CONSTANT (r); break; case COMPOUND_EXPR: { /* check_return_expr sometimes wraps a TARGET_EXPR in a COMPOUND_EXPR; don't get confused. Also handle EMPTY_CLASS_EXPR introduced by build_call_a. */ tree op0 = TREE_OPERAND (t, 0); tree op1 = TREE_OPERAND (t, 1); STRIP_NOPS (op1); if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0)) || TREE_CODE (op1) == EMPTY_CLASS_EXPR) r = cxx_eval_constant_expression (ctx, op0, addr, non_constant_p, overflow_p, jump_target); else { /* Check that the LHS is constant and then discard it. */ cxx_eval_constant_expression (ctx, op0, false, non_constant_p, overflow_p, jump_target); op1 = TREE_OPERAND (t, 1); r = cxx_eval_constant_expression (ctx, op1, addr, non_constant_p, overflow_p, jump_target); } } break; case POINTER_PLUS_EXPR: case PLUS_EXPR: case MINUS_EXPR: case MULT_EXPR: case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: case ROUND_DIV_EXPR: case TRUNC_MOD_EXPR: case CEIL_MOD_EXPR: case ROUND_MOD_EXPR: case RDIV_EXPR: case EXACT_DIV_EXPR: case MIN_EXPR: case MAX_EXPR: case LSHIFT_EXPR: case RSHIFT_EXPR: case LROTATE_EXPR: case RROTATE_EXPR: case BIT_IOR_EXPR: case BIT_XOR_EXPR: case BIT_AND_EXPR: case TRUTH_XOR_EXPR: case LT_EXPR: case LE_EXPR: case GT_EXPR: case GE_EXPR: case EQ_EXPR: case NE_EXPR: case UNORDERED_EXPR: case ORDERED_EXPR: case UNLT_EXPR: case UNLE_EXPR: case UNGT_EXPR: case UNGE_EXPR: case UNEQ_EXPR: case LTGT_EXPR: case RANGE_EXPR: case COMPLEX_EXPR: r = cxx_eval_binary_expression (ctx, t, addr, non_constant_p, overflow_p); break; /* fold can introduce non-IF versions of these; still treat them as short-circuiting. */ case TRUTH_AND_EXPR: case TRUTH_ANDIF_EXPR: r = cxx_eval_logical_expression (ctx, t, boolean_false_node, boolean_true_node, addr, non_constant_p, overflow_p); break; case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR: r = cxx_eval_logical_expression (ctx, t, boolean_true_node, boolean_false_node, addr, non_constant_p, overflow_p); break; case ARRAY_REF: r = cxx_eval_array_reference (ctx, t, addr, non_constant_p, overflow_p); break; case COMPONENT_REF: if (is_overloaded_fn (t)) { /* We can only get here in checking mode via build_non_dependent_expr, because any expression that calls or takes the address of the function will have pulled a FUNCTION_DECL out of the COMPONENT_REF. */ gcc_checking_assert (ctx->quiet || errorcount); *non_constant_p = true; return t; } r = cxx_eval_component_reference (ctx, t, addr, non_constant_p, overflow_p); break; case BIT_FIELD_REF: r = cxx_eval_bit_field_ref (ctx, t, addr, non_constant_p, overflow_p); break; case COND_EXPR: case VEC_COND_EXPR: r = cxx_eval_conditional_expression (ctx, t, addr, non_constant_p, overflow_p, jump_target); break; case CONSTRUCTOR: r = cxx_eval_bare_aggregate (ctx, t, addr, non_constant_p, overflow_p); break; case VEC_INIT_EXPR: /* We can get this in a defaulted constructor for a class with a non-static data member of array type. Either the initializer will be NULL, meaning default-initialization, or it will be an lvalue or xvalue of the same type, meaning direct-initialization from the corresponding member. */ r = cxx_eval_vec_init (ctx, t, addr, non_constant_p, overflow_p); break; case FMA_EXPR: case VEC_PERM_EXPR: r = cxx_eval_trinary_expression (ctx, t, addr, non_constant_p, overflow_p); break; case CONVERT_EXPR: case VIEW_CONVERT_EXPR: case NOP_EXPR: { tree oldop = TREE_OPERAND (t, 0); tree op = cxx_eval_constant_expression (ctx, oldop, addr, non_constant_p, overflow_p); if (*non_constant_p) return t; if (POINTER_TYPE_P (TREE_TYPE (t)) && TREE_CODE (op) == INTEGER_CST && !integer_zerop (op)) { if (!ctx->quiet) error_at (EXPR_LOC_OR_LOC (t, input_location), "reinterpret_cast from integer to pointer"); *non_constant_p = true; return t; } if (op == oldop) /* We didn't fold at the top so we could check for ptr-int conversion. */ return fold (t); r = fold_build1 (TREE_CODE (t), TREE_TYPE (t), op); /* Conversion of an out-of-range value has implementation-defined behavior; the language considers it different from arithmetic overflow, which is undefined. */ if (TREE_OVERFLOW_P (r) && !TREE_OVERFLOW_P (op)) TREE_OVERFLOW (r) = false; } break; case EMPTY_CLASS_EXPR: /* This is good enough for a function argument that might not get used, and they can't do anything with it, so just return it. */ return t; case STATEMENT_LIST: new_ctx = *ctx; new_ctx.ctor = new_ctx.object = NULL_TREE; return cxx_eval_statement_list (&new_ctx, t, non_constant_p, overflow_p, jump_target); case BIND_EXPR: return cxx_eval_constant_expression (ctx, BIND_EXPR_BODY (t), addr, non_constant_p, overflow_p, jump_target); case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: return cxx_eval_increment_expression (ctx, t, addr, non_constant_p, overflow_p); case LAMBDA_EXPR: case NEW_EXPR: case VEC_NEW_EXPR: case DELETE_EXPR: case VEC_DELETE_EXPR: case THROW_EXPR: case MODOP_EXPR: /* GCC internal stuff. */ case VA_ARG_EXPR: case OBJ_TYPE_REF: case WITH_CLEANUP_EXPR: case NON_DEPENDENT_EXPR: case BASELINK: case OFFSET_REF: if (!ctx->quiet) error_at (EXPR_LOC_OR_LOC (t, input_location), "expression %qE is not a constant-expression", t); *non_constant_p = true; break; case PLACEHOLDER_EXPR: if (!ctx || !ctx->ctor || (addr && !ctx->object)) { /* A placeholder without a referent. We can get here when checking whether NSDMIs are noexcept, or in massage_init_elt; just say it's non-constant for now. */ gcc_assert (ctx->quiet); *non_constant_p = true; break; } else { /* Use of the value or address of the current object. We could use ctx->object unconditionally, but using ctx->ctor when we can is a minor optimization. */ tree ctor = addr ? ctx->object : ctx->ctor; gcc_assert (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (t), TREE_TYPE (ctor))); return cxx_eval_constant_expression (ctx, ctor, addr, non_constant_p, overflow_p); } break; case GOTO_EXPR: *jump_target = TREE_OPERAND (t, 0); gcc_assert (breaks (jump_target) || continues (jump_target)); break; case LOOP_EXPR: cxx_eval_loop_expr (ctx, t, non_constant_p, overflow_p, jump_target); break; case SWITCH_EXPR: cxx_eval_switch_expr (ctx, t, non_constant_p, overflow_p, jump_target); break; default: internal_error ("unexpected expression %qE of kind %s", t, get_tree_code_name (TREE_CODE (t))); *non_constant_p = true; break; } if (r == error_mark_node) *non_constant_p = true; if (*non_constant_p) return t; else return r; } static tree cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, bool strict = true, tree object = NULL_TREE) { bool non_constant_p = false; bool overflow_p = false; constexpr_ctx ctx = { NULL, NULL, NULL, NULL, allow_non_constant, strict }; hash_map map; ctx.values = ↦ tree type = initialized_type (t); tree r = t; if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type)) { /* In C++14 an NSDMI can participate in aggregate initialization, and can refer to the address of the object being initialized, so we need to pass in the relevant VAR_DECL if we want to do the evaluation in a single pass. The evaluation will dynamically update ctx.values for the VAR_DECL. We use the same strategy for C++11 constexpr constructors that refer to the object being initialized. */ ctx.ctor = build_constructor (type, NULL); CONSTRUCTOR_NO_IMPLICIT_ZERO (ctx.ctor) = true; if (!object) { if (TREE_CODE (t) == TARGET_EXPR) object = TARGET_EXPR_SLOT (t); else if (TREE_CODE (t) == AGGR_INIT_EXPR) object = AGGR_INIT_EXPR_SLOT (t); } ctx.object = object; if (object) gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (object))); if (object && DECL_P (object)) map.put (object, ctx.ctor); if (TREE_CODE (r) == TARGET_EXPR) /* Avoid creating another CONSTRUCTOR when we expand the TARGET_EXPR. */ r = TARGET_EXPR_INITIAL (r); } r = cxx_eval_constant_expression (&ctx, r, false, &non_constant_p, &overflow_p); verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); /* Mutable logic is a bit tricky: we want to allow initialization of constexpr variables with mutable members, but we can't copy those members to another constexpr variable. */ if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_MUTABLE_POISON (r)) { if (!allow_non_constant) error ("%qE is not a constant expression because it refers to " "mutable subobjects of %qT", t, type); non_constant_p = true; } /* Technically we should check this for all subexpressions, but that runs into problems with our internal representation of pointer subtraction and the 5.19 rules are still in flux. */ if (CONVERT_EXPR_CODE_P (TREE_CODE (r)) && ARITHMETIC_TYPE_P (TREE_TYPE (r)) && TREE_CODE (TREE_OPERAND (r, 0)) == ADDR_EXPR) { if (!allow_non_constant) error ("conversion from pointer type %qT " "to arithmetic type %qT in a constant-expression", TREE_TYPE (TREE_OPERAND (r, 0)), TREE_TYPE (r)); non_constant_p = true; } if (!non_constant_p && overflow_p) non_constant_p = true; if (non_constant_p && !allow_non_constant) return error_mark_node; else if (non_constant_p && TREE_CONSTANT (r)) { /* This isn't actually constant, so unset TREE_CONSTANT. */ if (EXPR_P (r)) r = copy_node (r); else if (TREE_CODE (r) == CONSTRUCTOR) r = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (r), r); else r = build_nop (TREE_TYPE (r), r); TREE_CONSTANT (r) = false; } else if (non_constant_p || r == t) return t; if (TREE_CODE (r) == CONSTRUCTOR && CLASS_TYPE_P (TREE_TYPE (r))) { if (TREE_CODE (t) == TARGET_EXPR && TARGET_EXPR_INITIAL (t) == r) return t; else { r = get_target_expr (r); TREE_CONSTANT (r) = true; return r; } } else return r; } /* Returns true if T is a valid subexpression of a constant expression, even if it isn't itself a constant expression. */ bool is_sub_constant_expr (tree t) { bool non_constant_p = false; bool overflow_p = false; constexpr_ctx ctx = { NULL, NULL, NULL, NULL, true, true }; hash_map map; ctx.values = ↦ cxx_eval_constant_expression (&ctx, t, false, &non_constant_p, &overflow_p); return !non_constant_p && !overflow_p; } /* If T represents a constant expression returns its reduced value. Otherwise return error_mark_node. If T is dependent, then return NULL. */ tree cxx_constant_value (tree t, tree decl) { return cxx_eval_outermost_constant_expr (t, false, true, decl); } /* If T is a constant expression, returns its reduced value. Otherwise, if T does not have TREE_CONSTANT set, returns T. Otherwise, returns a version of T without TREE_CONSTANT. */ tree maybe_constant_value (tree t, tree decl) { tree r; if (instantiation_dependent_expression_p (t) || type_unknown_p (t) || BRACE_ENCLOSED_INITIALIZER_P (t) || !potential_constant_expression (t)) { if (TREE_OVERFLOW_P (t)) { t = build_nop (TREE_TYPE (t), t); TREE_CONSTANT (t) = false; } return t; } r = cxx_eval_outermost_constant_expr (t, true, true, decl); #ifdef ENABLE_CHECKING /* cp_tree_equal looks through NOPs, so allow them. */ gcc_assert (r == t || CONVERT_EXPR_P (t) || TREE_CODE (t) == VIEW_CONVERT_EXPR || (TREE_CONSTANT (t) && !TREE_CONSTANT (r)) || !cp_tree_equal (r, t)); #endif return r; } /* Like maybe_constant_value but first fully instantiate the argument. Note: this is equivalent to instantiate_non_dependent_expr_sfinae (t, tf_none) followed by maybe_constant_value but is more efficient, because calls instantiation_dependent_expression_p and potential_constant_expression at most once. */ tree fold_non_dependent_expr (tree t) { if (t == NULL_TREE) return NULL_TREE; /* If we're in a template, but T isn't value dependent, simplify it. We're supposed to treat: template void f(T[1 + 1]); template void f(T[2]); as two declarations of the same function, for example. */ if (processing_template_decl) { if (!instantiation_dependent_expression_p (t) && potential_constant_expression (t)) { processing_template_decl_sentinel s; t = instantiate_non_dependent_expr_internal (t, tf_none); if (type_unknown_p (t) || BRACE_ENCLOSED_INITIALIZER_P (t)) { if (TREE_OVERFLOW_P (t)) { t = build_nop (TREE_TYPE (t), t); TREE_CONSTANT (t) = false; } return t; } tree r = cxx_eval_outermost_constant_expr (t, true, true, NULL_TREE); #ifdef ENABLE_CHECKING /* cp_tree_equal looks through NOPs, so allow them. */ gcc_assert (r == t || CONVERT_EXPR_P (t) || TREE_CODE (t) == VIEW_CONVERT_EXPR || (TREE_CONSTANT (t) && !TREE_CONSTANT (r)) || !cp_tree_equal (r, t)); #endif return r; } else if (TREE_OVERFLOW_P (t)) { t = build_nop (TREE_TYPE (t), t); TREE_CONSTANT (t) = false; } return t; } return maybe_constant_value (t); } /* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather than wrapped in a TARGET_EXPR. */ tree maybe_constant_init (tree t, tree decl) { if (TREE_CODE (t) == EXPR_STMT) t = TREE_OPERAND (t, 0); if (TREE_CODE (t) == CONVERT_EXPR && VOID_TYPE_P (TREE_TYPE (t))) t = TREE_OPERAND (t, 0); if (TREE_CODE (t) == INIT_EXPR) t = TREE_OPERAND (t, 1); if (instantiation_dependent_expression_p (t) || type_unknown_p (t) || BRACE_ENCLOSED_INITIALIZER_P (t) || !potential_static_init_expression (t)) /* Don't try to evaluate it. */; else t = cxx_eval_outermost_constant_expr (t, true, false, decl); if (TREE_CODE (t) == TARGET_EXPR) { tree init = TARGET_EXPR_INITIAL (t); if (TREE_CODE (init) == CONSTRUCTOR) t = init; } return t; } #if 0 /* FIXME see ADDR_EXPR section in potential_constant_expression_1. */ /* Return true if the object referred to by REF has automatic or thread local storage. */ enum { ck_ok, ck_bad, ck_unknown }; static int check_automatic_or_tls (tree ref) { machine_mode mode; HOST_WIDE_INT bitsize, bitpos; tree offset; int volatilep = 0, unsignedp = 0; tree decl = get_inner_reference (ref, &bitsize, &bitpos, &offset, &mode, &unsignedp, &volatilep, false); duration_kind dk; /* If there isn't a decl in the middle, we don't know the linkage here, and this isn't a constant expression anyway. */ if (!DECL_P (decl)) return ck_unknown; dk = decl_storage_duration (decl); return (dk == dk_auto || dk == dk_thread) ? ck_bad : ck_ok; } #endif /* Return true if T denotes a potentially constant expression. Issue diagnostic as appropriate under control of FLAGS. If WANT_RVAL is true, an lvalue-rvalue conversion is implied. C++0x [expr.const] used to say 6 An expression is a potential constant expression if it is a constant expression where all occurrences of function parameters are replaced by arbitrary constant expressions of the appropriate type. 2 A conditional expression is a constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2), but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered. */ static bool potential_constant_expression_1 (tree t, bool want_rval, bool strict, tsubst_flags_t flags) { #define RECUR(T,RV) potential_constant_expression_1 ((T), (RV), strict, flags) enum { any = false, rval = true }; int i; tree tmp; if (t == error_mark_node) return false; if (t == NULL_TREE) return true; if (TREE_THIS_VOLATILE (t)) { if (flags & tf_error) error ("expression %qE has side-effects", t); return false; } if (CONSTANT_CLASS_P (t)) return true; switch (TREE_CODE (t)) { case FUNCTION_DECL: case BASELINK: case TEMPLATE_DECL: case OVERLOAD: case TEMPLATE_ID_EXPR: case LABEL_DECL: case LABEL_EXPR: case CASE_LABEL_EXPR: case CONST_DECL: case SIZEOF_EXPR: case ALIGNOF_EXPR: case OFFSETOF_EXPR: case NOEXCEPT_EXPR: case TEMPLATE_PARM_INDEX: case TRAIT_EXPR: case IDENTIFIER_NODE: case USERDEF_LITERAL: /* We can see a FIELD_DECL in a pointer-to-member expression. */ case FIELD_DECL: case PARM_DECL: case USING_DECL: case USING_STMT: case PLACEHOLDER_EXPR: case BREAK_STMT: case CONTINUE_STMT: return true; case AGGR_INIT_EXPR: case CALL_EXPR: /* -- an invocation of a function other than a constexpr function or a constexpr constructor. */ { tree fun = get_function_named_in_call (t); const int nargs = call_expr_nargs (t); i = 0; if (fun == NULL_TREE) { /* fold_call_expr can't do anything with IFN calls. */ if (flags & tf_error) error_at (EXPR_LOC_OR_LOC (t, input_location), "call to internal function"); return false; } if (is_overloaded_fn (fun)) { if (TREE_CODE (fun) == FUNCTION_DECL) { if (builtin_valid_in_constant_expr_p (fun)) return true; if (!DECL_DECLARED_CONSTEXPR_P (fun) /* Allow any built-in function; if the expansion isn't constant, we'll deal with that then. */ && !is_builtin_fn (fun)) { if (flags & tf_error) { error_at (EXPR_LOC_OR_LOC (t, input_location), "call to non-constexpr function %qD", fun); explain_invalid_constexpr_fn (fun); } return false; } /* A call to a non-static member function takes the address of the object as the first argument. But in a constant expression the address will be folded away, so look through it now. */ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun) && !DECL_CONSTRUCTOR_P (fun)) { tree x = get_nth_callarg (t, 0); if (is_this_parameter (x)) return true; else if (!RECUR (x, rval)) return false; i = 1; } } else { if (!RECUR (fun, true)) return false; fun = get_first_fn (fun); } /* Skip initial arguments to base constructors. */ if (DECL_BASE_CONSTRUCTOR_P (fun)) i = num_artificial_parms_for (fun); fun = DECL_ORIGIN (fun); } else { if (RECUR (fun, rval)) /* Might end up being a constant function pointer. */; else return false; } for (; i < nargs; ++i) { tree x = get_nth_callarg (t, i); if (!RECUR (x, rval)) return false; } return true; } case NON_LVALUE_EXPR: /* -- an lvalue-to-rvalue conversion (4.1) unless it is applied to -- an lvalue of integral type that refers to a non-volatile const variable or static data member initialized with constant expressions, or -- an lvalue of literal type that refers to non-volatile object defined with constexpr, or that refers to a sub-object of such an object; */ return RECUR (TREE_OPERAND (t, 0), rval); case VAR_DECL: if (want_rval && !decl_constant_var_p (t) && (strict || !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (t)) || !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t)) && !var_in_constexpr_fn (t) && !dependent_type_p (TREE_TYPE (t))) { if (flags & tf_error) non_const_var_error (t); return false; } return true; case NOP_EXPR: case CONVERT_EXPR: case VIEW_CONVERT_EXPR: /* -- a reinterpret_cast. FIXME not implemented, and this rule may change to something more specific to type-punning (DR 1312). */ { tree from = TREE_OPERAND (t, 0); if (POINTER_TYPE_P (TREE_TYPE (t)) && TREE_CODE (from) == INTEGER_CST && !integer_zerop (from)) { if (flags & tf_error) error_at (EXPR_LOC_OR_LOC (t, input_location), "reinterpret_cast from integer to pointer"); return false; } return (RECUR (from, TREE_CODE (t) != VIEW_CONVERT_EXPR)); } case ADDR_EXPR: /* -- a unary operator & that is applied to an lvalue that designates an object with thread or automatic storage duration; */ t = TREE_OPERAND (t, 0); if (TREE_CODE (t) == OFFSET_REF && PTRMEM_OK_P (t)) /* A pointer-to-member constant. */ return true; #if 0 /* FIXME adjust when issue 1197 is fully resolved. For now don't do any checking here, as we might dereference the pointer later. If we remove this code, also remove check_automatic_or_tls. */ i = check_automatic_or_tls (t); if (i == ck_ok) return true; if (i == ck_bad) { if (flags & tf_error) error ("address-of an object %qE with thread local or " "automatic storage is not a constant expression", t); return false; } #endif return RECUR (t, any); case COMPONENT_REF: case BIT_FIELD_REF: case ARROW_EXPR: case OFFSET_REF: /* -- a class member access unless its postfix-expression is of literal type or of pointer to literal type. */ /* This test would be redundant, as it follows from the postfix-expression being a potential constant expression. */ return RECUR (TREE_OPERAND (t, 0), want_rval); case EXPR_PACK_EXPANSION: return RECUR (PACK_EXPANSION_PATTERN (t), want_rval); case INDIRECT_REF: { tree x = TREE_OPERAND (t, 0); STRIP_NOPS (x); if (is_this_parameter (x)) { if (DECL_CONTEXT (x) && !DECL_DECLARED_CONSTEXPR_P (DECL_CONTEXT (x))) { if (flags & tf_error) error ("use of % in a constant expression"); return false; } return true; } return RECUR (x, rval); } case STATEMENT_LIST: { tree_stmt_iterator i; for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) { if (!RECUR (tsi_stmt (i), any)) return false; } return true; } break; case MODIFY_EXPR: if (cxx_dialect < cxx14) goto fail; if (!RECUR (TREE_OPERAND (t, 0), any)) return false; if (!RECUR (TREE_OPERAND (t, 1), rval)) return false; return true; case MODOP_EXPR: if (cxx_dialect < cxx14) goto fail; if (!RECUR (TREE_OPERAND (t, 0), rval)) return false; if (!RECUR (TREE_OPERAND (t, 2), rval)) return false; return true; case IF_STMT: if (!RECUR (IF_COND (t), rval)) return false; if (!RECUR (THEN_CLAUSE (t), any)) return false; if (!RECUR (ELSE_CLAUSE (t), any)) return false; return true; case DO_STMT: if (!RECUR (DO_COND (t), rval)) return false; if (!RECUR (DO_BODY (t), any)) return false; return true; case FOR_STMT: if (!RECUR (FOR_INIT_STMT (t), any)) return false; if (!RECUR (FOR_COND (t), rval)) return false; if (!RECUR (FOR_EXPR (t), any)) return false; if (!RECUR (FOR_BODY (t), any)) return false; return true; case WHILE_STMT: if (!RECUR (WHILE_COND (t), rval)) return false; if (!RECUR (WHILE_BODY (t), any)) return false; return true; case SWITCH_STMT: if (!RECUR (SWITCH_STMT_COND (t), rval)) return false; if (!RECUR (SWITCH_STMT_BODY (t), any)) return false; return true; case STMT_EXPR: return RECUR (STMT_EXPR_STMT (t), rval); case LAMBDA_EXPR: case DYNAMIC_CAST_EXPR: case PSEUDO_DTOR_EXPR: case NEW_EXPR: case VEC_NEW_EXPR: case DELETE_EXPR: case VEC_DELETE_EXPR: case THROW_EXPR: case OMP_ATOMIC: case OMP_ATOMIC_READ: case OMP_ATOMIC_CAPTURE_OLD: case OMP_ATOMIC_CAPTURE_NEW: /* GCC internal stuff. */ case VA_ARG_EXPR: case OBJ_TYPE_REF: case TRANSACTION_EXPR: case ASM_EXPR: fail: if (flags & tf_error) error ("expression %qE is not a constant-expression", t); return false; case TYPEID_EXPR: /* -- a typeid expression whose operand is of polymorphic class type; */ { tree e = TREE_OPERAND (t, 0); if (!TYPE_P (e) && !type_dependent_expression_p (e) && TYPE_POLYMORPHIC_P (TREE_TYPE (e))) { if (flags & tf_error) error ("typeid-expression is not a constant expression " "because %qE is of polymorphic type", e); return false; } return true; } case MINUS_EXPR: /* -- a subtraction where both operands are pointers. */ if (TYPE_PTR_P (TREE_OPERAND (t, 0)) && TYPE_PTR_P (TREE_OPERAND (t, 1))) { if (flags & tf_error) error ("difference of two pointer expressions is not " "a constant expression"); return false; } want_rval = true; goto binary; case LT_EXPR: case LE_EXPR: case GT_EXPR: case GE_EXPR: case EQ_EXPR: case NE_EXPR: /* -- a relational or equality operator where at least one of the operands is a pointer. */ if (TYPE_PTR_P (TREE_OPERAND (t, 0)) || TYPE_PTR_P (TREE_OPERAND (t, 1))) { if (flags & tf_error) error ("pointer comparison expression is not a " "constant expression"); return false; } want_rval = true; goto binary; case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: if (cxx_dialect < cxx14) goto fail; goto unary; case BIT_NOT_EXPR: /* A destructor. */ if (TYPE_P (TREE_OPERAND (t, 0))) return true; /* else fall through. */ case REALPART_EXPR: case IMAGPART_EXPR: case CONJ_EXPR: case SAVE_EXPR: case FIX_TRUNC_EXPR: case FLOAT_EXPR: case NEGATE_EXPR: case ABS_EXPR: case TRUTH_NOT_EXPR: case FIXED_CONVERT_EXPR: case UNARY_PLUS_EXPR: unary: return RECUR (TREE_OPERAND (t, 0), rval); case CAST_EXPR: case CONST_CAST_EXPR: case STATIC_CAST_EXPR: case REINTERPRET_CAST_EXPR: case IMPLICIT_CONV_EXPR: if (cxx_dialect < cxx11 && !dependent_type_p (TREE_TYPE (t)) && !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (t))) /* In C++98, a conversion to non-integral type can't be part of a constant expression. */ { if (flags & tf_error) error ("cast to non-integral type %qT in a constant expression", TREE_TYPE (t)); return false; } return (RECUR (TREE_OPERAND (t, 0), TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)); case BIND_EXPR: return RECUR (BIND_EXPR_BODY (t), want_rval); case WITH_CLEANUP_EXPR: case CLEANUP_POINT_EXPR: case MUST_NOT_THROW_EXPR: case TRY_CATCH_EXPR: case EH_SPEC_BLOCK: case EXPR_STMT: case PAREN_EXPR: case DECL_EXPR: case NON_DEPENDENT_EXPR: /* For convenience. */ case RETURN_EXPR: return RECUR (TREE_OPERAND (t, 0), want_rval); case SCOPE_REF: return RECUR (TREE_OPERAND (t, 1), want_rval); case TARGET_EXPR: if (!literal_type_p (TREE_TYPE (t))) { if (flags & tf_error) { error ("temporary of non-literal type %qT in a " "constant expression", TREE_TYPE (t)); explain_non_literal_class (TREE_TYPE (t)); } return false; } case INIT_EXPR: return RECUR (TREE_OPERAND (t, 1), rval); case CONSTRUCTOR: { vec *v = CONSTRUCTOR_ELTS (t); constructor_elt *ce; for (i = 0; vec_safe_iterate (v, i, &ce); ++i) if (!RECUR (ce->value, want_rval)) return false; return true; } case TREE_LIST: { gcc_assert (TREE_PURPOSE (t) == NULL_TREE || DECL_P (TREE_PURPOSE (t))); if (!RECUR (TREE_VALUE (t), want_rval)) return false; if (TREE_CHAIN (t) == NULL_TREE) return true; return RECUR (TREE_CHAIN (t), want_rval); } case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: case ROUND_DIV_EXPR: case TRUNC_MOD_EXPR: case CEIL_MOD_EXPR: case ROUND_MOD_EXPR: { tree denom = TREE_OPERAND (t, 1); if (!RECUR (denom, rval)) return false; /* We can't call cxx_eval_outermost_constant_expr on an expression that hasn't been through instantiate_non_dependent_expr yet. */ if (!processing_template_decl) denom = cxx_eval_outermost_constant_expr (denom, true); if (integer_zerop (denom)) { if (flags & tf_error) error ("division by zero is not a constant-expression"); return false; } else { want_rval = true; return RECUR (TREE_OPERAND (t, 0), want_rval); } } case COMPOUND_EXPR: { /* check_return_expr sometimes wraps a TARGET_EXPR in a COMPOUND_EXPR; don't get confused. Also handle EMPTY_CLASS_EXPR introduced by build_call_a. */ tree op0 = TREE_OPERAND (t, 0); tree op1 = TREE_OPERAND (t, 1); STRIP_NOPS (op1); if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0)) || TREE_CODE (op1) == EMPTY_CLASS_EXPR) return RECUR (op0, want_rval); else goto binary; } /* If the first operand is the non-short-circuit constant, look at the second operand; otherwise we only care about the first one for potentiality. */ case TRUTH_AND_EXPR: case TRUTH_ANDIF_EXPR: tmp = boolean_true_node; goto truth; case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR: tmp = boolean_false_node; truth: { tree op = TREE_OPERAND (t, 0); if (!RECUR (op, rval)) return false; if (!processing_template_decl) op = cxx_eval_outermost_constant_expr (op, true); if (tree_int_cst_equal (op, tmp)) return RECUR (TREE_OPERAND (t, 1), rval); else return true; } case PLUS_EXPR: case MULT_EXPR: case POINTER_PLUS_EXPR: case RDIV_EXPR: case EXACT_DIV_EXPR: case MIN_EXPR: case MAX_EXPR: case LSHIFT_EXPR: case RSHIFT_EXPR: case LROTATE_EXPR: case RROTATE_EXPR: case BIT_IOR_EXPR: case BIT_XOR_EXPR: case BIT_AND_EXPR: case TRUTH_XOR_EXPR: case UNORDERED_EXPR: case ORDERED_EXPR: case UNLT_EXPR: case UNLE_EXPR: case UNGT_EXPR: case UNGE_EXPR: case UNEQ_EXPR: case LTGT_EXPR: case RANGE_EXPR: case COMPLEX_EXPR: want_rval = true; /* Fall through. */ case ARRAY_REF: case ARRAY_RANGE_REF: case MEMBER_REF: case DOTSTAR_EXPR: binary: for (i = 0; i < 2; ++i) if (!RECUR (TREE_OPERAND (t, i), want_rval)) return false; return true; case CILK_SYNC_STMT: case CILK_SPAWN_STMT: case ARRAY_NOTATION_REF: return false; case FMA_EXPR: case VEC_PERM_EXPR: for (i = 0; i < 3; ++i) if (!RECUR (TREE_OPERAND (t, i), true)) return false; return true; case COND_EXPR: case VEC_COND_EXPR: /* If the condition is a known constant, we know which of the legs we care about; otherwise we only require that the condition and either of the legs be potentially constant. */ tmp = TREE_OPERAND (t, 0); if (!RECUR (tmp, rval)) return false; if (!processing_template_decl) tmp = cxx_eval_outermost_constant_expr (tmp, true); if (integer_zerop (tmp)) return RECUR (TREE_OPERAND (t, 2), want_rval); else if (TREE_CODE (tmp) == INTEGER_CST) return RECUR (TREE_OPERAND (t, 1), want_rval); for (i = 1; i < 3; ++i) if (potential_constant_expression_1 (TREE_OPERAND (t, i), want_rval, strict, tf_none)) return true; if (flags & tf_error) error ("expression %qE is not a constant-expression", t); return false; case VEC_INIT_EXPR: if (VEC_INIT_EXPR_IS_CONSTEXPR (t)) return true; if (flags & tf_error) { error ("non-constant array initialization"); diagnose_non_constexpr_vec_init (t); } return false; default: if (objc_is_property_ref (t)) return false; sorry ("unexpected AST of kind %s", get_tree_code_name (TREE_CODE (t))); gcc_unreachable(); return false; } #undef RECUR } /* The main entry point to the above. */ bool potential_constant_expression (tree t) { return potential_constant_expression_1 (t, false, true, tf_none); } bool potential_static_init_expression (tree t) { return potential_constant_expression_1 (t, false, false, tf_none); } /* As above, but require a constant rvalue. */ bool potential_rvalue_constant_expression (tree t) { return potential_constant_expression_1 (t, true, true, tf_none); } /* Like above, but complain about non-constant expressions. */ bool require_potential_constant_expression (tree t) { return potential_constant_expression_1 (t, false, true, tf_warning_or_error); } /* Cross product of the above. */ bool require_potential_rvalue_constant_expression (tree t) { return potential_constant_expression_1 (t, true, true, tf_warning_or_error); } #include "gt-cp-constexpr.h"