diff options
author | Jason Merrill <jason@gcc.gnu.org> | 2010-11-01 21:30:51 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2010-11-01 21:30:51 -0400 |
commit | 66e61a34b5ba3d0748578bb553d9ef15202eee9f (patch) | |
tree | cee12743618f7b54280bbe28abf0374e6e46b7e0 /gcc/cp | |
parent | aef4a21519866e460d2baa161a402164af67547d (diff) | |
download | gcc-66e61a34b5ba3d0748578bb553d9ef15202eee9f.zip gcc-66e61a34b5ba3d0748578bb553d9ef15202eee9f.tar.gz gcc-66e61a34b5ba3d0748578bb553d9ef15202eee9f.tar.bz2 |
cp-tree.h (register_constexpr_fundef): Declare.
* cp-tree.h (register_constexpr_fundef): Declare.
* decl.c (maybe_save_function_definition): New.
(finish_function): Use it.
* semantics.c (constexpr_fundef): New datatype.
(constexpr_fundef_table): New global table.
(constexpr_fundef_equal): New.
(constexpr_fundef_hash): Likewise.
(retrieve_constexpr_fundef): Likewise.
(validate_constexpr_fundecl): Store in the table.
(build_data_member_initialization): New fn.
(build_constexpr_constructor_member_initializers): New.
(register_constexpr_fundef): Define.
(is_this_parameter): New.
(get_function_named_in_call): Likewise.
(get_nth_callarg): Likewise.
(check_automatic_or_tls): New.
(morally_constexpr_builtin_function_p): New.
(potential_constant_expression): New.
From-SVN: r166165
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 22 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/decl.c | 17 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 726 |
4 files changed, 766 insertions, 0 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2646839..f790525 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,25 @@ +2010-11-01 Gabriel Dos Reis <gdr@cse.tamu.edu> + Jason Merrill <jason@redhat.com> + + * cp-tree.h (register_constexpr_fundef): Declare. + * decl.c (maybe_save_function_definition): New. + (finish_function): Use it. + * semantics.c (constexpr_fundef): New datatype. + (constexpr_fundef_table): New global table. + (constexpr_fundef_equal): New. + (constexpr_fundef_hash): Likewise. + (retrieve_constexpr_fundef): Likewise. + (validate_constexpr_fundecl): Store in the table. + (build_data_member_initialization): New fn. + (build_constexpr_constructor_member_initializers): New. + (register_constexpr_fundef): Define. + (is_this_parameter): New. + (get_function_named_in_call): Likewise. + (get_nth_callarg): Likewise. + (check_automatic_or_tls): New. + (morally_constexpr_builtin_function_p): New. + (potential_constant_expression): New. + 2010-11-01 Jason Merrill <jason@redhat.com> * decl2.c (decl_constant_var_p): New fn. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bc4eb46..4dfa8e9 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5252,6 +5252,7 @@ extern void finish_handler (tree); extern void finish_cleanup (tree, tree); extern bool literal_type_p (tree); extern tree validate_constexpr_fundecl (tree); +extern tree register_constexpr_fundef (tree, tree); extern tree ensure_literal_type_for_constexpr_object (tree); enum { diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b7ab080f..de6f0c4f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -12667,6 +12667,19 @@ record_key_method_defined (tree fndecl) } } +/* Subroutine of finish_function. + Save the body of constexpr functions for possible + future compile time evaluation. */ + +static void +maybe_save_function_definition (tree fun) +{ + if (!processing_template_decl + && DECL_DECLARED_CONSTEXPR_P (fun) + && !DECL_CLONED_FUNCTION_P (fun)) + register_constexpr_fundef (fun, DECL_SAVED_TREE (fun)); +} + /* Finish up a function declaration and compile that function all the way to assembler language output. The free the storage for the function definition. @@ -12778,6 +12791,10 @@ finish_function (int flags) of curly braces for a function. */ gcc_assert (stmts_are_full_exprs_p ()); + /* Save constexpr function body before it gets munged by + the NRV transformation. */ + maybe_save_function_definition (fndecl); + /* Set up the named return value optimization, if we can. Candidate variables are selected in check_return_expr. */ if (current_function_return_value) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index ad26abb..0420d37 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5282,6 +5282,55 @@ ensure_literal_type_for_constexpr_object (tree decl) return decl; } +/* Representation of entries in the constexpr function definition table. */ + +typedef struct GTY(()) constexpr_fundef { + tree decl; + tree body; +} constexpr_fundef; + +/* This table holds all constexpr function definitions seen in + the current translation unit. */ + +static GTY ((param_is (constexpr_fundef))) htab_t constexpr_fundef_table; + +static bool potential_constant_expression (tree, tsubst_flags_t); + +/* 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. */ + +static inline int +constexpr_fundef_equal (const void *p, const void *q) +{ + const constexpr_fundef *lhs = (const constexpr_fundef *) p; + const constexpr_fundef *rhs = (const constexpr_fundef *) q; + 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. */ + +static inline hashval_t +constexpr_fundef_hash (const void *p) +{ + const constexpr_fundef *fundef = (const constexpr_fundef *) p; + 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 *) htab_find (constexpr_fundef_table, &fundef); +} + /* Return true if type expression T is a valid parameter type, or a valid return type, of a constexpr function. */ @@ -5343,6 +5392,9 @@ is_valid_constexpr_fn (tree fun, bool complain) tree validate_constexpr_fundecl (tree fun) { + constexpr_fundef entry; + constexpr_fundef **slot; + if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun)) return NULL; else if (DECL_CLONED_FUNCTION_P (fun)) @@ -5355,10 +5407,684 @@ validate_constexpr_fundecl (tree fun) return NULL; } + /* Create the constexpr function table if necessary. */ + if (constexpr_fundef_table == NULL) + constexpr_fundef_table = htab_create_ggc (101, + constexpr_fundef_hash, + constexpr_fundef_equal, + ggc_free); + entry.decl = fun; + entry.body = NULL; + slot = (constexpr_fundef **) + htab_find_slot (constexpr_fundef_table, &entry, INSERT); + if (*slot == NULL) + { + *slot = ggc_alloc_constexpr_fundef (); + **slot = entry; + } + return fun; +} + +/* 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(constructor_elt,gc) **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) == 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. */ + return true; + if (TREE_CODE (t) == CONVERT_EXPR) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == INIT_EXPR + || TREE_CODE (t) == MODIFY_EXPR) + { + member = TREE_OPERAND (t, 0); + init = unshare_expr (TREE_OPERAND (t, 1)); + } + else + { + tree memtype; + gcc_assert (TREE_CODE (t) == CALL_EXPR); + member = CALL_EXPR_ARG (t, 0); + memtype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (member))); + if (TREE_CODE (member) == NOP_EXPR) + { + /* We don't put out anything for an empty base. */ + gcc_assert (is_empty_class (memtype)); + /* But if the constructor used isn't constexpr, leave in the call + so we complain later. */ + if (potential_constant_expression (t, tf_none)) + return true; + } + else + { + gcc_assert (TREE_CODE (member) == ADDR_EXPR); + member = TREE_OPERAND (member, 0); + } + /* We don't use build_cplus_new here because it complains about + abstract bases. T has the wrong type, but + cxx_eval_constant_expression doesn't care. */ + init = unshare_expr (t); + } + if (TREE_CODE (member) == COMPONENT_REF) + member = TREE_OPERAND (member, 1); + CONSTRUCTOR_APPEND_ELT (*vec, member, init); + return true; +} + +/* 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(constructor_elt,gc) *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) == BIND_EXPR) + body = BIND_EXPR_BODY (body); + if (TREE_CODE (body) == CLEANUP_POINT_EXPR) + ok = build_data_member_initialization (body, &vec); + else + { + tree_stmt_iterator i; + gcc_assert (TREE_CODE (body) == STATEMENT_LIST); + for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i)) + { + ok = build_data_member_initialization (tsi_stmt (i), &vec); + if (!ok) + break; + } + } + if (ok) + return build_constructor (type, vec); + else + return error_mark_node; +} + +/* 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 *fundef = retrieve_constexpr_fundef (fun); + gcc_assert (fundef != NULL && fundef->body == NULL); + + if (DECL_CONSTRUCTOR_P (fun)) + body = build_constexpr_constructor_member_initializers + (DECL_CONTEXT (fun), body); + else + { + if (TREE_CODE (body) == BIND_EXPR) + body = BIND_EXPR_BODY (body); + 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); + if (TREE_CODE (body) == CLEANUP_POINT_EXPR) + body = TREE_OPERAND (body, 0); + if (TREE_CODE (body) != RETURN_EXPR) + { + error ("body of constexpr function %qD not a return-statement", fun); + DECL_DECLARED_CONSTEXPR_P (fun) = false; + return NULL; + } + body = unshare_expr (TREE_OPERAND (body, 0)); + } + + if (!potential_constant_expression (body, (DECL_TEMPLATE_INSTANTIATION (fun) + ? tf_none : tf_error))) + { + DECL_DECLARED_CONSTEXPR_P (fun) = false; + return NULL; + } + fundef->body = body; + return fun; +} + +/* Return true if T designates the implied `this' parameter. */ + +static inline bool +is_this_parameter (tree t) +{ + return t == current_class_ptr; +} + +/* 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 (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; + } +} + +/* 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) +{ + enum 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; +} + +/* Return true if the DECL designates a builtin function that is + morally constexpr, in the sense that its parameter types and + return type are literal types and the compiler is allowed to + fold its invocations. */ + +static bool +morally_constexpr_builtin_function_p (tree decl) +{ + tree funtype = TREE_TYPE (decl); + tree t; + + if (!is_builtin_fn (decl)) + return false; + if (!literal_type_p (TREE_TYPE (funtype))) + return false; + for (t = TYPE_ARG_TYPES (funtype); t != NULL ; t = TREE_CHAIN (t)) + { + if (t == void_list_node) + return true; + if (!literal_type_p (TREE_VALUE (t))) + return false; + } + /* We assume no varargs builtins are suitable. */ + return t != NULL; +} + +/* Return true if T denotes a constant expression, or potential constant + expression if POTENTIAL is true. + Issue diagnostic as appropriate under control of flags. Variables + with static storage duration initialized by constant expressions + are guaranteed to be statically initialized. + + C++0x [expr.const] + + 6 An expression is a potential constant expression if it is + a constant expression where all occurences 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 (tree t, tsubst_flags_t flags) +{ + int i; + tree tmp; + if (t == error_mark_node) + return false; + 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 LABEL_DECL: + case CONST_DECL: + return true; + + case PARM_DECL: + /* -- this (5.1) unless it appears as the postfix-expression in a + class member access expression, including the result of the + implicit transformation in the body of the non-static + member function (9.3.1); */ + if (is_this_parameter (t)) + { + if (flags & tf_error) + error ("%qE is not a potential constant expression", t); + return false; + } + 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); + if (TREE_CODE (fun) != FUNCTION_DECL) + { + if (potential_constant_expression (fun, flags)) + /* Might end up being a constant function pointer. */ + return true; + if (flags & tf_error) + error ("%qE is not a function name", fun); + return false; + } + /* Skip initial arguments to base constructors. */ + if (DECL_BASE_CONSTRUCTOR_P (fun)) + i = num_artificial_parms_for (fun); + else + i = 0; + fun = DECL_ORIGIN (fun); + if (builtin_valid_in_constant_expr_p (fun)) + return true; + if (!DECL_DECLARED_CONSTEXPR_P (fun) + && !morally_constexpr_builtin_function_p (fun)) + { + if (flags & tf_error) + error ("%qD is not %<constexpr%>", fun); + return false; + } + for (; i < nargs; ++i) + { + tree x = get_nth_callarg (t, i); + /* 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 (i == 0 && DECL_NONSTATIC_MEMBER_P (fun) + && !DECL_CONSTRUCTOR_P (fun)) + { + if (TREE_CODE (x) == ADDR_EXPR) + x = TREE_OPERAND (x, 0); + if (is_this_parameter (x)) + /* OK. */; + else if (!potential_constant_expression (x, flags)) + { + if (flags & tf_error) + error ("object argument is not a potential constant " + "expression"); + return false; + } + } + else if (!potential_constant_expression (x, flags)) + { + if (flags & tf_error) + error ("argument in position %qP is not a " + "potential constant expression", i); + 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 potential_constant_expression (TREE_OPERAND (t, 0), flags); + + case VAR_DECL: + if (!decl_constant_var_p (t)) + { + if (flags & tf_error) + error ("variable %qD is not declared constexpr", t); + return false; + } + return true; + + case NOP_EXPR: + case CONVERT_EXPR: + case VIEW_CONVERT_EXPR: + /* -- an array-to-pointer conversion that is applied to an lvalue + that designates an object with thread or automatic storage + duration; FIXME not implemented as it breaks constexpr arrays; + need to fix the standard + -- a type conversion from a pointer or pointer-to-member type + to a literal type. */ + { + tree from = TREE_OPERAND (t, 0); + tree source = TREE_TYPE (from); + tree target = TREE_TYPE (t); + if (TYPE_PTR_P (source) && ARITHMETIC_TYPE_P (target) + && !(TREE_CODE (from) == COMPONENT_REF + && TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (from, 0))))) + { + if (flags & tf_error) + error ("conversion of expression %qE of pointer type " + "cannot yield a constant expression", from); + return false; + } + return potential_constant_expression (from, flags); + } + + 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); + 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; + } + return potential_constant_expression (t, flags); + + case COMPONENT_REF: + case BIT_FIELD_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 potential_constant_expression (TREE_OPERAND (t, 0), flags); + + case INDIRECT_REF: + { + tree x = TREE_OPERAND (t, 0); + STRIP_NOPS (x); + if (is_this_parameter (x)) + return true; + return potential_constant_expression (x, flags); + } + + case LAMBDA_EXPR: + case DYNAMIC_CAST_EXPR: + case PSEUDO_DTOR_EXPR: + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTDECREMENT_EXPR: + case NEW_EXPR: + case VEC_NEW_EXPR: + case DELETE_EXPR: + case VEC_DELETE_EXPR: + case THROW_EXPR: + case MODIFY_EXPR: + case MODOP_EXPR: + /* GCC internal stuff. */ + case VA_ARG_EXPR: + case OBJ_TYPE_REF: + case WITH_CLEANUP_EXPR: + case CLEANUP_POINT_EXPR: + case MUST_NOT_THROW_EXPR: + case TRY_CATCH_EXPR: + case STATEMENT_LIST: + case BIND_EXPR: + 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_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; + } + 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; + } + goto binary; + + 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 BIT_NOT_EXPR: + case TRUTH_NOT_EXPR: + case PAREN_EXPR: + case FIXED_CONVERT_EXPR: + /* For convenience. */ + case RETURN_EXPR: + return potential_constant_expression (TREE_OPERAND (t, 0), flags); + + case INIT_EXPR: + case TARGET_EXPR: + return potential_constant_expression (TREE_OPERAND (t, 1), flags); + + case CONSTRUCTOR: + { + VEC(constructor_elt, gc) *v = CONSTRUCTOR_ELTS (t); + constructor_elt *ce; + for (i = 0; VEC_iterate (constructor_elt, v, i, ce); ++i) + if (!potential_constant_expression (ce->value, flags)) + return false; + return true; + } + + case TREE_LIST: + { + gcc_assert (TREE_PURPOSE (t) == NULL_TREE + || DECL_P (TREE_PURPOSE (t))); + if (!potential_constant_expression (TREE_VALUE (t), flags)) + return false; + if (TREE_CHAIN (t) == NULL_TREE) + return true; + return potential_constant_expression (TREE_CHAIN (t), flags); + } + + 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: + if (integer_zerop (decl_constant_value (TREE_OPERAND (t, 1)))) + return false; + else + goto binary; + + 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 potential_constant_expression (op0, flags); + 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: + if (TREE_OPERAND (t, 0) == tmp) + return potential_constant_expression (TREE_OPERAND (t, 1), flags); + else + return potential_constant_expression (TREE_OPERAND (t, 0), flags); + + case ARRAY_REF: + case ARRAY_RANGE_REF: + 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 UNLT_EXPR: + case UNLE_EXPR: + case UNGT_EXPR: + case UNGE_EXPR: + case UNEQ_EXPR: + case RANGE_EXPR: + case COMPLEX_EXPR: + binary: + for (i = 0; i < 2; ++i) + if (!potential_constant_expression (TREE_OPERAND (t, i), + flags)) + 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 (!potential_constant_expression (tmp, flags)) + return false; + else if (tmp == boolean_true_node) + return potential_constant_expression (TREE_OPERAND (t, 1), flags); + else if (tmp == boolean_false_node) + return potential_constant_expression (TREE_OPERAND (t, 2), flags); + for (i = 1; i < 3; ++i) + if (potential_constant_expression (TREE_OPERAND (t, i), tf_none)) + return true; + if (flags & tf_error) + error ("expression %qE is not a constant-expression", t); + return false; + + case VEC_INIT_EXPR: + /* We should only see this in a defaulted constructor for a class + with a non-static data member of array type; if we get here we + know this is a potential constant expression. */ + gcc_assert (DECL_DEFAULTED_FN (current_function_decl)); + return true; + + default: + sorry ("unexpected ast of kind %s", tree_code_name[TREE_CODE (t)]); + gcc_unreachable(); + return false; + } +} + + /* Constructor for a lambda expression. */ tree |