#include "tm.h"
#include "tree.h"
#include "cp-tree.h"
-#include "c-common.h"
+#include "c-family/c-common.h"
#include "tree-inline.h"
#include "tree-mudflap.h"
-#include "except.h"
#include "toplev.h"
#include "flags.h"
-#include "rtl.h"
-#include "expr.h"
#include "output.h"
#include "timevar.h"
-#include "debug.h"
#include "diagnostic.h"
#include "cgraph.h"
#include "tree-iterator.h"
#include "vec.h"
#include "target.h"
#include "gimple.h"
+#include "bitmap.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
int i, j;
deferred_access_check *chk, *probe;
- for (i = 0 ;
- VEC_iterate (deferred_access_check, checks, i, chk) ;
- ++i)
+ FOR_EACH_VEC_ELT (deferred_access_check, checks, i, chk)
{
- for (j = 0 ;
- VEC_iterate (deferred_access_check,
- ptr->deferred_access_checks, j, probe) ;
- ++j)
+ FOR_EACH_VEC_ELT (deferred_access_check,
+ ptr->deferred_access_checks, j, probe)
{
if (probe->binfo == chk->binfo &&
probe->decl == chk->decl &&
if (!checks)
return;
- for (i = 0 ; VEC_iterate (deferred_access_check, checks, i, chk) ; ++i)
+ FOR_EACH_VEC_ELT (deferred_access_check, checks, i, chk)
enforce_access (chk->binfo, chk->decl, chk->diag_decl);
}
}
/* See if we are already going to perform this check. */
- for (i = 0 ;
- VEC_iterate (deferred_access_check,
- ptr->deferred_access_checks, i, chk) ;
- ++i)
+ FOR_EACH_VEC_ELT (deferred_access_check,
+ ptr->deferred_access_checks, i, chk)
{
if (chk->decl == decl && chk->binfo == binfo &&
chk->diag_decl == diag_decl)
new_access->diag_decl = diag_decl;
}
+/* Used by build_over_call in LOOKUP_SPECULATIVE mode: return whether DECL
+ is accessible in BINFO, and possibly complain if not. If we're not
+ checking access, everything is accessible. */
+
+bool
+speculative_access_check (tree binfo, tree decl, tree diag_decl,
+ bool complain)
+{
+ if (deferred_access_no_check)
+ return true;
+
+ /* If we're checking for implicit delete, we don't want access
+ control errors. */
+ if (!accessible_p (binfo, decl, true))
+ {
+ /* Unless we're under maybe_explain_implicit_delete. */
+ if (complain)
+ enforce_access (binfo, decl, diag_decl);
+ return false;
+ }
+
+ return true;
+}
+
/* Returns nonzero if the current statement is a full expression,
i.e. temporaries created during that statement should be destroyed
at the end of the statement. */
TREE_USED (destination) = 1;
else
{
+ destination = mark_rvalue_use (destination);
if (!processing_template_decl)
{
destination = cp_convert (ptr_type_node, destination);
{
if (warn_sequence_point)
verify_sequence_points (expr);
- expr = convert_to_void (expr, "statement", tf_warning_or_error);
+ expr = convert_to_void (expr, ICV_STATEMENT, tf_warning_or_error);
}
else if (!type_dependent_expression_p (expr))
- convert_to_void (build_non_dependent_expr (expr), "statement",
+ convert_to_void (build_non_dependent_expr (expr), ICV_STATEMENT,
tf_warning_or_error);
if (check_for_bare_parameter_packs (expr))
{
if (warn_sequence_point)
verify_sequence_points (expr);
- expr = convert_to_void (expr, "3rd expression in for",
+ expr = convert_to_void (expr, ICV_THIRD_IN_FOR,
tf_warning_or_error);
}
else if (!type_dependent_expression_p (expr))
- convert_to_void (build_non_dependent_expr (expr), "3rd expression in for",
+ convert_to_void (build_non_dependent_expr (expr), ICV_THIRD_IN_FOR,
tf_warning_or_error);
expr = maybe_cleanup_point_expr_void (expr);
if (check_for_bare_parameter_packs (expr))
/* Finish the body of a for-statement, which may be given by
FOR_STMT. The increment-EXPR for the loop must be
- provided. */
+ provided.
+ It can also finish RANGE_FOR_STMT. */
void
finish_for_stmt (tree for_stmt)
{
- FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt));
+ if (TREE_CODE (for_stmt) == RANGE_FOR_STMT)
+ RANGE_FOR_BODY (for_stmt) = do_poplevel (RANGE_FOR_BODY (for_stmt));
+ else
+ FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt));
/* Pop the scope for the body of the loop. */
if (flag_new_for_scope > 0)
finish_stmt ();
}
+/* Begin a range-for-statement. Returns a new RANGE_FOR_STMT.
+ To finish it call finish_for_stmt(). */
+
+tree
+begin_range_for_stmt (void)
+{
+ tree r;
+
+ r = build_stmt (input_location, RANGE_FOR_STMT,
+ NULL_TREE, NULL_TREE, NULL_TREE);
+
+ if (flag_new_for_scope > 0)
+ TREE_CHAIN (r) = do_pushlevel (sk_for);
+
+ return r;
+}
+
+/* Finish the head of a range-based for statement, which may
+ be given by RANGE_FOR_STMT. DECL must be the declaration
+ and EXPR must be the loop expression. */
+
+void
+finish_range_for_decl (tree range_for_stmt, tree decl, tree expr)
+{
+ RANGE_FOR_DECL (range_for_stmt) = decl;
+ RANGE_FOR_EXPR (range_for_stmt) = expr;
+ add_stmt (range_for_stmt);
+ RANGE_FOR_BODY (range_for_stmt) = do_pushlevel (sk_block);
+}
+
/* Finish a break-statement. */
tree
finish_compound_stmt (tree stmt)
{
if (TREE_CODE (stmt) == BIND_EXPR)
- BIND_EXPR_BODY (stmt) = do_poplevel (BIND_EXPR_BODY (stmt));
+ {
+ tree body = do_poplevel (BIND_EXPR_BODY (stmt));
+ /* If the STATEMENT_LIST is empty and this BIND_EXPR isn't special,
+ discard the BIND_EXPR so it can be merged with the containing
+ STATEMENT_LIST. */
+ if (TREE_CODE (body) == STATEMENT_LIST
+ && STATEMENT_LIST_HEAD (body) == NULL
+ && !BIND_EXPR_BODY_BLOCK (stmt)
+ && !BIND_EXPR_TRY_BLOCK (stmt))
+ stmt = body;
+ else
+ BIND_EXPR_BODY (stmt) = body;
+ }
else if (STATEMENT_LIST_NO_SCOPE (stmt))
stmt = pop_stmt_list (stmt);
else
tree operand;
int i;
- oconstraints = (const char **) alloca (noutputs * sizeof (char *));
+ oconstraints = XALLOCAVEC (const char *, noutputs);
string = resolve_asm_operand_names (string, output_operands,
input_operands, labels);
/* Perform Koenig lookup. FN is the postfix-expression representing
the function (or functions) to call; ARGS are the arguments to the
- call. Returns the functions to be considered by overload
- resolution. */
+ call; if INCLUDE_STD then the `std' namespace is automatically
+ considered an associated namespace (used in range-based for loops).
+ Returns the functions to be considered by overload resolution. */
tree
-perform_koenig_lookup (tree fn, VEC(tree,gc) *args)
+perform_koenig_lookup (tree fn, VEC(tree,gc) *args, bool include_std)
{
tree identifier = NULL_TREE;
tree functions = NULL_TREE;
if (!any_type_dependent_arguments_p (args)
&& !any_dependent_template_arguments_p (tmpl_args))
{
- fn = lookup_arg_dependent (identifier, functions, args);
+ fn = lookup_arg_dependent (identifier, functions, args, include_std);
if (!fn)
/* The unqualified name could not be resolved. */
fn = unqualified_fn_lookup_error (identifier);
if (TREE_CODE (type) == ARRAY_TYPE)
cp_complete_array_type (&type, compound_literal, false);
compound_literal = digest_init (type, compound_literal);
- if ((!at_function_scope_p () || cp_type_readonly (type))
- && initializer_constant_valid_p (compound_literal, type))
- {
- tree decl = create_temporary_var (type);
- DECL_INITIAL (decl) = compound_literal;
- TREE_STATIC (decl) = 1;
- cp_apply_type_quals_to_decl (cp_type_quals (type), decl);
- decl = pushdecl_top_level (decl);
- DECL_NAME (decl) = make_anon_name ();
- SET_DECL_ASSEMBLER_NAME (decl, DECL_NAME (decl));
- return decl;
- }
- else
- return get_target_expr (compound_literal);
+ return get_target_expr (compound_literal);
}
/* Return the declaration for the function-name variable indicated by
TYPE_BEING_DEFINED (t) = 1;
cplus_decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
+ fixup_attribute_variants (t);
if (flag_pack_struct)
{
return;
/* We should see only one DECL at a time. */
- gcc_assert (TREE_CHAIN (decl) == NULL_TREE);
+ gcc_assert (DECL_CHAIN (decl) == NULL_TREE);
/* Set up access control for DECL. */
TREE_PRIVATE (decl)
CLASSTYPE_METHOD_VEC. */
if (add_method (current_class_type, decl, NULL_TREE))
{
- TREE_CHAIN (decl) = TYPE_METHODS (current_class_type);
+ DECL_CHAIN (decl) = TYPE_METHODS (current_class_type);
TYPE_METHODS (current_class_type) = decl;
maybe_add_class_template_decl_list (current_class_type, decl,
= chainon (TYPE_FIELDS (current_class_type), decl);
else
{
- TREE_CHAIN (decl) = TYPE_FIELDS (current_class_type);
+ DECL_CHAIN (decl) = TYPE_FIELDS (current_class_type);
TYPE_FIELDS (current_class_type) = decl;
}
the complexity of the problem"
FIXME update for final resolution of core issue 696. */
- if (DECL_INTEGRAL_CONSTANT_VAR_P (decl))
+ if (decl_constant_var_p (decl))
return integral_constant_value (decl);
if (TYPE_P (context))
return error_mark_node;
}
}
+
+ /* Also disallow uses of function parameters outside the function
+ body, except inside an unevaluated context (i.e. decltype). */
+ if (TREE_CODE (decl) == PARM_DECL
+ && DECL_CONTEXT (decl) == NULL_TREE
+ && !cp_unevaluated_operand)
+ {
+ error ("use of parameter %qD outside function body", decl);
+ return error_mark_node;
+ }
}
/* If we didn't find anything, or what we found was a type,
return id_expression;
}
- /* Only certain kinds of names are allowed in constant
- expression. Enumerators and template parameters have already
- been handled above. */
- if (integral_constant_expression_p
- && ! DECL_INTEGRAL_CONSTANT_VAR_P (decl)
- && ! builtin_valid_in_constant_expr_p (decl))
- {
- if (!allow_non_integral_constant_expression_p)
- {
- error ("%qD cannot appear in a constant-expression", decl);
- return error_mark_node;
- }
- *non_integral_constant_expression_p = true;
- }
-
if (TREE_CODE (decl) == NAMESPACE_DECL)
{
error ("use of namespace %qD as expression", decl);
|| TREE_CODE (decl) == RESULT_DECL)
mark_used (decl);
+ /* Only certain kinds of names are allowed in constant
+ expression. Enumerators and template parameters have already
+ been handled above. */
+ if (integral_constant_expression_p
+ && ! decl_constant_var_p (decl)
+ && ! builtin_valid_in_constant_expr_p (decl))
+ {
+ if (!allow_non_integral_constant_expression_p)
+ {
+ error ("%qD cannot appear in a constant-expression", decl);
+ return error_mark_node;
+ }
+ *non_integral_constant_expression_p = true;
+ }
+
if (scope)
{
decl = (adjust_result_of_qualified_name_lookup
{
tree r = convert_from_reference (decl);
- if (processing_template_decl && TYPE_P (scope))
+ /* In a template, return a SCOPE_REF for most qualified-ids
+ so that we can check access at instantiation time. But if
+ we're looking at a member of the current instantiation, we
+ know we have access and building up the SCOPE_REF confuses
+ non-type template argument handling. */
+ if (processing_template_decl && TYPE_P (scope)
+ && !currently_open_class (scope))
r = build_qualified_name (TREE_TYPE (r),
scope, decl,
template_p);
fn,
aggr_init_expr_nargs (aggr_init_expr),
AGGR_INIT_EXPR_ARGP (aggr_init_expr));
+ TREE_NOTHROW (call_expr) = TREE_NOTHROW (aggr_init_expr);
if (style == ctor)
{
{
tree thunk;
- for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
+ for (thunk = DECL_THUNKS (fn); thunk; thunk = DECL_CHAIN (thunk))
{
if (!THUNK_ALIAS (thunk))
{
tree probe;
for (probe = DECL_THUNKS (thunk);
- probe; probe = TREE_CHAIN (probe))
+ probe; probe = DECL_CHAIN (probe))
use_thunk (probe, /*emit_p=*/1);
}
}
{
struct nrv_data data;
- /* Copy debugging information from VAR to RESULT. */
+ /* Copy name from VAR to RESULT. */
DECL_NAME (result) = DECL_NAME (var);
- DECL_ARTIFICIAL (result) = DECL_ARTIFICIAL (var);
- DECL_IGNORED_P (result) = DECL_IGNORED_P (var);
- DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (var);
- DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (var);
/* Don't forget that we take its address. */
TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (var);
+ /* Finally set DECL_VALUE_EXPR to avoid assigning
+ a stack slot at -O0 for the original var and debug info
+ uses RESULT location for VAR. */
+ SET_DECL_VALUE_EXPR (var, result);
+ DECL_HAS_VALUE_EXPR_P (var) = 1;
data.var = var;
data.result = result;
htab_delete (data.visited);
}
\f
-/* Return the declaration for the function called by CALL_EXPR T,
- TYPE is the class type of the clause decl. */
-
-static tree
-omp_clause_info_fndecl (tree t, tree type)
-{
- tree ret = get_callee_fndecl (t);
-
- if (ret)
- return ret;
-
- gcc_assert (TREE_CODE (t) == CALL_EXPR);
- t = CALL_EXPR_FN (t);
- STRIP_NOPS (t);
- if (TREE_CODE (t) == OBJ_TYPE_REF)
- {
- t = cp_fold_obj_type_ref (t, type);
- if (TREE_CODE (t) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL)
- return TREE_OPERAND (t, 0);
- }
-
- return NULL_TREE;
-}
-
/* Create CP_OMP_CLAUSE_INFO for clause C. Returns true if it is invalid. */
bool
info = make_tree_vec (3);
CP_OMP_CLAUSE_INFO (c) = info;
- if (need_default_ctor
- || (need_copy_ctor && !TYPE_HAS_TRIVIAL_INIT_REF (type)))
+ if (need_default_ctor || need_copy_ctor)
{
- VEC(tree,gc) *vec;
-
if (need_default_ctor)
- vec = NULL;
+ t = get_default_ctor (type);
else
- {
- t = build_int_cst (build_pointer_type (type), 0);
- t = build1 (INDIRECT_REF, type, t);
- vec = make_tree_vector_single (t);
- }
- t = build_special_member_call (NULL_TREE, complete_ctor_identifier,
- &vec, type, LOOKUP_NORMAL,
- tf_warning_or_error);
+ t = get_copy_ctor (type);
- if (vec != NULL)
- release_tree_vector (vec);
-
- if (targetm.cxx.cdtor_returns_this () || errorcount)
- /* Because constructors and destructors return this,
- the call will have been cast to "void". Remove the
- cast here. We would like to use STRIP_NOPS, but it
- wouldn't work here because TYPE_MODE (t) and
- TYPE_MODE (TREE_OPERAND (t, 0)) are different.
- They are VOIDmode and Pmode, respectively. */
- if (TREE_CODE (t) == NOP_EXPR)
- t = TREE_OPERAND (t, 0);
-
- TREE_VEC_ELT (info, 0) = get_callee_fndecl (t);
+ if (t && !trivial_fn_p (t))
+ TREE_VEC_ELT (info, 0) = t;
}
if ((need_default_ctor || need_copy_ctor)
&& TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
- {
- t = build_int_cst (build_pointer_type (type), 0);
- t = build1 (INDIRECT_REF, type, t);
- t = build_special_member_call (t, complete_dtor_identifier,
- NULL, type, LOOKUP_NORMAL,
- tf_warning_or_error);
-
- if (targetm.cxx.cdtor_returns_this () || errorcount)
- /* Because constructors and destructors return this,
- the call will have been cast to "void". Remove the
- cast here. We would like to use STRIP_NOPS, but it
- wouldn't work here because TYPE_MODE (t) and
- TYPE_MODE (TREE_OPERAND (t, 0)) are different.
- They are VOIDmode and Pmode, respectively. */
- if (TREE_CODE (t) == NOP_EXPR)
- t = TREE_OPERAND (t, 0);
+ TREE_VEC_ELT (info, 1) = get_dtor (type);
- TREE_VEC_ELT (info, 1) = omp_clause_info_fndecl (t, type);
- }
-
- if (need_copy_assignment && !TYPE_HAS_TRIVIAL_ASSIGN_REF (type))
+ if (need_copy_assignment)
{
- VEC(tree,gc) *vec;
-
- t = build_int_cst (build_pointer_type (type), 0);
- t = build1 (INDIRECT_REF, type, t);
- vec = make_tree_vector_single (t);
- t = build_special_member_call (t, ansi_assopname (NOP_EXPR),
- &vec, type, LOOKUP_NORMAL,
- tf_warning_or_error);
- release_tree_vector (vec);
-
- /* We'll have called convert_from_reference on the call, which
- may well have added an indirect_ref. It's unneeded here,
- and in the way, so kill it. */
- if (TREE_CODE (t) == INDIRECT_REF)
- t = TREE_OPERAND (t, 0);
+ t = get_copy_assign (type);
- TREE_VEC_ELT (info, 2) = omp_clause_info_fndecl (t, type);
+ if (t && !trivial_fn_p (t))
+ TREE_VEC_ELT (info, 2) = t;
}
return errorcount != save_errorcount;
/* Fold the expression and convert it to a boolean value. */
condition = fold_non_dependent_expr (condition);
condition = cp_convert (boolean_type_node, condition);
+ condition = maybe_constant_value (condition);
if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition))
/* Do nothing; the condition is satisfied. */
/* Report the error. */
error ("static assertion failed: %E", message);
else if (condition && condition != error_mark_node)
- error ("non-constant condition for static assertion");
+ {
+ error ("non-constant condition for static assertion");
+ cxx_constant_value (condition);
+ }
input_location = saved_loc;
}
}
type = TYPE_MAIN_VARIANT (type);
else if (real_lvalue_p (expr))
{
- if (TREE_CODE (type) != REFERENCE_TYPE)
- type = build_reference_type (type);
+ if (TREE_CODE (type) != REFERENCE_TYPE
+ || TYPE_REF_IS_RVALUE (type))
+ type = build_reference_type (non_reference (type));
}
else
type = non_reference (type);
return false;
fns = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), ix);
}
- else if (TYPE_HAS_INIT_REF (type))
+ else if (TYPE_HAS_COPY_CTOR (type))
{
/* If construction of the copy constructor was postponed, create
it now. */
return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
&& (trivial_type_p (type1)
|| (CLASS_TYPE_P (type1)
- && TYPE_HAS_TRIVIAL_ASSIGN_REF (type1))));
+ && TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
case CPTK_HAS_NOTHROW_CONSTRUCTOR:
type1 = strip_array_types (type1);
return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
|| (CLASS_TYPE_P (type1)
- && (t = locate_ctor (type1, NULL))
+ && (t = locate_ctor (type1))
&& TYPE_NOTHROW_P (TREE_TYPE (t))));
case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
type" wording for this trait. */
type1 = strip_array_types (type1);
return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE
- || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_INIT_REF (type1)));
+ || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_COPY_CTOR (type1)));
case CPTK_HAS_TRIVIAL_DESTRUCTOR:
type1 = strip_array_types (type1);
&& TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
case CPTK_HAS_VIRTUAL_DESTRUCTOR:
- return (CLASS_TYPE_P (type1)
- && (t = locate_dtor (type1, NULL)) && DECL_VIRTUAL_P (t));
+ return type_has_virtual_destructor (type1);
case CPTK_IS_ABSTRACT:
return (CLASS_TYPE_P (type1) && CLASSTYPE_PURE_VIRTUALS (type1));
case CPTK_IS_UNION:
return (type_code1 == UNION_TYPE);
+ case CPTK_IS_LITERAL_TYPE:
+ return (literal_type_p (type1));
+
default:
gcc_unreachable ();
return false;
if (COMPLETE_TYPE_P (type))
return true;
- if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type))
+ if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type)
+ && COMPLETE_TYPE_P (TREE_TYPE (type)))
return true;
if (VOID_TYPE_P (type))
|| kind == CPTK_IS_POLYMORPHIC
|| kind == CPTK_IS_STD_LAYOUT
|| kind == CPTK_IS_TRIVIAL
+ || kind == CPTK_IS_LITERAL_TYPE
|| kind == CPTK_IS_UNION);
if (kind == CPTK_IS_CONVERTIBLE_TO)
case CPTK_IS_POLYMORPHIC:
case CPTK_IS_STD_LAYOUT:
case CPTK_IS_TRIVIAL:
+ case CPTK_IS_LITERAL_TYPE:
if (!check_trait_type (type1))
{
error ("incomplete type %qT not allowed", type1);
return 0;
}
+\f
/* Return true if T is a literal type. */
bool
return false;
}
-
/* If DECL is a variable declared `constexpr', require its type
be literal. Return the DECL if OK, otherwise NULL. */
{
tree type = TREE_TYPE (decl);
if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl)
- && !processing_template_decl && !literal_type_p (type))
+ && !processing_template_decl
+ /* The call to complete_type is just for initializer_list. */
+ && !literal_type_p (complete_type (type)))
{
error ("the type %qT of constexpr variable %qD is not literal",
type, 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. */
+
+static bool
+valid_type_in_constexpr_fundecl_p (tree t)
+{
+ return (literal_type_p (t)
+ /* FIXME we allow ref to non-literal; should change standard to
+ match, or change back if not. */
+ || TREE_CODE (t) == REFERENCE_TYPE);
+}
+
+/* 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)
+{
+ tree parm = FUNCTION_FIRST_USER_PARM (fun);
+ bool ret = true;
+ for (; parm != NULL; parm = TREE_CHAIN (parm))
+ if (!valid_type_in_constexpr_fundecl_p (TREE_TYPE (parm)))
+ {
+ ret = false;
+ if (complain)
+ error ("invalid type for parameter %q#D of constexpr function",
+ parm);
+ }
+
+ if (!DECL_CONSTRUCTOR_P (fun))
+ {
+ tree rettype = TREE_TYPE (TREE_TYPE (fun));
+ if (!valid_type_in_constexpr_fundecl_p (rettype))
+ {
+ ret = false;
+ if (complain)
+ error ("invalid return type %qT of constexpr function %qD",
+ rettype, fun);
+ }
+
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
+ && COMPLETE_TYPE_P (DECL_CONTEXT (fun))
+ && !valid_type_in_constexpr_fundecl_p (DECL_CONTEXT (fun)))
+ {
+ ret = false;
+ if (complain)
+ error ("enclosing class of %q#D is not a literal type", fun);
+ }
+ }
+
+ return ret;
+}
+
/* Return non-null if FUN certainly designates a valid constexpr function
declaration. Otherwise return NULL. Issue appropriate diagnostics
if necessary. Note that we only check the declaration, not the body
tree
validate_constexpr_fundecl (tree fun)
{
- tree rettype = NULL;
- tree parm = NULL;
+ constexpr_fundef entry;
+ constexpr_fundef **slot;
- /* Don't bother if FUN is not marked constexpr. */
- if (!DECL_DECLARED_CONSTEXPR_P (fun))
+ if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun))
return NULL;
+ else if (DECL_CLONED_FUNCTION_P (fun))
+ /* We already checked the original function. */
+ return fun;
- /* For a function template, we have absolutely no guarantee that all
- instantiations will be constexpr. */
- if (TREE_CODE (fun) == TEMPLATE_DECL)
- return NULL;
-
- parm = FUNCTION_FIRST_USER_PARM (fun);
- for (; parm != NULL; parm = TREE_CHAIN (parm))
+ if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INSTANTIATION (fun)))
+ {
+ DECL_DECLARED_CONSTEXPR_P (fun) = false;
+ 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));
+ if (TREE_CODE (member) == INDIRECT_REF)
+ {
+ /* Don't put out anything for value-init of an empty base. */
+ gcc_assert (is_empty_class (TREE_TYPE (member)));
+ gcc_assert (TREE_CODE (init) == CONSTRUCTOR
+ && CONSTRUCTOR_NELTS (init) == 0);
+ return true;
+ }
+ }
+ 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 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
+ gcc_assert (errorcount > 0);
+ 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
{
- tree type = TREE_TYPE (parm);
- if (dependent_type_p (type))
- return NULL;
- if (!literal_type_p (type))
+ 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 ("parameter %q#D is not of literal type", parm);
+ 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 (DECL_CONSTRUCTOR_P (fun))
- return fun;
-
- rettype = TREE_TYPE (TREE_TYPE (fun));
- if (dependent_type_p (rettype))
- return NULL;
- if (!literal_type_p (rettype))
+ if (!potential_constant_expression (body, (DECL_TEMPLATE_INSTANTIATION (fun)
+ ? tf_none : tf_error)))
{
- error ("return type %qT of function %qD is not a literal type",
- TREE_TYPE (TREE_TYPE (fun)), fun);
+ DECL_DECLARED_CONSTEXPR_P (fun) = false;
return NULL;
}
+ fundef->body = body;
+ return fun;
+}
+
+/* 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. */
+
+typedef struct GTY(()) constexpr_call {
+ /* Description of the constexpr function definition. */
+ constexpr_fundef *fundef;
+ /* Parameter bindings enironment. 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 accomodate 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;
+} constexpr_call;
+
+/* A table of all constexpr calls that have been evaluated by the
+ compiler in this translation unit. */
+
+static GTY ((param_is (constexpr_call))) htab_t constexpr_call_table;
+
+static tree cxx_eval_constant_expression (const constexpr_call *, tree,
+ bool, bool, bool *);
+
+/* Compute a hash value for a constexpr call representation. */
+
+static hashval_t
+constexpr_call_hash (const void *p)
+{
+ const constexpr_call *info = (const constexpr_call *) p;
+ return info->hash;
+}
+
+/* Return 1 if the objects pointed to by P and Q represent calls
+ to the same constexpr function with the same arguments.
+ Otherwise, return 0. */
+
+static int
+constexpr_call_equal (const void *p, const void *q)
+{
+ const constexpr_call *lhs = (const constexpr_call *) p;
+ const constexpr_call *rhs = (const constexpr_call *) q;
+ tree lhs_bindings;
+ tree rhs_bindings;
+ if (lhs == rhs)
+ return 1;
+ if (!constexpr_fundef_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 = htab_create_ggc (101,
+ constexpr_call_hash,
+ constexpr_call_equal,
+ ggc_free);
+}
+
+/* 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;
+ }
+}
+
+/* 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_call *call, tree t,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_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 (call, CALL_EXPR_ARG (t, i),
+ allow_non_constant, addr,
+ non_constant_p);
+ if (allow_non_constant && *non_constant_p)
+ return t;
+ }
+ if (*non_constant_p)
+ return t;
+ new_call = build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
+ CALL_EXPR_FN (t), nargs, args);
+ return fold (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 (SCALAR_TYPE_P (type));
+ return fold_convert (type, temp);
+}
+
+/* Subroutine of cxx_eval_call_expression.
+ We are processing a call expression (either CALL_EXPR or
+ AGGR_INIT_EXPR) in the call context of OLD_CALL. 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_call *old_call, tree t,
+ constexpr_call *new_call,
+ bool allow_non_constant,
+ bool *non_constant_p)
+{
+ const int nargs = call_expr_nargs (t);
+ tree fun = new_call->fundef->decl;
+ tree parms = DECL_ARGUMENTS (fun);
+ int i;
+ for (i = 0; i < nargs; ++i)
+ {
+ tree x, arg;
+ tree type = parms ? TREE_TYPE (parms) : void_type_node;
+ /* For member function, the first argument is a pointer to the implied
+ object. And for an object contruction, don't bind `this' before
+ it is fully constructed. */
+ if (i == 0 && DECL_CONSTRUCTOR_P (fun))
+ goto next;
+ x = get_nth_callarg (t, i);
+ arg = cxx_eval_constant_expression (old_call, x, allow_non_constant,
+ TREE_CODE (type) == REFERENCE_TYPE,
+ non_constant_p);
+ /* Don't VERIFY_CONSTANT here. */
+ if (*non_constant_p && allow_non_constant)
+ return;
+ /* Just discard ellipsis args after checking their constantitude. */
+ if (!parms)
+ continue;
+
+ /* Make sure the binding has the same type as the parm. */
+ if (TREE_CODE (type) != REFERENCE_TYPE)
+ arg = adjust_temp_type (type, arg);
+ new_call->bindings = tree_cons (parms, arg, new_call->bindings);
+ 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. */
+
+static VEC(tree,heap) *call_stack = NULL;
+static int call_stack_tick;
+static int last_cx_error_tick;
+
+static void
+push_cx_call_context (tree call)
+{
+ ++call_stack_tick;
+ if (!EXPR_HAS_LOCATION (call))
+ SET_EXPR_LOCATION (call, input_location);
+ VEC_safe_push (tree, heap, call_stack, call);
+}
+
+static void
+pop_cx_call_context (void)
+{
+ ++call_stack_tick;
+ VEC_pop (tree, call_stack);
+}
+
+VEC(tree,heap) *
+cx_error_context (void)
+{
+ VEC(tree,heap) *r = NULL;
+ if (call_stack_tick != last_cx_error_tick
+ && !VEC_empty (tree, call_stack))
+ 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_call *old_call, tree t,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_p)
+{
+ location_t loc = EXPR_LOC_OR_HERE (t);
+ tree fun = get_function_named_in_call (t);
+ tree result;
+ constexpr_call new_call = { NULL, NULL, NULL, 0 };
+ constexpr_call **slot;
+ if (TREE_CODE (fun) != FUNCTION_DECL)
+ {
+ /* Might be a constexpr function pointer. */
+ fun = cxx_eval_constant_expression (old_call, fun, allow_non_constant,
+ /*addr*/false, non_constant_p);
+ if (TREE_CODE (fun) == ADDR_EXPR)
+ fun = TREE_OPERAND (fun, 0);
+ }
+ if (TREE_CODE (fun) != FUNCTION_DECL)
+ {
+ if (!allow_non_constant)
+ 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 (old_call, t, allow_non_constant,
+ addr, non_constant_p);
+ if (!DECL_DECLARED_CONSTEXPR_P (fun))
+ {
+ if (!allow_non_constant)
+ {
+ error_at (loc, "%qD is not a constexpr function", fun);
+ if (DECL_TEMPLATE_INSTANTIATION (fun)
+ && DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
+ (DECL_TI_TEMPLATE (fun))))
+ is_valid_constexpr_fn (fun, true);
+ }
+ *non_constant_p = true;
+ return t;
+ }
+
+ /* If in direct recursive call, optimize definition search. */
+ if (old_call != NULL && old_call->fundef->decl == fun)
+ new_call.fundef = old_call->fundef;
+ else
+ {
+ new_call.fundef = retrieve_constexpr_fundef (fun);
+ if (new_call.fundef == NULL || new_call.fundef->body == NULL)
+ {
+ if (!allow_non_constant)
+ error_at (loc, "%qD used before its definition", fun);
+ *non_constant_p = true;
+ return t;
+ }
+ }
+ cxx_bind_parameters_in_call (old_call, t, &new_call,
+ allow_non_constant, non_constant_p);
+ if (*non_constant_p)
+ return t;
+
+ push_cx_call_context (t);
+
+ new_call.hash
+ = iterative_hash_template_arg (new_call.bindings,
+ constexpr_fundef_hash (new_call.fundef));
+
+ /* If we have seen this call before, we are done. */
+ maybe_initialize_constexpr_call_table ();
+ slot = (constexpr_call **)
+ htab_find_slot (constexpr_call_table, &new_call, INSERT);
+ if (*slot != NULL)
+ {
+ /* Calls which are in progress have their result set to NULL
+ so that we can detect circular dependencies. */
+ if ((*slot)->result == NULL)
+ {
+ if (!allow_non_constant)
+ error ("call has circular dependency");
+ (*slot)->result = result = error_mark_node;
+ }
+ else
+ {
+ result = (*slot)->result;
+ if (result == error_mark_node && !allow_non_constant)
+ /* Re-evaluate to get the error. */
+ cxx_eval_constant_expression (&new_call, new_call.fundef->body,
+ allow_non_constant, addr,
+ non_constant_p);
+ }
+ }
+ else
+ {
+ /* 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. */
+ constexpr_call *entry = ggc_alloc_constexpr_call ();
+ *entry = new_call;
+ *slot = entry;
+ result
+ = cxx_eval_constant_expression (&new_call, new_call.fundef->body,
+ allow_non_constant, addr,
+ non_constant_p);
+ if (*non_constant_p)
+ entry->result = result = error_mark_node;
+ else
+ {
+ /* 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))
+ {
+ tree ob_arg = get_nth_callarg (t, 0);
+ STRIP_NOPS (ob_arg);
+ gcc_assert (TREE_CODE (TREE_TYPE (ob_arg)) == POINTER_TYPE
+ && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (ob_arg))));
+ result = adjust_temp_type (TREE_TYPE (TREE_TYPE (ob_arg)),
+ result);
+ }
+ entry->result = result;
+ }
+ }
+
+ pop_cx_call_context ();
+ return result;
+}
+
+bool
+reduced_constant_expression_p (tree t)
+{
+ /* FIXME speed this up, it's taking 16% of compile time on sieve testcase. */
+ if (cxx_dialect >= cxx0x && TREE_OVERFLOW_P (t))
+ /* In C++0x, integer overflow makes this not a constant expression.
+ FIXME arithmetic overflow is different from conversion truncation */
+ return false;
+ /* 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)
+{
+ if (!*non_constant_p && !reduced_constant_expression_p (t))
+ {
+ if (!allow_non_constant)
+ error ("%qE is not a constant expression", t);
+ *non_constant_p = true;
+ }
+ return *non_constant_p;
+}
+#define VERIFY_CONSTANT(X) \
+do { \
+ if (verify_constant ((X), allow_non_constant, non_constant_p)) \
+ return t; \
+ } while (0)
+
+/* 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_call *call, tree t,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_p)
+{
+ tree r;
+ tree orig_arg = TREE_OPERAND (t, 0);
+ tree arg = cxx_eval_constant_expression (call, orig_arg, allow_non_constant,
+ addr, non_constant_p);
+ VERIFY_CONSTANT (arg);
+ if (arg == orig_arg)
+ return t;
+ r = fold_build1 (TREE_CODE (t), TREE_TYPE (t), 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_call *call, tree t,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_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 (call, orig_lhs,
+ allow_non_constant, addr,
+ non_constant_p);
+ VERIFY_CONSTANT (lhs);
+ rhs = cxx_eval_constant_expression (call, orig_rhs,
+ allow_non_constant, addr,
+ non_constant_p);
+ VERIFY_CONSTANT (rhs);
+ if (lhs == orig_lhs && rhs == orig_rhs)
+ return t;
+ r = fold_build2 (TREE_CODE (t), TREE_TYPE (t), 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_call *call, tree t,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_p)
+{
+ tree val = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0),
+ allow_non_constant, addr,
+ non_constant_p);
+ VERIFY_CONSTANT (val);
+ if (val == boolean_true_node)
+ return cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
+ allow_non_constant, addr,
+ non_constant_p);
+ gcc_assert (val == boolean_false_node);
+ /* Don't VERIFY_CONSTANT here. */
+ return cxx_eval_constant_expression (call, TREE_OPERAND (t, 2),
+ allow_non_constant, addr,
+ non_constant_p);
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+ Attempt to reduce a reference to an array slot. */
+
+static tree
+cxx_eval_array_reference (const constexpr_call *call, tree t,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_p)
+{
+ tree oldary = TREE_OPERAND (t, 0);
+ tree ary = cxx_eval_constant_expression (call, oldary,
+ allow_non_constant, addr,
+ non_constant_p);
+ tree index, oldidx;
+ HOST_WIDE_INT i;
+ unsigned len;
+ if (*non_constant_p)
+ return t;
+ oldidx = TREE_OPERAND (t, 1);
+ index = cxx_eval_constant_expression (call, oldidx,
+ allow_non_constant, false,
+ non_constant_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);
+ len = (TREE_CODE (ary) == CONSTRUCTOR
+ ? CONSTRUCTOR_NELTS (ary)
+ : (unsigned)TREE_STRING_LENGTH (ary));
+ if (compare_tree_int (index, len) >= 0)
+ {
+ if (!allow_non_constant)
+ error ("array subscript out of bound");
+ *non_constant_p = true;
+ return t;
+ }
+ i = tree_low_cst (index, 0);
+ if (TREE_CODE (ary) == CONSTRUCTOR)
+ return VEC_index (constructor_elt, CONSTRUCTOR_ELTS (ary), i)->value;
+ else
+ return build_int_cst (cv_unqualified (TREE_TYPE (TREE_TYPE (ary))),
+ TREE_STRING_POINTER (ary)[i]);
+ /* 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_call *call, tree t,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_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 (call, orig_whole,
+ allow_non_constant, addr,
+ non_constant_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 (!allow_non_constant)
+ error ("%qE is not a constant expression", orig_whole);
+ *non_constant_p = true;
+ }
+ if (*non_constant_p)
+ return t;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value)
+ {
+ if (field == part)
+ return value;
+ }
+ if (TREE_CODE (TREE_TYPE (whole)) == UNION_TYPE)
+ {
+ /* FIXME Mike Miller wants this to be OK. */
+ if (!allow_non_constant)
+ error ("accessing %qD member instead of initialized %qD member in "
+ "constant expression", part, CONSTRUCTOR_ELT (whole, 0)->index);
+ *non_constant_p = true;
+ return t;
+ }
+ 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_call *call, tree t,
+ tree bailout_value, tree continue_value,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_p)
+{
+ tree r;
+ tree lhs = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0),
+ allow_non_constant, addr,
+ non_constant_p);
+ VERIFY_CONSTANT (lhs);
+ if (lhs == bailout_value)
+ return lhs;
+ gcc_assert (lhs == continue_value);
+ r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
+ allow_non_constant, addr, non_constant_p);
+ VERIFY_CONSTANT (r);
+ return r;
+}
+
+/* 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_call *call, tree t,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_p)
+{
+ VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (t);
+ VEC(constructor_elt,gc) *n = VEC_alloc (constructor_elt, gc,
+ VEC_length (constructor_elt, v));
+ constructor_elt *ce;
+ HOST_WIDE_INT i;
+ bool changed = false;
+ tree type = TREE_TYPE (t);
+ gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (t));
+ for (i = 0; VEC_iterate (constructor_elt, v, i, ce); ++i)
+ {
+ tree elt = cxx_eval_constant_expression (call, ce->value,
+ allow_non_constant, addr,
+ non_constant_p);
+ /* Don't VERIFY_CONSTANT here. */
+ if (allow_non_constant && *non_constant_p)
+ goto fail;
+ if (elt != ce->value)
+ changed = true;
+ if (TREE_CODE (type) != ARRAY_TYPE
+ && !(same_type_ignoring_top_level_qualifiers_p
+ (DECL_CONTEXT (ce->index), type)))
+ {
+ /* Push our vtable pointer down into the base where it belongs. */
+ tree vptr_base = DECL_CONTEXT (ce->index);
+ tree base_ctor;
+ gcc_assert (ce->index == TYPE_VFIELD (type));
+ for (base_ctor = VEC_index (constructor_elt, n, 0)->value; ;
+ base_ctor = CONSTRUCTOR_ELT (base_ctor, 0)->value)
+ if (TREE_TYPE (base_ctor) == vptr_base)
+ {
+ constructor_elt *p = CONSTRUCTOR_ELT (base_ctor, 0);
+ gcc_assert (p->index == ce->index);
+ p->value = elt;
+ break;
+ }
+ }
+ else
+ CONSTRUCTOR_APPEND_ELT (n, ce->index, elt);
+ }
+ if (*non_constant_p || !changed)
+ {
+ fail:
+ VEC_free (constructor_elt, gc, n);
+ return t;
+ }
+ t = build_constructor (TREE_TYPE (t), n);
+ TREE_CONSTANT (t) = true;
+ 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 this is only intended to support 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_call *call, tree atype, tree init,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_p)
+{
+ tree elttype = TREE_TYPE (atype);
+ int max = tree_low_cst (array_type_nelts (atype), 0);
+ VEC(constructor_elt,gc) *n = VEC_alloc (constructor_elt, gc, max + 1);
+ 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 (!init)
+ {
+ VEC(tree,gc) *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 = cxx_eval_constant_expression (call, init, allow_non_constant,
+ addr, non_constant_p);
+ }
+
+ if (*non_constant_p && !allow_non_constant)
+ goto fail;
+
+ for (i = 0; i <= max; ++i)
+ {
+ tree idx = build_int_cst (size_type_node, i);
+ tree eltinit;
+ if (TREE_CODE (elttype) == ARRAY_TYPE)
+ {
+ /* A multidimensional array; recurse. */
+ eltinit = cp_build_array_ref (input_location, init, idx,
+ tf_warning_or_error);
+ eltinit = cxx_eval_vec_init_1 (call, elttype, eltinit,
+ allow_non_constant, addr,
+ non_constant_p);
+ }
+ else if (TREE_CODE (init) == CONSTRUCTOR)
+ {
+ /* Initializing an element using the call to the default
+ constructor we just built above. */
+ eltinit = unshare_expr (init);
+ }
+ else
+ {
+ /* Copying an element. */
+ VEC(tree,gc) *argvec;
+ 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);
+ argvec = make_tree_vector ();
+ VEC_quick_push (tree, argvec, eltinit);
+ eltinit = (build_special_member_call
+ (NULL_TREE, complete_ctor_identifier, &argvec,
+ elttype, LOOKUP_NORMAL, tf_warning_or_error));
+ release_tree_vector (argvec);
+ eltinit = cxx_eval_constant_expression
+ (call, eltinit, allow_non_constant, addr, non_constant_p);
+ }
+ if (*non_constant_p && !allow_non_constant)
+ goto fail;
+ CONSTRUCTOR_APPEND_ELT (n, idx, eltinit);
+ }
+
+ if (!*non_constant_p)
+ {
+ init = build_constructor (TREE_TYPE (atype), n);
+ TREE_CONSTANT (init) = true;
+ return init;
+ }
+
+ fail:
+ VEC_free (constructor_elt, gc, n);
+ return init;
+}
+
+static tree
+cxx_eval_vec_init (const constexpr_call *call, tree t,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_p)
+{
+ tree atype = TREE_TYPE (t);
+ tree init = VEC_INIT_EXPR_INIT (t);
+ tree r = cxx_eval_vec_init_1 (call, atype, init, allow_non_constant,
+ addr, non_constant_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. */
+
+static tree
+cxx_eval_indirect_ref (const constexpr_call *call, tree t,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_p)
+{
+ tree orig_op0 = TREE_OPERAND (t, 0);
+ tree op0 = cxx_eval_constant_expression (call, orig_op0, allow_non_constant,
+ /*addr*/false, non_constant_p);
+ tree type, sub, subtype, r;
+ bool empty_base;
+
+ /* Don't VERIFY_CONSTANT here. */
+ if (*non_constant_p)
+ return t;
+
+ type = TREE_TYPE (t);
+ sub = op0;
+ r = NULL_TREE;
+ empty_base = false;
+
+ STRIP_NOPS (sub);
+ subtype = TREE_TYPE (sub);
+ gcc_assert (POINTER_TYPE_P (subtype));
+
+ if (TREE_CODE (sub) == ADDR_EXPR)
+ {
+ tree op = TREE_OPERAND (sub, 0);
+ tree optype = TREE_TYPE (op);
+
+ if (same_type_ignoring_top_level_qualifiers_p (optype, type))
+ r = op;
+ /* Also handle conversion to an empty base class, which
+ is represented with a NOP_EXPR. */
+ else if (!addr && is_empty_class (type)
+ && CLASS_TYPE_P (optype)
+ && DERIVED_FROM_P (type, optype))
+ {
+ r = op;
+ empty_base = true;
+ }
+ /* *(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)))
+ {
+ r = 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 *)&struct_with_foo_field)[1] => COMPONENT_REF */
+ 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)))
+ {
+ r = fold_build3 (COMPONENT_REF, type, op00,
+ field, NULL_TREE);
+ break;
+ }
+ }
+ }
+ }
+
+ /* Let build_fold_indirect_ref handle the cases it does fine with. */
+ if (r == NULL_TREE)
+ r = build_fold_indirect_ref (op0);
+ if (TREE_CODE (r) != INDIRECT_REF)
+ r = cxx_eval_constant_expression (call, r, allow_non_constant,
+ addr, non_constant_p);
+ else if (TREE_CODE (sub) == ADDR_EXPR
+ || TREE_CODE (sub) == POINTER_PLUS_EXPR)
+ {
+ gcc_assert (!same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t)));
+ /* FIXME Mike Miller wants this to be OK. */
+ if (!allow_non_constant)
+ 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)
+ {
+ VERIFY_CONSTANT (r);
+ r = build_constructor (TREE_TYPE (t), NULL);
+ TREE_CONSTANT (r) = true;
+ }
+
+ if (TREE_CODE (r) == INDIRECT_REF && TREE_OPERAND (r, 0) == orig_op0)
+ return t;
+ return r;
+}
+
+/* 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 */
+
+static tree
+cxx_eval_constant_expression (const constexpr_call *call, tree t,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_p)
+{
+ 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);
+ return t;
+ }
+ if (TREE_CODE (t) != NOP_EXPR
+ && reduced_constant_expression_p (t))
+ return fold (t);
+
+ switch (TREE_CODE (t))
+ {
+ case VAR_DECL:
+ if (addr)
+ return t;
+ /* else fall through. */
+ case CONST_DECL:
+ r = integral_constant_value (t);
+ if (TREE_CODE (r) == TARGET_EXPR
+ && TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR)
+ r = TARGET_EXPR_INITIAL (r);
+ if (DECL_P (r))
+ {
+ if (!allow_non_constant)
+ {
+ tree type = TREE_TYPE (r);
+ error ("the value of %qD is not usable in a constant "
+ "expression", r);
+ 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))
+ inform (DECL_SOURCE_LOCATION (r),
+ "%qD was not initialized with a constant "
+ "expression", r);
+ else
+ gcc_unreachable ();
+ }
+ else
+ {
+ if (cxx_dialect >= cxx0x && !DECL_DECLARED_CONSTEXPR_P (r))
+ inform (DECL_SOURCE_LOCATION (r),
+ "%qD was not declared %<constexpr%>", r);
+ else
+ inform (DECL_SOURCE_LOCATION (r),
+ "%qD does not have integral or enumeration type",
+ r);
+ }
+ }
+ *non_constant_p = true;
+ }
+ break;
+
+ case FUNCTION_DECL:
+ case LABEL_DECL:
+ return t;
+
+ case PARM_DECL:
+ if (call && DECL_CONTEXT (t) == call->fundef->decl)
+ r = lookup_parameter_binding (call, t);
+ else if (addr)
+ /* Defer in case this is only used for its type. */;
+ else
+ {
+ if (!allow_non_constant)
+ 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 (call, t, allow_non_constant, addr,
+ non_constant_p);
+ break;
+
+ case TARGET_EXPR:
+ case INIT_EXPR:
+ /* Pass false for 'addr' because these codes indicate
+ initialization of a temporary. */
+ r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
+ allow_non_constant, false,
+ non_constant_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);
+ break;
+
+ case SCOPE_REF:
+ r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
+ allow_non_constant, addr,
+ non_constant_p);
+ break;
+
+ case RETURN_EXPR:
+ case NON_LVALUE_EXPR:
+ case TRY_CATCH_EXPR:
+ case CLEANUP_POINT_EXPR:
+ case MUST_NOT_THROW_EXPR:
+ case SAVE_EXPR:
+ r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0),
+ allow_non_constant, addr,
+ non_constant_p);
+ 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 (call, t, allow_non_constant, addr,
+ non_constant_p);
+ break;
+
+ case ADDR_EXPR:
+ {
+ tree oldop = TREE_OPERAND (t, 0);
+ tree op = cxx_eval_constant_expression (call, oldop,
+ allow_non_constant,
+ /*addr*/true,
+ non_constant_p);
+ /* Don't VERIFY_CONSTANT here. */
+ if (*non_constant_p)
+ return t;
+ /* 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 (call, t, allow_non_constant, addr,
+ non_constant_p);
+ 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 (call, op0, allow_non_constant,
+ addr, non_constant_p);
+ else
+ goto binary;
+ }
+ 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 RANGE_EXPR:
+ case COMPLEX_EXPR:
+ binary:
+ r = cxx_eval_binary_expression (call, t, allow_non_constant, addr,
+ non_constant_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 (call, t, boolean_false_node,
+ boolean_true_node,
+ allow_non_constant, addr,
+ non_constant_p);
+ break;
+
+ case TRUTH_OR_EXPR:
+ case TRUTH_ORIF_EXPR:
+ r = cxx_eval_logical_expression (call, t, boolean_true_node,
+ boolean_false_node,
+ allow_non_constant, addr,
+ non_constant_p);
+ break;
+
+ case ARRAY_REF:
+ r = cxx_eval_array_reference (call, t, allow_non_constant, addr,
+ non_constant_p);
+ break;
+
+ case COMPONENT_REF:
+ r = cxx_eval_component_reference (call, t, allow_non_constant, addr,
+ non_constant_p);
+ break;
+
+ case COND_EXPR:
+ case VEC_COND_EXPR:
+ r = cxx_eval_conditional_expression (call, t, allow_non_constant, addr,
+ non_constant_p);
+ break;
+
+ case CONSTRUCTOR:
+ r = cxx_eval_bare_aggregate (call, t, allow_non_constant, addr,
+ non_constant_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 (call, t, allow_non_constant, addr,
+ non_constant_p);
+ break;
+
+ case CONVERT_EXPR:
+ case VIEW_CONVERT_EXPR:
+ case NOP_EXPR:
+ {
+ tree oldop = TREE_OPERAND (t, 0);
+ tree op = oldop;
+ tree to = TREE_TYPE (t);
+ tree source = TREE_TYPE (op);
+ if (TYPE_PTR_P (source) && ARITHMETIC_TYPE_P (to)
+ && !(TREE_CODE (op) == COMPONENT_REF
+ && TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (op, 0)))))
+ {
+ if (!allow_non_constant)
+ error ("conversion of expression %qE of pointer type "
+ "cannot yield a constant expression", op);
+ *non_constant_p = true;
+ return t;
+ }
+ op = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0),
+ allow_non_constant, addr,
+ non_constant_p);
+ if (*non_constant_p)
+ 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), to, op);
+ }
+ 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 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 STATEMENT_LIST:
+ case BIND_EXPR:
+ case NON_DEPENDENT_EXPR:
+ case BASELINK:
+ case EXPR_STMT:
+ if (!allow_non_constant)
+ error_at (EXPR_LOC_OR_HERE (t),
+ "expression %qE is not a constant-expression", t);
+ *non_constant_p = true;
+ break;
+
+ default:
+ internal_error ("unexpected expression %qE of kind %s", t,
+ 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 non_constant_p = false;
+ tree r = cxx_eval_constant_expression (NULL, t, allow_non_constant,
+ false, &non_constant_p);
+
+ if (!non_constant_p && !reduced_constant_expression_p (r))
+ {
+ if (!allow_non_constant)
+ error ("%qE is not a constant expression", t);
+ non_constant_p = true;
+ }
+
+ if (non_constant_p && !allow_non_constant)
+ return error_mark_node;
+ else if (non_constant_p && TREE_CONSTANT (t))
+ {
+ /* This isn't actually constant, so unset TREE_CONSTANT. */
+ if (EXPR_P (t) || TREE_CODE (t) == CONSTRUCTOR)
+ r = copy_node (t);
+ else
+ r = build_nop (TREE_TYPE (t), t);
+ TREE_CONSTANT (r) = false;
+ return r;
+ }
+ else if (non_constant_p || r == t)
+ return t;
+ else 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;
+ cxx_eval_constant_expression (NULL, t, true, false, &non_constant_p);
+ return !non_constant_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)
+{
+ return cxx_eval_outermost_constant_expr (t, false);
+}
+
+/* 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 r;
+
+ if (type_dependent_expression_p (t)
+ /* FIXME shouldn't check value-dependence first; see comment before
+ value_dependent_expression_p. */
+ || value_dependent_expression_p (t))
+ return t;
+
+ r = cxx_eval_outermost_constant_expr (t, true);
+#ifdef ENABLE_CHECKING
+ /* cp_tree_equal looks through NOPs, so allow them. */
+ gcc_assert (r == t
+ || CONVERT_EXPR_P (t)
+ || (TREE_CONSTANT (t) && !TREE_CONSTANT (r))
+ || !cp_tree_equal (r, t));
+#endif
+ return r;
+}
+
+/* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather
+ than wrapped in a TARGET_EXPR. */
+
+tree
+maybe_constant_init (tree t)
+{
+ t = maybe_constant_value (t);
+ if (TREE_CODE (t) == TARGET_EXPR)
+ {
+ tree init = TARGET_EXPR_INITIAL (t);
+ if (TREE_CODE (init) == CONSTRUCTOR
+ && TREE_CONSTANT (init))
+ t = init;
+ }
+ return t;
+}
+
+/* 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 (maybe_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;
+ }
+}
+
+\f
/* Constructor for a lambda expression. */
tree
if (TREE_CODE (type) != REFERENCE_TYPE)
{
if (!LAMBDA_EXPR_MUTABLE_P (lam))
- type = cp_build_qualified_type (type, (TYPE_QUALS (type)
+ type = cp_build_qualified_type (type, (cp_type_quals (type)
|TYPE_QUAL_CONST));
type = build_reference_type (type);
}
DECL_NOT_REALLY_EXTERN (fn) = 1;
DECL_DECLARED_INLINE_P (fn) = 1;
DECL_STATIC_FUNCTION_P (fn) = 1;
- DECL_ARGUMENTS (fn) = copy_list (TREE_CHAIN (DECL_ARGUMENTS (callop)));
- for (arg = DECL_ARGUMENTS (fn); arg; arg = TREE_CHAIN (arg))
+ DECL_ARGUMENTS (fn) = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop)));
+ for (arg = DECL_ARGUMENTS (fn); arg; arg = DECL_CHAIN (arg))
DECL_CONTEXT (arg) = fn;
if (nested)
DECL_INTERFACE_KNOWN (fn) = 1;
null_pointer_node);
argvec = make_tree_vector ();
VEC_quick_push (tree, argvec, arg);
- for (arg = DECL_ARGUMENTS (statfn); arg; arg = TREE_CHAIN (arg))
+ for (arg = DECL_ARGUMENTS (statfn); arg; arg = DECL_CHAIN (arg))
VEC_safe_push (tree, gc, argvec, arg);
call = build_call_a (callop, VEC_length (tree, argvec),
VEC_address (tree, argvec));