and during the instantiation of template functions.
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009, 2010 Free Software Foundation, Inc.
+ 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
Written by Mark Mitchell (mmitchell@usa.net) based on code found
formerly in parse.y and pt.c.
#include "tree.h"
#include "cp-tree.h"
#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
#include "tree-inline.h"
#include "tree-mudflap.h"
#include "toplev.h"
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 (error_operand_p (destination))
return NULL_TREE;
}
- /* We don't inline calls to functions with computed gotos.
- Those functions are typically up to some funny business,
- and may be depending on the labels being at particular
- addresses, or some such. */
- DECL_UNINLINABLE (current_function_decl) = 1;
}
check_goto (destination);
{
tree r, scope;
scope = do_pushlevel (sk_block);
- r = build_stmt (input_location, IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
- TREE_CHAIN (r) = scope;
+ r = build_stmt (input_location, IF_STMT, NULL_TREE,
+ NULL_TREE, NULL_TREE, scope);
begin_cond (&IF_COND (r));
return r;
}
void
finish_if_stmt (tree if_stmt)
{
- tree scope = TREE_CHAIN (if_stmt);
- TREE_CHAIN (if_stmt) = NULL;
+ tree scope = IF_SCOPE (if_stmt);
+ IF_SCOPE (if_stmt) = NULL;
add_stmt (do_poplevel (scope));
finish_stmt ();
}
return r;
}
-/* Begin a for-statement. Returns a new FOR_STMT if appropriate. */
+/* Begin the scope of a for-statement or a range-for-statement.
+ Both the returned trees are to be used in a call to
+ begin_for_stmt or begin_range_for_stmt. */
+
+tree
+begin_for_scope (tree *init)
+{
+ tree scope = NULL_TREE;
+ if (flag_new_for_scope > 0)
+ scope = do_pushlevel (sk_for);
+
+ if (processing_template_decl)
+ *init = push_stmt_list ();
+ else
+ *init = NULL_TREE;
+
+ return scope;
+}
+
+/* Begin a for-statement. Returns a new FOR_STMT.
+ SCOPE and INIT should be the return of begin_for_scope,
+ or both NULL_TREE */
tree
-begin_for_stmt (void)
+begin_for_stmt (tree scope, tree init)
{
tree r;
r = build_stmt (input_location, FOR_STMT, NULL_TREE, NULL_TREE,
- NULL_TREE, NULL_TREE);
-
- if (flag_new_for_scope > 0)
- TREE_CHAIN (r) = do_pushlevel (sk_for);
+ NULL_TREE, NULL_TREE, NULL_TREE);
- if (processing_template_decl)
- FOR_INIT_STMT (r) = push_stmt_list ();
+ if (scope == NULL_TREE)
+ {
+ gcc_assert (!init || !(flag_new_for_scope > 0));
+ if (!init)
+ scope = begin_for_scope (&init);
+ }
+ FOR_INIT_STMT (r) = init;
+ FOR_SCOPE (r) = scope;
return r;
}
/* 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)
{
- tree scope = TREE_CHAIN (for_stmt);
- TREE_CHAIN (for_stmt) = NULL;
+ tree scope;
+ tree *scope_ptr = (TREE_CODE (for_stmt) == RANGE_FOR_STMT
+ ? &RANGE_FOR_SCOPE (for_stmt)
+ : &FOR_SCOPE (for_stmt));
+ scope = *scope_ptr;
+ *scope_ptr = NULL;
add_stmt (do_poplevel (scope));
}
finish_stmt ();
}
+/* Begin a range-for-statement. Returns a new RANGE_FOR_STMT.
+ SCOPE and INIT should be the return of begin_for_scope,
+ or both NULL_TREE .
+ To finish it call finish_for_stmt(). */
+
+tree
+begin_range_for_stmt (tree scope, tree init)
+{
+ tree r;
+
+ r = build_stmt (input_location, RANGE_FOR_STMT,
+ NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
+
+ if (scope == NULL_TREE)
+ {
+ gcc_assert (!init || !(flag_new_for_scope > 0));
+ if (!init)
+ scope = begin_for_scope (&init);
+ }
+
+ /* RANGE_FOR_STMTs do not use nor save the init tree, so we
+ pop it now. */
+ if (init)
+ pop_stmt_list (init);
+ RANGE_FOR_SCOPE (r) = scope;
+
+ 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
{
tree r, scope;
- r = build_stmt (input_location, SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
-
scope = do_pushlevel (sk_block);
- TREE_CHAIN (r) = scope;
+ r = build_stmt (input_location, SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE, scope);
+
begin_cond (&SWITCH_STMT_COND (r));
return r;
pop_switch ();
finish_stmt ();
- scope = TREE_CHAIN (switch_stmt);
- TREE_CHAIN (switch_stmt) = NULL;
+ scope = SWITCH_STMT_SCOPE (switch_stmt);
+ SWITCH_STMT_SCOPE (switch_stmt) = NULL;
add_stmt (do_poplevel (scope));
}
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
effectively const. */
|| (CLASS_TYPE_P (TREE_TYPE (operand))
&& C_TYPE_FIELDS_READONLY (TREE_TYPE (operand)))))
- readonly_error (operand, REK_ASSIGNMENT_ASM);
+ cxx_readonly_error (operand, lv_asm);
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
oconstraints[i] = constraint;
object = maybe_dummy_object (scope, NULL);
}
+ if (object == error_mark_node)
+ return error_mark_node;
+
/* DR 613: Can use non-static data members without an associated
object in sizeof/decltype/alignof. */
if (is_dummy_object (object) && cp_unevaluated_operand == 0
/* It actually has a value we need to deal with. First, force it
to be an rvalue so that we won't need to build up a copy
constructor call later when we try to assign it to something. */
- expr = force_rvalue (expr);
+ expr = force_rvalue (expr, tf_warning_or_error);
if (error_operand_p (expr))
return error_mark_node;
temporary object created by the final expression is destroyed at
the end of the full-expression containing the
statement-expression. */
- result = force_target_expr (type, result);
+ result = force_target_expr (type, result, tf_warning_or_error);
}
return result;
/* 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 (processing_template_decl)
{
+ /* If the call expression is dependent, build a CALL_EXPR node
+ with no type; type_dependent_expression_p recognizes
+ expressions with no type as being dependent. */
if (type_dependent_expression_p (fn)
- || any_type_dependent_arguments_p (*args))
+ || any_type_dependent_arguments_p (*args)
+ /* For a non-static member function, we need to specifically
+ test the type dependency of the "this" pointer because it
+ is not included in *ARGS even though it is considered to
+ be part of the list of arguments. Note that this is
+ related to CWG issues 515 and 1005. */
+ || (((TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
+ || BASELINK_P (fn))
+ && current_class_ref
+ && type_dependent_expression_p (current_class_ref)))
{
result = build_nt_call_vec (fn, *args);
KOENIG_LOOKUP_P (result) = koenig_p;
make_args_non_dependent (*args);
}
+ if (TREE_CODE (fn) == COMPONENT_REF)
+ {
+ tree member = TREE_OPERAND (fn, 1);
+ if (BASELINK_P (member))
+ {
+ tree object = TREE_OPERAND (fn, 0);
+ return build_new_method_call (object, member,
+ args, NULL_TREE,
+ (disallow_virtual
+ ? LOOKUP_NORMAL | LOOKUP_NONVIRTUAL
+ : LOOKUP_NORMAL),
+ /*fn_p=*/NULL,
+ complain);
+ }
+ }
+
if (is_overloaded_fn (fn))
fn = baselink_for_fns (fn);
result = build_new_method_call (object, fn, args, NULL_TREE,
(disallow_virtual
- ? LOOKUP_NONVIRTUAL : 0),
+ ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
+ : LOOKUP_NORMAL),
/*fn_p=*/NULL,
complain);
}
/* A call where the function is unknown. */
result = cp_build_function_call_vec (fn, args, complain);
- if (processing_template_decl)
+ if (processing_template_decl && result != error_mark_node)
{
+ if (TREE_CODE (result) == INDIRECT_REF)
+ result = TREE_OPERAND (result, 0);
result = build_call_vec (TREE_TYPE (result), orig_fn, orig_args);
KOENIG_LOOKUP_P (result) = koenig_p;
release_tree_vector (orig_args);
+ result = convert_from_reference (result);
+ }
+
+ if (koenig_p)
+ {
+ /* Free garbage OVERLOADs from arg-dependent lookup. */
+ tree next = NULL_TREE;
+ for (fn = orig_fn;
+ fn && TREE_CODE (fn) == OVERLOAD && OVL_ARG_DEPENDENT (fn);
+ fn = next)
+ {
+ if (processing_template_decl)
+ /* In a template, we'll re-use them at instantiation time. */
+ OVL_ARG_DEPENDENT (fn) = false;
+ else
+ {
+ next = OVL_CHAIN (fn);
+ ggc_free (fn);
+ }
+ }
}
return result;
the CONSTRUCTOR in COMPOUND_LITERAL is being cast. */
tree
-finish_compound_literal (tree type, tree compound_literal)
+finish_compound_literal (tree type, tree compound_literal,
+ tsubst_flags_t complain)
{
if (type == error_mark_node)
return error_mark_node;
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ compound_literal
+ = finish_compound_literal (TREE_TYPE (type), compound_literal,
+ complain);
+ return cp_build_c_cast (type, compound_literal, complain);
+ }
+
if (!TYPE_OBJ_P (type))
{
- error ("compound literal of non-object type %qT", type);
+ if (complain & tf_error)
+ error ("compound literal of non-object type %qT", type);
return error_mark_node;
}
that it came from T{} rather than T({}). */
CONSTRUCTOR_IS_DIRECT_INIT (compound_literal) = 1;
compound_literal = build_tree_list (NULL_TREE, compound_literal);
- return build_functional_cast (type, compound_literal, tf_error);
+ return build_functional_cast (type, compound_literal, complain);
}
if (TREE_CODE (type) == ARRAY_TYPE
&& check_array_initializer (NULL_TREE, type, compound_literal))
return error_mark_node;
compound_literal = reshape_init (type, compound_literal);
- if (TREE_CODE (type) == ARRAY_TYPE)
- cp_complete_array_type (&type, compound_literal, false);
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_DOMAIN (type) == NULL_TREE)
+ {
+ cp_complete_array_type_or_error (&type, compound_literal,
+ false, complain);
+ if (type == error_mark_node)
+ return error_mark_node;
+ }
compound_literal = digest_init (type, compound_literal);
+ /* Put static/constant array temporaries in static variables, but always
+ represent class temporaries with TARGET_EXPR so we elide copies. */
if ((!at_function_scope_p () || CP_TYPE_CONST_P (type))
+ && TREE_CODE (type) == ARRAY_TYPE
+ && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
&& initializer_constant_valid_p (compound_literal, type))
{
tree decl = create_temporary_var (type);
DECL_INITIAL (decl) = compound_literal;
TREE_STATIC (decl) = 1;
+ if (literal_type_p (type) && CP_TYPE_CONST_NON_VOLATILE_P (type))
+ {
+ /* 5.19 says that a constant expression can include an
+ lvalue-rvalue conversion applied to "a glvalue of literal type
+ that refers to a non-volatile temporary object initialized
+ with a constant expression". Rather than try to communicate
+ that this VAR_DECL is a temporary, just mark it constexpr. */
+ DECL_DECLARED_CONSTEXPR_P (decl) = true;
+ DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
+ TREE_CONSTANT (decl) = true;
+ }
cp_apply_type_quals_to_decl (cp_type_quals (type), decl);
decl = pushdecl_top_level (decl);
DECL_NAME (decl) = make_anon_name ();
return decl;
}
else
- return get_target_expr (compound_literal);
+ return get_target_expr_sfinae (compound_literal, complain);
}
/* Return the declaration for the function-name variable indicated by
tree decl;
decl = fname_decl (input_location, C_RID_CODE (id), id);
- if (processing_template_decl)
+ if (processing_template_decl && current_function_decl)
decl = DECL_NAME (decl);
return decl;
}
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;
}
return result;
}
-/* Issue a diagnostic that NAME cannot be found in SCOPE. DECL is
- what we found when we tried to do the lookup.
- LOCATION is the location of the NAME identifier;
- The location is used in the error message*/
-
-void
-qualified_name_lookup_error (tree scope, tree name,
- tree decl, location_t location)
-{
- if (scope == error_mark_node)
- ; /* We already complained. */
- else if (TYPE_P (scope))
- {
- if (!COMPLETE_TYPE_P (scope))
- error_at (location, "incomplete type %qT used in nested name specifier",
- scope);
- else if (TREE_CODE (decl) == TREE_LIST)
- {
- error_at (location, "reference to %<%T::%D%> is ambiguous",
- scope, name);
- print_candidates (decl);
- }
- else
- error_at (location, "%qD is not a member of %qT", name, scope);
- }
- else if (scope != global_namespace)
- error_at (location, "%qD is not a member of %qD", name, scope);
- else
- error_at (location, "%<::%D%> has not been declared", name);
-}
-
/* If FNS is a member function, a set of member functions, or a
template-id referring to one or more member functions, return a
BASELINK for FNS, incorporating the current access context.
the current class so that we can check later to see if
the meaning would have been different after the class
was entirely defined. */
- if (!scope && decl != error_mark_node)
+ if (!scope && decl != error_mark_node
+ && TREE_CODE (id_expression) == IDENTIFIER_NODE)
maybe_note_name_used_in_class (id_expression, decl);
/* Disallow uses of local variables from containing functions, except
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 (! error_operand_p (decl)
+ && 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
return type;
}
+/* Implement the __underlying_type keyword: Return the underlying
+ type of TYPE, suitable for use as a type-specifier. */
+
+tree
+finish_underlying_type (tree type)
+{
+ tree underlying_type;
+
+ if (processing_template_decl)
+ {
+ underlying_type = cxx_make_type (UNDERLYING_TYPE);
+ UNDERLYING_TYPE_TYPE (underlying_type) = type;
+ SET_TYPE_STRUCTURAL_EQUALITY (underlying_type);
+
+ return underlying_type;
+ }
+
+ complete_type (type);
+
+ if (TREE_CODE (type) != ENUMERAL_TYPE)
+ {
+ error ("%qE is not an enumeration type", type);
+ return error_mark_node;
+ }
+
+ underlying_type = ENUM_UNDERLYING_TYPE (type);
+
+ /* Fixup necessary in this case because ENUM_UNDERLYING_TYPE
+ includes TYPE_MIN_VALUE and TYPE_MAX_VALUE information.
+ See finish_enum_value_list for details. */
+ if (!ENUM_FIXED_UNDERLYING_TYPE_P (type))
+ underlying_type
+ = c_common_type_for_mode (TYPE_MODE (underlying_type),
+ TYPE_UNSIGNED (underlying_type));
+
+ return underlying_type;
+}
+
/* Perform C++-specific checks for __builtin_offsetof before calling
fold_offsetof. */
{
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);
}
}
if ((flag_keep_inline_functions
&& DECL_DECLARED_INLINE_P (fn)
&& !DECL_REALLY_EXTERN (fn))
- || lookup_attribute ("dllexport", DECL_ATTRIBUTES (fn)))
+ || (flag_keep_inline_dllexport
+ && lookup_attribute ("dllexport", DECL_ATTRIBUTES (fn))))
mark_needed (fn);
}
/* 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;
}
}
a full expression. */
tree
-finish_decltype_type (tree expr, bool id_expression_or_member_access_p)
+finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
+ tsubst_flags_t complain)
{
- tree orig_expr = expr;
tree type = NULL_TREE;
if (!expr || error_operand_p (expr))
|| (TREE_CODE (expr) == BIT_NOT_EXPR
&& TYPE_P (TREE_OPERAND (expr, 0))))
{
- error ("argument to decltype must be an expression");
+ if (complain & tf_error)
+ error ("argument to decltype must be an expression");
return error_mark_node;
}
+ /* FIXME instantiation-dependent */
if (type_dependent_expression_p (expr)
/* In a template, a COMPONENT_REF has an IDENTIFIER_NODE for op1 even
if it isn't dependent, so that we can check access control at
&& processing_template_decl
&& TREE_CODE (expr) == COMPONENT_REF))
{
- if (id_expression_or_member_access_p)
- {
- switch (TREE_CODE (expr))
- {
- case VAR_DECL:
- case PARM_DECL:
- case RESULT_DECL:
- case FUNCTION_DECL:
- case CONST_DECL:
- case TEMPLATE_PARM_INDEX:
- type = TREE_TYPE (expr);
- break;
-
- default:
- break;
- }
- }
-
- if (type && !type_uses_auto (type))
- return type;
-
- treat_as_dependent:
type = cxx_make_type (DECLTYPE_TYPE);
DECLTYPE_TYPE_EXPR (type) = expr;
DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type)
expr = resolve_nondeduced_context (expr);
+ if (type_unknown_p (expr))
+ {
+ if (complain & tf_error)
+ error ("decltype cannot resolve address of overloaded function");
+ return error_mark_node;
+ }
+
/* To get the size of a static data member declared as an array of
unknown bound, we need to instantiate it. */
if (TREE_CODE (expr) == VAR_DECL
expr = TREE_OPERAND (expr, 1);
if (TREE_CODE (expr) == BASELINK)
- /* See through BASELINK nodes to the underlying functions. */
+ /* See through BASELINK nodes to the underlying function. */
expr = BASELINK_FUNCTIONS (expr);
- if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
- expr = TREE_OPERAND (expr, 0);
-
- if (TREE_CODE (expr) == OVERLOAD)
- {
- if (OVL_CHAIN (expr)
- || TREE_CODE (OVL_FUNCTION (expr)) == TEMPLATE_DECL)
- {
- error ("%qE refers to a set of overloaded functions", orig_expr);
- return error_mark_node;
- }
- else
- /* An overload set containing only one function: just look
- at that function. */
- expr = OVL_FUNCTION (expr);
- }
-
switch (TREE_CODE (expr))
{
case FIELD_DECL:
break;
default:
- gcc_assert (TYPE_P (expr) || DECL_P (expr)
- || TREE_CODE (expr) == SCOPE_REF);
- error ("argument to decltype must be an expression");
+ gcc_unreachable ();
return error_mark_node;
}
}
else
{
- /* Expressions of reference type are sometimes wrapped in
- INDIRECT_REFs. INDIRECT_REFs are just internal compiler
- representation, not part of the language, so we have to look
- through them. */
- if (TREE_CODE (expr) == INDIRECT_REF
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0)))
- == REFERENCE_TYPE)
- expr = TREE_OPERAND (expr, 0);
-
- if (TREE_CODE (expr) == CALL_EXPR)
- {
- /* If e is a function call (5.2.2 [expr.call]) or an
- invocation of an overloaded operator (parentheses around e
- are ignored), decltype(e) is defined as the return type of
- that function. */
- tree fndecl = get_callee_fndecl (expr);
- if (fndecl && fndecl != error_mark_node)
- type = TREE_TYPE (TREE_TYPE (fndecl));
- else
- {
- tree target_type = TREE_TYPE (CALL_EXPR_FN (expr));
- if ((TREE_CODE (target_type) == REFERENCE_TYPE
- || TREE_CODE (target_type) == POINTER_TYPE)
- && (TREE_CODE (TREE_TYPE (target_type)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (target_type)) == METHOD_TYPE))
- type = TREE_TYPE (TREE_TYPE (target_type));
- else if (processing_template_decl)
- /* Within a template finish_call_expr doesn't resolve
- CALL_EXPR_FN, so even though this decltype isn't really
- dependent let's defer resolving it. */
- goto treat_as_dependent;
- else
- sorry ("unable to determine the declared type of expression %<%E%>",
- expr);
- }
- }
- else
- {
- type = is_bitfield_expr_with_lowered_type (expr);
- if (type)
- {
- /* Bitfields are special, because their type encodes the
- number of bits they store. If the expression referenced a
- bitfield, TYPE now has the declared type of that
- bitfield. */
- type = cp_build_qualified_type (type,
- cp_type_quals (TREE_TYPE (expr)));
-
- if (real_lvalue_p (expr))
- type = build_reference_type (type);
- }
- /* Within a lambda-expression:
-
- Every occurrence of decltype((x)) where x is a possibly
- parenthesized id-expression that names an entity of
- automatic storage duration is treated as if x were
- transformed into an access to a corresponding data member
- of the closure type that would have been declared if x
- were a use of the denoted entity. */
- else if (outer_automatic_var_p (expr)
- && current_function_decl
- && LAMBDA_FUNCTION_P (current_function_decl))
- type = capture_decltype (expr);
- else
- {
- /* Otherwise, where T is the type of e, if e is an lvalue,
- decltype(e) is defined as T&, otherwise decltype(e) is
- defined as T. */
- type = TREE_TYPE (expr);
- if (type == error_mark_node)
- return error_mark_node;
- else if (expr == current_class_ptr)
- /* If the expression is just "this", we want the
- cv-unqualified pointer for the "this" type. */
- type = TYPE_MAIN_VARIANT (type);
- else if (real_lvalue_p (expr))
- {
- if (TREE_CODE (type) != REFERENCE_TYPE)
- type = build_reference_type (type);
- }
- else
- type = non_reference (type);
- }
- }
- }
-
- if (!type || type == unknown_type_node)
- {
- error ("type of %qE is unknown", expr);
- return error_mark_node;
+ /* Within a lambda-expression:
+
+ Every occurrence of decltype((x)) where x is a possibly
+ parenthesized id-expression that names an entity of
+ automatic storage duration is treated as if x were
+ transformed into an access to a corresponding data member
+ of the closure type that would have been declared if x
+ were a use of the denoted entity. */
+ if (outer_automatic_var_p (expr)
+ && current_function_decl
+ && LAMBDA_FUNCTION_P (current_function_decl))
+ type = capture_decltype (expr);
+ else if (error_operand_p (expr))
+ type = error_mark_node;
+ else if (expr == current_class_ptr)
+ /* If the expression is just "this", we want the
+ cv-unqualified pointer for the "this" type. */
+ type = TYPE_MAIN_VARIANT (TREE_TYPE (expr));
+ else
+ {
+ /* Otherwise, where T is the type of e, if e is an lvalue,
+ decltype(e) is defined as T&; if an xvalue, T&&; otherwise, T. */
+ cp_lvalue_kind clk = lvalue_kind (expr);
+ type = unlowered_expr_type (expr);
+ gcc_assert (TREE_CODE (type) != REFERENCE_TYPE);
+ if (clk != clk_none && !(clk & clk_class))
+ type = cp_build_reference_type (type, (clk & clk_rvalueref));
+ }
}
return type;
case CPTK_IS_UNION:
return (type_code1 == UNION_TYPE);
+ case CPTK_IS_LITERAL_TYPE:
+ return (literal_type_p (type1));
+
default:
gcc_unreachable ();
return false;
|| 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
literal_type_p (tree t)
{
- if (SCALAR_TYPE_P (t))
+ if (SCALAR_TYPE_P (t)
+ || TREE_CODE (t) == REFERENCE_TYPE)
return true;
if (CLASS_TYPE_P (t))
return CLASSTYPE_LITERAL_P (t);
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;
+
+/* 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);
+}
+
+/* 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 (!literal_type_p (TREE_TYPE (parm)))
+ {
+ ret = false;
+ if (complain)
+ error ("invalid type for parameter %d of constexpr "
+ "function %q+#D", DECL_PARM_INDEX (parm), fun);
+ }
+
+ if (!DECL_CONSTRUCTOR_P (fun))
+ {
+ tree rettype = TREE_TYPE (TREE_TYPE (fun));
+ if (!literal_type_p (rettype))
+ {
+ ret = false;
+ if (complain)
+ error ("invalid return type %qT of constexpr function %q+D",
+ rettype, fun);
+ }
+
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
+ && !CLASSTYPE_LITERAL_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)))
{
- tree type = TREE_TYPE (parm);
- if (dependent_type_p (type))
- return NULL;
- if (!literal_type_p (type))
- {
- error ("parameter %q#D is not of literal type", parm);
- return NULL;
- }
+ DECL_DECLARED_CONSTEXPR_P (fun) = false;
+ return NULL;
}
- 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))
+ /* 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)
{
- error ("return type %qT of function %qD is not a literal type",
- TREE_TYPE (TREE_TYPE (fun)), fun);
- return 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. */
-/* Constructor for a lambda expression. */
-
-tree
-build_lambda_expr (void)
+static bool
+build_data_member_initialization (tree t, VEC(constructor_elt,gc) **vec)
{
- tree lambda = make_node (LAMBDA_EXPR);
- LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) = CPLD_NONE;
- LAMBDA_EXPR_CAPTURE_LIST (lambda) = NULL_TREE;
- LAMBDA_EXPR_THIS_CAPTURE (lambda) = NULL_TREE;
- LAMBDA_EXPR_RETURN_TYPE (lambda) = NULL_TREE;
- LAMBDA_EXPR_MUTABLE_P (lambda) = false;
- return lambda;
-}
-
-/* Create the closure object for a LAMBDA_EXPR. */
+ tree member, init;
+ if (TREE_CODE (t) == CLEANUP_POINT_EXPR)
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) == EXPR_STMT)
+ t = TREE_OPERAND (t, 0);
+ if (t == error_mark_node)
+ return false;
+ if (TREE_CODE (t) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator i;
+ for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
+ {
+ if (! build_data_member_initialization (tsi_stmt (i), vec))
+ return false;
+ }
+ return true;
+ }
+ if (TREE_CODE (t) == CLEANUP_STMT)
+ {
+ /* We can't see a CLEANUP_STMT in a constructor for a literal class,
+ but we can in a constexpr constructor for a non-literal class. Just
+ ignore it; either all the initialization will be constant, in which
+ case the cleanup can't run, or it can't be constexpr.
+ Still recurse into CLEANUP_BODY. */
+ return build_data_member_initialization (CLEANUP_BODY (t), vec);
+ }
+ if (TREE_CODE (t) == CONVERT_EXPR)
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) == INIT_EXPR
+ || TREE_CODE (t) == MODIFY_EXPR)
+ {
+ member = TREE_OPERAND (t, 0);
+ init = unshare_expr (TREE_OPERAND (t, 1));
+ }
+ else
+ {
+ gcc_assert (TREE_CODE (t) == CALL_EXPR);
+ member = CALL_EXPR_ARG (t, 0);
+ /* We don't use build_cplus_new here because it complains about
+ abstract bases. Leaving the call unwrapped means that it has the
+ wrong type, but cxx_eval_constant_expression doesn't care. */
+ init = unshare_expr (t);
+ }
+ if (TREE_CODE (member) == INDIRECT_REF)
+ member = TREE_OPERAND (member, 0);
+ if (TREE_CODE (member) == NOP_EXPR)
+ {
+ tree op = member;
+ STRIP_NOPS (op);
+ if (TREE_CODE (op) == ADDR_EXPR)
+ {
+ gcc_assert (same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (TREE_TYPE (op)),
+ TREE_TYPE (TREE_TYPE (member))));
+ /* Initializing a cv-qualified member; we need to look through
+ the const_cast. */
+ member = op;
+ }
+ else
+ {
+ /* We don't put out anything for an empty base. */
+ gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (member))));
+ /* But if the initializer isn't constexpr, leave it in so we
+ complain later. */
+ if (potential_constant_expression (init))
+ return true;
+ }
+ }
+ if (TREE_CODE (member) == ADDR_EXPR)
+ member = TREE_OPERAND (member, 0);
+ if (TREE_CODE (member) == COMPONENT_REF
+ /* If we're initializing a member of a subaggregate, it's a vtable
+ pointer. Leave it as COMPONENT_REF so we remember the path to get
+ to the vfield. */
+ && TREE_CODE (TREE_OPERAND (member, 0)) != COMPONENT_REF)
+ member = TREE_OPERAND (member, 1);
+ CONSTRUCTOR_APPEND_ELT (*vec, member, init);
+ return true;
+}
+
+/* Make sure that there are no statements after LAST in the constructor
+ body represented by LIST. */
+
+bool
+check_constexpr_ctor_body (tree last, tree list)
+{
+ bool ok = true;
+ if (TREE_CODE (list) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator i = tsi_last (list);
+ for (; !tsi_end_p (i); tsi_prev (&i))
+ {
+ tree t = tsi_stmt (i);
+ if (t == last)
+ break;
+ if (TREE_CODE (t) == BIND_EXPR)
+ {
+ if (!check_constexpr_ctor_body (last, BIND_EXPR_BODY (t)))
+ return false;
+ else
+ continue;
+ }
+ /* We currently allow typedefs and static_assert.
+ FIXME allow them in the standard, too. */
+ if (TREE_CODE (t) != STATIC_ASSERT)
+ {
+ ok = false;
+ break;
+ }
+ }
+ }
+ else if (list != last
+ && TREE_CODE (list) != STATIC_ASSERT)
+ ok = false;
+ if (!ok)
+ {
+ error ("constexpr constructor does not have empty body");
+ DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false;
+ }
+ return ok;
+}
+
+/* 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) == STATEMENT_LIST)
+ body = STATEMENT_LIST_HEAD (body)->stmt;
+ body = BIND_EXPR_BODY (body);
+ if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
+ {
+ body = TREE_OPERAND (body, 0);
+ if (TREE_CODE (body) == EXPR_STMT)
+ body = TREE_OPERAND (body, 0);
+ if (TREE_CODE (body) == INIT_EXPR
+ && (same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (TREE_OPERAND (body, 0)),
+ current_class_type)))
+ {
+ /* Trivial copy. */
+ return TREE_OPERAND (body, 1);
+ }
+ ok = build_data_member_initialization (body, &vec);
+ }
+ else if (TREE_CODE (body) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator i;
+ for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
+ {
+ ok = build_data_member_initialization (tsi_stmt (i), &vec);
+ if (!ok)
+ break;
+ }
+ }
+ else
+ gcc_assert (errorcount > 0);
+ if (ok)
+ return build_constructor (type, vec);
+ else
+ return error_mark_node;
+}
+
+/* Subroutine of register_constexpr_fundef. BODY is the body of a function
+ declared to be constexpr, or a sub-statement thereof. Returns the
+ return value if suitable, error_mark_node for a statement not allowed in
+ a constexpr function, or NULL_TREE if no return value was found. */
+
+static tree
+constexpr_fn_retval (tree body)
+{
+ switch (TREE_CODE (body))
+ {
+ case STATEMENT_LIST:
+ {
+ tree_stmt_iterator i;
+ tree expr = NULL_TREE;
+ for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
+ {
+ tree s = constexpr_fn_retval (tsi_stmt (i));
+ if (s == error_mark_node)
+ return error_mark_node;
+ else if (s == NULL_TREE)
+ /* Keep iterating. */;
+ else if (expr)
+ /* Multiple return statements. */
+ return error_mark_node;
+ else
+ expr = s;
+ }
+ return expr;
+ }
+
+ case RETURN_EXPR:
+ return unshare_expr (TREE_OPERAND (body, 0));
+
+ case DECL_EXPR:
+ if (TREE_CODE (DECL_EXPR_DECL (body)) == USING_DECL)
+ return NULL_TREE;
+ return error_mark_node;
+
+ case USING_STMT:
+ return NULL_TREE;
+
+ default:
+ 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);
+ body = constexpr_fn_retval (body);
+ if (body == NULL_TREE || body == error_mark_node)
+ {
+ error ("body of constexpr function %qD not a return-statement", fun);
+ DECL_DECLARED_CONSTEXPR_P (fun) = false;
+ return NULL;
+ }
+ }
+
+ if (!potential_rvalue_constant_expression (body))
+ {
+ DECL_DECLARED_CONSTEXPR_P (fun) = false;
+ if (!DECL_TEMPLATE_INSTANTIATION (fun))
+ require_potential_rvalue_constant_expression (body);
+ 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 cp_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;
+ if (*non_constant_p)
+ /* Don't try to adjust the type of non-constant args. */
+ goto next;
+
+ /* Make sure the binding has the same type as the parm. */
+ if (TREE_CODE (type) != REFERENCE_TYPE)
+ arg = adjust_temp_type (type, arg);
+ 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. */
+
+/* FIXME remember and print actual constant arguments. */
+static VEC(tree,heap) *call_stack = NULL;
+static int call_stack_tick;
+static int last_cx_error_tick;
+
+static bool
+push_cx_call_context (tree call)
+{
+ ++call_stack_tick;
+ if (!EXPR_HAS_LOCATION (call))
+ SET_EXPR_LOCATION (call, input_location);
+ VEC_safe_push (tree, heap, call_stack, call);
+ if (VEC_length (tree, call_stack) > (unsigned) max_constexpr_depth)
+ return false;
+ return true;
+}
+
+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;
+ constexpr_call *entry;
+ bool depth_ok;
+
+ 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;
+ }
+
+ /* Shortcut trivial copy constructor/op=. */
+ if (call_expr_nargs (t) == 2 && trivial_fn_p (fun))
+ {
+ tree arg = convert_from_reference (get_nth_callarg (t, 1));
+ return cxx_eval_constant_expression (old_call, arg, allow_non_constant,
+ addr, non_constant_p);
+ }
+
+ /* 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;
+
+ depth_ok = 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);
+ entry = *slot;
+ if (entry == NULL)
+ {
+ /* We need to keep a pointer to the entry, not just the slot, as the
+ slot can move in the call to cxx_eval_builtin_function_call. */
+ *slot = entry = ggc_alloc_constexpr_call ();
+ *entry = new_call;
+ }
+ /* Calls which are in progress have their result set to NULL
+ so that we can detect circular dependencies. */
+ else if (entry->result == NULL)
+ {
+ if (!allow_non_constant)
+ error ("call has circular dependency");
+ *non_constant_p = true;
+ entry->result = result = error_mark_node;
+ }
+
+ if (!depth_ok)
+ {
+ if (!allow_non_constant)
+ error ("constexpr evaluation depth exceeds maximum of %d (use "
+ "-fconstexpr-depth= to increase the maximum)",
+ max_constexpr_depth);
+ *non_constant_p = true;
+ entry->result = result = error_mark_node;
+ }
+ else
+ {
+ result = entry->result;
+ if (!result || (result == error_mark_node && !allow_non_constant))
+ result = (cxx_eval_constant_expression
+ (&new_call, new_call.fundef->body,
+ allow_non_constant, addr,
+ non_constant_p));
+ if (result == error_mark_node)
+ *non_constant_p = true;
+ 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 unshare_expr (result);
+}
+
+/* FIXME speed this up, it's taking 16% of compile time on sieve testcase. */
+
+bool
+reduced_constant_expression_p (tree t)
+{
+ if (TREE_OVERFLOW_P (t))
+ /* Integer overflow makes this not a constant expression. */
+ 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)
+ {
+ /* If T was already folded to a _CST with TREE_OVERFLOW set,
+ printing the folded constant isn't helpful. */
+ if (TREE_OVERFLOW_P (t))
+ {
+ permerror (input_location, "overflow in constant expression");
+ /* If we're being permissive (and are in an enforcing
+ context), consider this constant. */
+ if (flag_permissive)
+ return false;
+ }
+ else
+ error ("%q+E 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, elem_nchars = 1;
+ 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);
+ if (TREE_CODE (ary) == CONSTRUCTOR)
+ len = CONSTRUCTOR_NELTS (ary);
+ else
+ {
+ elem_nchars = (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (ary)))
+ / TYPE_PRECISION (char_type_node));
+ len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
+ }
+ 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 if (elem_nchars == 1)
+ return build_int_cst (cv_unqualified (TREE_TYPE (TREE_TYPE (ary))),
+ TREE_STRING_POINTER (ary)[i]);
+ else
+ {
+ tree type = cv_unqualified (TREE_TYPE (TREE_TYPE (ary)));
+ return native_interpret_expr (type, (const unsigned char *)
+ TREE_STRING_POINTER (ary)
+ + i * elem_nchars, elem_nchars);
+ }
+ /* Don't VERIFY_CONSTANT here. */
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+ Attempt to reduce a field access of a value of class type. */
+
+static tree
+cxx_eval_component_reference (const constexpr_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.
+ Attempt to reduce a field access of a value of class type that is
+ expressed as a BIT_FIELD_REF. */
+
+static tree
+cxx_eval_bit_field_ref (const constexpr_call *call, tree t,
+ bool allow_non_constant, bool addr,
+ bool *non_constant_p)
+{
+ tree orig_whole = TREE_OPERAND (t, 0);
+ tree whole = cxx_eval_constant_expression (call, orig_whole,
+ allow_non_constant, addr,
+ non_constant_p);
+ tree start, field, value;
+ unsigned HOST_WIDE_INT i;
+
+ if (whole == orig_whole)
+ return t;
+ /* Don't VERIFY_CONSTANT here; we only want to check that we got a
+ CONSTRUCTOR. */
+ if (!*non_constant_p && TREE_CODE (whole) != CONSTRUCTOR)
+ {
+ if (!allow_non_constant)
+ error ("%qE is not a constant expression", orig_whole);
+ *non_constant_p = true;
+ }
+ if (*non_constant_p)
+ return t;
+
+ start = TREE_OPERAND (t, 2);
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value)
+ {
+ if (bit_position (field) == start)
+ return value;
+ }
+ 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;
+}
+
+/* REF is a COMPONENT_REF designating a particular field. V is a vector of
+ CONSTRUCTOR elements to initialize (part of) an object containing that
+ field. Return a pointer to the constructor_elt corresponding to the
+ initialization of the field. */
+
+static constructor_elt *
+base_field_constructor_elt (VEC(constructor_elt,gc) *v, tree ref)
+{
+ tree aggr = TREE_OPERAND (ref, 0);
+ tree field = TREE_OPERAND (ref, 1);
+ HOST_WIDE_INT i;
+ constructor_elt *ce;
+
+ gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
+
+ if (TREE_CODE (aggr) == COMPONENT_REF)
+ {
+ constructor_elt *base_ce
+ = base_field_constructor_elt (v, aggr);
+ v = CONSTRUCTOR_ELTS (base_ce->value);
+ }
+
+ for (i = 0; VEC_iterate (constructor_elt, v, i, ce); ++i)
+ if (ce->index == field)
+ return ce;
+
+ gcc_unreachable ();
+ return NULL;
+}
+
+/* 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;
+ 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 (ce->index) == COMPONENT_REF)
+ {
+ /* This is an initialization of a vfield inside a base
+ subaggregate that we already initialized; push this
+ initialization into the previous initialization. */
+ constructor_elt *inner = base_field_constructor_elt (n, ce->index);
+ inner->value = elt;
+ }
+ 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 apart from value-initialization (when VALUE_INIT is true),
+ this is only intended to support value-initialization and the
+ initializations done by defaulted constructors for classes with
+ non-static data members of array type. In this case, VEC_INIT_EXPR_INIT
+ will either be NULL_TREE for the default constructor, or a COMPONENT_REF
+ for the copy/move constructor. */
+
+static tree
+cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init,
+ bool value_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 (value_init)
+ gcc_assert (!init);
+ else 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. */
+ if (value_init)
+ eltinit = NULL_TREE;
+ else
+ eltinit = cp_build_array_ref (input_location, init, idx,
+ tf_warning_or_error);
+ eltinit = cxx_eval_vec_init_1 (call, elttype, eltinit, value_init,
+ allow_non_constant, addr,
+ non_constant_p);
+ }
+ else if (value_init)
+ {
+ eltinit = build_value_init (elttype, tf_warning_or_error);
+ eltinit = cxx_eval_constant_expression
+ (call, 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,
+ VEC_INIT_EXPR_VALUE_INIT (t),
+ 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;
+}
+
+/* Complain about R, a VAR_DECL, not being usable in a constant expression.
+ Shared between potential_constant_expression and
+ cxx_eval_constant_expression. */
+
+static void
+non_const_var_error (tree r)
+{
+ tree type = TREE_TYPE (r);
+ error ("the value of %qD is not usable in a constant "
+ "expression", r);
+ /* Avoid error cascade. */
+ if (DECL_INITIAL (r) == error_mark_node)
+ return;
+ if (DECL_DECLARED_CONSTEXPR_P (r))
+ inform (DECL_SOURCE_LOCATION (r),
+ "%qD used in its own initializer", r);
+ else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type))
+ {
+ if (!CP_TYPE_CONST_P (type))
+ inform (DECL_SOURCE_LOCATION (r),
+ "%q#D is not const", r);
+ else if (CP_TYPE_VOLATILE_P (type))
+ inform (DECL_SOURCE_LOCATION (r),
+ "%q#D is volatile", r);
+ else if (!DECL_INITIAL (r))
+ 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);
+ }
+}
+
+/* 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)
+ non_const_var_error (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
+ {
+ /* Check that the LHS is constant and then discard it. */
+ cxx_eval_constant_expression (call, op0, allow_non_constant,
+ false, non_constant_p);
+ r = cxx_eval_constant_expression (call, op1, allow_non_constant,
+ addr, non_constant_p);
+ }
+ }
+ 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:
+ 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 BIT_FIELD_REF:
+ r = cxx_eval_bit_field_ref (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);
+ /* Conversion of an out-of-range value has implementation-defined
+ behavior; the language considers it different from arithmetic
+ overflow, which is undefined. */
+ if (TREE_OVERFLOW_P (r) && !TREE_OVERFLOW_P (op))
+ TREE_OVERFLOW (r) = false;
+ }
+ break;
+
+ case EMPTY_CLASS_EXPR:
+ /* This is good enough for a function argument that might not get
+ used, and they can't do anything with it, so just return it. */
+ return t;
+
+ case 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:
+ case OFFSET_REF:
+ 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);
+
+ verify_constant (r, allow_non_constant, &non_constant_p);
+
+ 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)
+ || type_unknown_p (t)
+ || !potential_constant_expression (t)
+ || 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;
+}
+
+#if 0
+/* FIXME see ADDR_EXPR section in potential_constant_expression_1. */
+/* Return true if the object referred to by REF has automatic or thread
+ local storage. */
+
+enum { ck_ok, ck_bad, ck_unknown };
+static int
+check_automatic_or_tls (tree ref)
+{
+ 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;
+}
+#endif
+
+/* 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 potentially constant expression. Issue
+ diagnostic as appropriate under control of FLAGS. If WANT_RVAL is true,
+ an lvalue-rvalue conversion is implied.
+
+ C++0x [expr.const] used to say
+
+ 6 An expression is a potential constant expression if it is
+ a constant expression where all 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_1 (tree t, bool want_rval, tsubst_flags_t flags)
+{
+ enum { any = false, rval = true };
+ int i;
+ tree tmp;
+
+ /* C++98 has different rules for the form of a constant expression that
+ are enforced in the parser, so we can assume that anything that gets
+ this far is suitable. */
+ if (cxx_dialect < cxx0x)
+ return true;
+
+ if (t == error_mark_node)
+ return false;
+ if (t == NULL_TREE)
+ return true;
+ if (TREE_THIS_VOLATILE (t))
+ {
+ if (flags & tf_error)
+ error ("expression %qE has side-effects", t);
+ return false;
+ }
+ if (CONSTANT_CLASS_P (t))
+ {
+ if (TREE_OVERFLOW (t))
+ {
+ if (flags & tf_error)
+ {
+ permerror (EXPR_LOC_OR_HERE (t),
+ "overflow in constant expression");
+ if (flag_permissive)
+ return true;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ switch (TREE_CODE (t))
+ {
+ case FUNCTION_DECL:
+ case BASELINK:
+ case TEMPLATE_DECL:
+ case OVERLOAD:
+ case TEMPLATE_ID_EXPR:
+ case LABEL_DECL:
+ case CONST_DECL:
+ case SIZEOF_EXPR:
+ case ALIGNOF_EXPR:
+ case OFFSETOF_EXPR:
+ case NOEXCEPT_EXPR:
+ case TEMPLATE_PARM_INDEX:
+ case TRAIT_EXPR:
+ case IDENTIFIER_NODE:
+ 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); */
+ /* FIXME this restriction seems pointless since the standard dropped
+ "potential constant expression". */
+ 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);
+ i = 0;
+
+ if (is_overloaded_fn (fun))
+ {
+ if (TREE_CODE (fun) == FUNCTION_DECL)
+ {
+ if (builtin_valid_in_constant_expr_p (fun))
+ return true;
+ if (!DECL_DECLARED_CONSTEXPR_P (fun)
+ && !morally_constexpr_builtin_function_p (fun))
+ {
+ if (flags & tf_error)
+ error ("%qD is not %<constexpr%>", fun);
+ return false;
+ }
+ /* A call to a non-static member function takes the address
+ of the object as the first argument. But in a constant
+ expression the address will be folded away, so look
+ through it now. */
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
+ && !DECL_CONSTRUCTOR_P (fun))
+ {
+ tree x = get_nth_callarg (t, 0);
+ if (is_this_parameter (x))
+ /* OK. */;
+ else if (!potential_constant_expression_1 (x, rval, flags))
+ {
+ if (flags & tf_error)
+ error ("object argument is not a potential "
+ "constant expression");
+ return false;
+ }
+ i = 1;
+ }
+ }
+ else
+ fun = get_first_fn (fun);
+ /* Skip initial arguments to base constructors. */
+ if (DECL_BASE_CONSTRUCTOR_P (fun))
+ i = num_artificial_parms_for (fun);
+ fun = DECL_ORIGIN (fun);
+ }
+ else
+ {
+ if (potential_constant_expression_1 (fun, rval, flags))
+ /* Might end up being a constant function pointer. */;
+ else
+ {
+ if (flags & tf_error)
+ error ("%qE is not a function name", fun);
+ return false;
+ }
+ }
+ for (; i < nargs; ++i)
+ {
+ tree x = get_nth_callarg (t, i);
+ if (!potential_constant_expression_1 (x, rval, 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_1 (TREE_OPERAND (t, 0), rval, flags);
+
+ case VAR_DECL:
+ if (want_rval && !decl_constant_var_p (t)
+ && !dependent_type_p (TREE_TYPE (t)))
+ {
+ if (flags & tf_error)
+ non_const_var_error (t);
+ return false;
+ }
+ return true;
+
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case VIEW_CONVERT_EXPR:
+ /* -- 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_1
+ (from, TREE_CODE (t) != VIEW_CONVERT_EXPR, 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);
+#if 0
+ /* FIXME adjust when issue 1197 is fully resolved. For now don't do
+ any checking here, as we might dereference the pointer later. If
+ we remove this code, also remove check_automatic_or_tls. */
+ i = check_automatic_or_tls (t);
+ if (i == ck_ok)
+ return true;
+ if (i == ck_bad)
+ {
+ if (flags & tf_error)
+ error ("address-of an object %qE with thread local or "
+ "automatic storage is not a constant expression", t);
+ return false;
+ }
+#endif
+ return potential_constant_expression_1 (t, any, flags);
+
+ case COMPONENT_REF:
+ case BIT_FIELD_REF:
+ case ARROW_EXPR:
+ case OFFSET_REF:
+ /* -- a class member access unless its postfix-expression is
+ of literal type or of pointer to literal type. */
+ /* This test would be redundant, as it follows from the
+ postfix-expression being a potential constant expression. */
+ return potential_constant_expression_1 (TREE_OPERAND (t, 0),
+ want_rval, flags);
+
+ case EXPR_PACK_EXPANSION:
+ return potential_constant_expression_1 (PACK_EXPANSION_PATTERN (t),
+ want_rval, flags);
+
+ case INDIRECT_REF:
+ {
+ tree x = TREE_OPERAND (t, 0);
+ STRIP_NOPS (x);
+ if (is_this_parameter (x))
+ {
+ if (DECL_CONSTRUCTOR_P (DECL_CONTEXT (x)) && want_rval)
+ {
+ if (flags & tf_error)
+ sorry ("use of the value of the object being constructed "
+ "in a constant expression");
+ return false;
+ }
+ return true;
+ }
+ return potential_constant_expression_1 (x, rval, 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:
+ /* Don't bother trying to define a subset of statement-expressions to
+ be constant-expressions, at least for now. */
+ case STMT_EXPR:
+ case EXPR_STMT:
+ 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_dependent_expression_p (e)
+ && TYPE_POLYMORPHIC_P (TREE_TYPE (e)))
+ {
+ if (flags & tf_error)
+ error ("typeid-expression is not a constant expression "
+ "because %qE is of polymorphic type", e);
+ return false;
+ }
+ return true;
+ }
+
+ case MINUS_EXPR:
+ /* -- a subtraction where both operands are pointers. */
+ if (TYPE_PTR_P (TREE_OPERAND (t, 0))
+ && TYPE_PTR_P (TREE_OPERAND (t, 1)))
+ {
+ if (flags & tf_error)
+ error ("difference of two pointer expressions is not "
+ "a constant expression");
+ return false;
+ }
+ want_rval = true;
+ goto binary;
+
+ case LT_EXPR:
+ case LE_EXPR:
+ case GT_EXPR:
+ case GE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ /* -- a relational or equality operator where at least
+ one of the operands is a pointer. */
+ if (TYPE_PTR_P (TREE_OPERAND (t, 0))
+ || TYPE_PTR_P (TREE_OPERAND (t, 1)))
+ {
+ if (flags & tf_error)
+ error ("pointer comparison expression is not a "
+ "constant expression");
+ return false;
+ }
+ want_rval = true;
+ goto binary;
+
+ case 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 FIXED_CONVERT_EXPR:
+ case UNARY_PLUS_EXPR:
+ return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval,
+ flags);
+
+ case CAST_EXPR:
+ case CONST_CAST_EXPR:
+ case STATIC_CAST_EXPR:
+ case REINTERPRET_CAST_EXPR:
+ return (potential_constant_expression_1
+ (TREE_OPERAND (t, 0),
+ TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE, flags));
+
+ case PAREN_EXPR:
+ case NON_DEPENDENT_EXPR:
+ /* For convenience. */
+ case RETURN_EXPR:
+ return potential_constant_expression_1 (TREE_OPERAND (t, 0),
+ want_rval, flags);
+
+ case SCOPE_REF:
+ return potential_constant_expression_1 (TREE_OPERAND (t, 1),
+ want_rval, flags);
+
+ case INIT_EXPR:
+ case TARGET_EXPR:
+ return potential_constant_expression_1 (TREE_OPERAND (t, 1),
+ rval, 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_1 (ce->value, want_rval, flags))
+ return false;
+ return true;
+ }
+
+ case TREE_LIST:
+ {
+ gcc_assert (TREE_PURPOSE (t) == NULL_TREE
+ || DECL_P (TREE_PURPOSE (t)));
+ if (!potential_constant_expression_1 (TREE_VALUE (t), want_rval,
+ flags))
+ return false;
+ if (TREE_CHAIN (t) == NULL_TREE)
+ return true;
+ return potential_constant_expression_1 (TREE_CHAIN (t), want_rval,
+ 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:
+ {
+ tree denom = TREE_OPERAND (t, 1);
+ /* We can't call maybe_constant_value on an expression
+ that hasn't been through fold_non_dependent_expr yet. */
+ if (!processing_template_decl)
+ denom = maybe_constant_value (denom);
+ if (integer_zerop (denom))
+ {
+ if (flags & tf_error)
+ error ("division by zero is not a constant-expression");
+ return false;
+ }
+ else
+ {
+ want_rval = true;
+ 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_1 (op0, want_rval, 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_1 (TREE_OPERAND (t, 1), rval, flags);
+ else
+ return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval, flags);
+
+ case PLUS_EXPR:
+ case MULT_EXPR:
+ case POINTER_PLUS_EXPR:
+ case RDIV_EXPR:
+ case EXACT_DIV_EXPR:
+ case MIN_EXPR:
+ case MAX_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_AND_EXPR:
+ case TRUTH_XOR_EXPR:
+ case UNORDERED_EXPR:
+ case ORDERED_EXPR:
+ case UNLT_EXPR:
+ case UNLE_EXPR:
+ case UNGT_EXPR:
+ case UNGE_EXPR:
+ case UNEQ_EXPR:
+ case RANGE_EXPR:
+ case COMPLEX_EXPR:
+ want_rval = true;
+ /* Fall through. */
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ case MEMBER_REF:
+ case DOTSTAR_EXPR:
+ binary:
+ for (i = 0; i < 2; ++i)
+ if (!potential_constant_expression_1 (TREE_OPERAND (t, i),
+ want_rval, 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_1 (tmp, rval, flags))
+ return false;
+ else if (tmp == boolean_true_node)
+ return potential_constant_expression_1 (TREE_OPERAND (t, 1),
+ want_rval, flags);
+ else if (tmp == boolean_false_node)
+ return potential_constant_expression_1 (TREE_OPERAND (t, 2),
+ want_rval, flags);
+ for (i = 1; i < 3; ++i)
+ if (potential_constant_expression_1 (TREE_OPERAND (t, i),
+ want_rval, tf_none))
+ return true;
+ if (flags & tf_error)
+ error ("expression %qE is not a constant-expression", t);
+ return false;
+
+ case VEC_INIT_EXPR:
+ if (VEC_INIT_EXPR_IS_CONSTEXPR (t))
+ return true;
+ if (flags & tf_error)
+ {
+ error ("non-constant array initialization");
+ diagnose_non_constexpr_vec_init (t);
+ }
+ return false;
+
+ default:
+ sorry ("unexpected ast of kind %s", tree_code_name[TREE_CODE (t)]);
+ gcc_unreachable();
+ return false;
+ }
+}
+
+/* The main entry point to the above. */
+
+bool
+potential_constant_expression (tree t)
+{
+ return potential_constant_expression_1 (t, false, tf_none);
+}
+
+/* As above, but require a constant rvalue. */
+
+bool
+potential_rvalue_constant_expression (tree t)
+{
+ return potential_constant_expression_1 (t, true, tf_none);
+}
+
+/* Like above, but complain about non-constant expressions. */
+
+bool
+require_potential_constant_expression (tree t)
+{
+ return potential_constant_expression_1 (t, false, tf_warning_or_error);
+}
+
+/* Cross product of the above. */
+
+bool
+require_potential_rvalue_constant_expression (tree t)
+{
+ return potential_constant_expression_1 (t, true, tf_warning_or_error);
+}
+\f
+/* Constructor for a lambda expression. */
+
+tree
+build_lambda_expr (void)
+{
+ tree lambda = make_node (LAMBDA_EXPR);
+ LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) = CPLD_NONE;
+ LAMBDA_EXPR_CAPTURE_LIST (lambda) = NULL_TREE;
+ LAMBDA_EXPR_THIS_CAPTURE (lambda) = NULL_TREE;
+ LAMBDA_EXPR_RETURN_TYPE (lambda) = NULL_TREE;
+ LAMBDA_EXPR_MUTABLE_P (lambda) = false;
+ return lambda;
+}
+
+/* Create the closure object for a LAMBDA_EXPR. */
tree
build_lambda_object (tree lambda_expr)
tree field = TREE_PURPOSE (node);
tree val = TREE_VALUE (node);
+ if (field == error_mark_node)
+ {
+ expr = error_mark_node;
+ goto out;
+ }
+
if (DECL_P (val))
mark_used (val);
There's normally no way to express direct-initialization
from an element of a CONSTRUCTOR, so we build up a special
TARGET_EXPR to bypass the usual copy-initialization. */
- val = force_rvalue (val);
+ val = force_rvalue (val, tf_warning_or_error);
if (TREE_CODE (val) == TARGET_EXPR)
TARGET_EXPR_DIRECT_INIT_P (val) = true;
}
But we briefly treat it as an aggregate to make this simpler. */
type = TREE_TYPE (lambda_expr);
CLASSTYPE_NON_AGGREGATE (type) = 0;
- expr = finish_compound_literal (type, expr);
+ expr = finish_compound_literal (type, expr, tf_warning_or_error);
CLASSTYPE_NON_AGGREGATE (type) = 1;
+ out:
input_location = saved_loc;
return expr;
}
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;
/* Put the thunk in the same comdat group as the call op. */
struct cgraph_node *callop_node, *thunk_node;
DECL_COMDAT_GROUP (statfn) = DECL_COMDAT_GROUP (callop);
- callop_node = cgraph_node (callop);
- thunk_node = cgraph_node (statfn);
+ callop_node = cgraph_get_create_node (callop);
+ thunk_node = cgraph_get_create_node (statfn);
gcc_assert (callop_node->same_comdat_group == NULL);
gcc_assert (thunk_node->same_comdat_group == NULL);
callop_node->same_comdat_group = thunk_node;
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));
CALL_FROM_THUNK_P (call) = 1;
if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
- call = build_cplus_new (TREE_TYPE (call), call);
+ call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
call = convert_from_reference (call);
finish_return_stmt (call);