#include "c-family/c-objc.h"
#include "tree-inline.h"
#include "tree-mudflap.h"
+#include "intl.h"
#include "toplev.h"
#include "flags.h"
#include "output.h"
expression. The reason why we do this is because the original type might be
an aggregate and we cannot create a temporary variable for that type. */
-static tree
+tree
maybe_cleanup_point_expr_void (tree expr)
{
if (!processing_template_decl && stmts_are_full_exprs_p ())
/* This inhibits warnings in c_common_truthvalue_conversion. */
TREE_NO_WARNING (expr) = 1;
- if (TREE_CODE (expr) == OFFSET_REF)
+ if (TREE_CODE (expr) == OFFSET_REF
+ || TREE_CODE (expr) == SCOPE_REF)
/* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be
enclosed in parentheses. */
PTRMEM_OK_P (expr) = 0;
expressions with no type as being dependent. */
if (type_dependent_expression_p (fn)
|| any_type_dependent_arguments_p (*args)
- /* For a non-static member function, we need to specifically
+ /* For a non-static member function that doesn't have an
+ explicit object argument, 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. */
- || (non_static_member_function_p (fn)
+ || (TREE_CODE (fn) != COMPONENT_REF
+ && non_static_member_function_p (fn)
&& current_class_ref
&& type_dependent_expression_p (current_class_ref)))
{
finish_unary_op_expr (enum tree_code code, tree expr)
{
tree result = build_x_unary_op (code, expr, tf_warning_or_error);
- /* Inside a template, build_x_unary_op does not fold the
- expression. So check whether the result is folded before
- setting TREE_NEGATED_INT. */
- if (code == NEGATE_EXPR && TREE_CODE (expr) == INTEGER_CST
- && TREE_CODE (result) == INTEGER_CST
- && !TYPE_UNSIGNED (TREE_TYPE (result))
- && INT_CST_LT (result, integer_zero_node))
- {
- /* RESULT may be a cached INTEGER_CST, so we must copy it before
- setting TREE_NEGATED_INT. */
- result = copy_node (result);
- TREE_NEGATED_INT (result) = 1;
- }
if (TREE_OVERFLOW_P (result) && !TREE_OVERFLOW_P (expr))
overflow_warning (input_location, result);
&& check_array_initializer (NULL_TREE, type, compound_literal))
return error_mark_node;
compound_literal = reshape_init (type, compound_literal, complain);
+ if (SCALAR_TYPE_P (type)
+ && !BRACE_ENCLOSED_INITIALIZER_P (compound_literal))
+ check_narrowing (type, compound_literal);
if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_DOMAIN (type) == NULL_TREE)
{
tree
finish_template_type (tree name, tree args, int entering_scope)
{
- tree decl;
+ tree type;
- decl = lookup_template_class (name, args,
+ type = lookup_template_class (name, args,
NULL_TREE, NULL_TREE, entering_scope,
tf_warning_or_error | tf_user);
- if (decl != error_mark_node)
- decl = TYPE_STUB_DECL (decl);
-
- return decl;
+ if (type == error_mark_node)
+ return type;
+ else if (CLASS_TYPE_P (type) && !alias_type_or_template_p (type))
+ return TYPE_STUB_DECL (type);
+ else
+ return TYPE_NAME (type);
}
/* Finish processing a BASE_CLASS with the indicated ACCESS_SPECIFIER.
tree containing_function = current_function_decl;
tree lambda_stack = NULL_TREE;
tree lambda_expr = NULL_TREE;
- tree initializer = decl;
+ tree initializer = convert_from_reference (decl);
+
+ /* Mark it as used now even if the use is ill-formed. */
+ mark_used (decl);
/* Core issue 696: "[At the July 2009 meeting] the CWG expressed
support for an approach in which a reference to a local
else
{
error (TREE_CODE (decl) == VAR_DECL
- ? "use of %<auto%> variable from containing function"
- : "use of parameter from containing function");
+ ? G_("use of %<auto%> variable from containing function")
+ : G_("use of parameter from containing function"));
error (" %q+#D declared here", decl);
return error_mark_node;
}
if (scope)
{
decl = (adjust_result_of_qualified_name_lookup
- (decl, scope, current_class_type));
+ (decl, scope, current_nonlambda_class_type()));
if (TREE_CODE (decl) == FUNCTION_DECL)
mark_used (decl);
if (TREE_CODE (first_fn) == TEMPLATE_DECL)
first_fn = DECL_TEMPLATE_RESULT (first_fn);
- if (!really_overloaded_fn (decl))
- mark_used (first_fn);
+ if (!really_overloaded_fn (decl)
+ && !mark_used (first_fn))
+ return error_mark_node;
if (!template_arg_p
&& TREE_CODE (first_fn) == FUNCTION_DECL
return underlying_type;
}
+/* Implement the __direct_bases keyword: Return the direct base classes
+ of type */
+
+tree
+calculate_direct_bases (tree type)
+{
+ VEC(tree, gc) *vector = make_tree_vector();
+ tree bases_vec = NULL_TREE;
+ VEC(tree, none) *base_binfos;
+ tree binfo;
+ unsigned i;
+
+ complete_type (type);
+
+ if (!NON_UNION_CLASS_TYPE_P (type))
+ return make_tree_vec (0);
+
+ base_binfos = BINFO_BASE_BINFOS (TYPE_BINFO (type));
+
+ /* Virtual bases are initialized first */
+ for (i = 0; VEC_iterate (tree, base_binfos, i, binfo); i++)
+ {
+ if (BINFO_VIRTUAL_P (binfo))
+ {
+ VEC_safe_push (tree, gc, vector, binfo);
+ }
+ }
+
+ /* Now non-virtuals */
+ for (i = 0; VEC_iterate (tree, base_binfos, i, binfo); i++)
+ {
+ if (!BINFO_VIRTUAL_P (binfo))
+ {
+ VEC_safe_push (tree, gc, vector, binfo);
+ }
+ }
+
+
+ bases_vec = make_tree_vec (VEC_length (tree, vector));
+
+ for (i = 0; i < VEC_length (tree, vector); ++i)
+ {
+ TREE_VEC_ELT (bases_vec, i) = BINFO_TYPE (VEC_index (tree, vector, i));
+ }
+ return bases_vec;
+}
+
+/* Implement the __bases keyword: Return the base classes
+ of type */
+
+/* Find morally non-virtual base classes by walking binfo hierarchy */
+/* Virtual base classes are handled separately in finish_bases */
+
+static tree
+dfs_calculate_bases_pre (tree binfo, ATTRIBUTE_UNUSED void *data_)
+{
+ /* Don't walk bases of virtual bases */
+ return BINFO_VIRTUAL_P (binfo) ? dfs_skip_bases : NULL_TREE;
+}
+
+static tree
+dfs_calculate_bases_post (tree binfo, void *data_)
+{
+ VEC(tree, gc) **data = (VEC(tree, gc) **) data_;
+ if (!BINFO_VIRTUAL_P (binfo))
+ {
+ VEC_safe_push (tree, gc, *data, BINFO_TYPE (binfo));
+ }
+ return NULL_TREE;
+}
+
+/* Calculates the morally non-virtual base classes of a class */
+static VEC(tree, gc) *
+calculate_bases_helper (tree type)
+{
+ VEC(tree, gc) *vector = make_tree_vector();
+
+ /* Now add non-virtual base classes in order of construction */
+ dfs_walk_all (TYPE_BINFO (type),
+ dfs_calculate_bases_pre, dfs_calculate_bases_post, &vector);
+ return vector;
+}
+
+tree
+calculate_bases (tree type)
+{
+ VEC(tree, gc) *vector = make_tree_vector();
+ tree bases_vec = NULL_TREE;
+ unsigned i;
+ VEC(tree, gc) *vbases;
+ VEC(tree, gc) *nonvbases;
+ tree binfo;
+
+ complete_type (type);
+
+ if (!NON_UNION_CLASS_TYPE_P (type))
+ return make_tree_vec (0);
+
+ /* First go through virtual base classes */
+ for (vbases = CLASSTYPE_VBASECLASSES (type), i = 0;
+ VEC_iterate (tree, vbases, i, binfo); i++)
+ {
+ VEC(tree, gc) *vbase_bases = calculate_bases_helper (BINFO_TYPE (binfo));
+ VEC_safe_splice (tree, gc, vector, vbase_bases);
+ release_tree_vector (vbase_bases);
+ }
+
+ /* Now for the non-virtual bases */
+ nonvbases = calculate_bases_helper (type);
+ VEC_safe_splice (tree, gc, vector, nonvbases);
+ release_tree_vector (nonvbases);
+
+ /* Last element is entire class, so don't copy */
+ bases_vec = make_tree_vec (VEC_length (tree, vector) - 1);
+
+ for (i = 0; i < VEC_length (tree, vector) - 1; ++i)
+ {
+ TREE_VEC_ELT (bases_vec, i) = VEC_index (tree, vector, i);
+ }
+ release_tree_vector (vector);
+ return bases_vec;
+}
+
+tree
+finish_bases (tree type, bool direct)
+{
+ tree bases = NULL_TREE;
+
+ if (!processing_template_decl)
+ {
+ /* Parameter packs can only be used in templates */
+ error ("Parameter pack __bases only valid in template declaration");
+ return error_mark_node;
+ }
+
+ bases = cxx_make_type (BASES);
+ BASES_TYPE (bases) = type;
+ BASES_DIRECT (bases) = direct;
+ SET_TYPE_STRUCTURAL_EQUALITY (bases);
+
+ return bases;
+}
+
/* Perform C++-specific checks for __builtin_offsetof before calling
fold_offsetof. */
}
if (REFERENCE_REF_P (expr))
expr = TREE_OPERAND (expr, 0);
- return fold_offsetof (expr, NULL_TREE);
+ if (TREE_CODE (expr) == COMPONENT_REF)
+ {
+ tree object = TREE_OPERAND (expr, 0);
+ if (!complete_type_or_else (TREE_TYPE (object), object))
+ return error_mark_node;
+ }
+ return fold_offsetof (expr);
}
/* Replace the AGGR_INIT_EXPR at *TP with an equivalent CALL_EXPR. This
}
}
+/* Returns true iff FUN is an instantiation of a constexpr function
+ template. */
+
+static inline bool
+is_instantiation_of_constexpr (tree fun)
+{
+ return (DECL_TEMPLOID_INSTANTIATION (fun)
+ && DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
+ (DECL_TI_TEMPLATE (fun))));
+}
+
/* Generate RTL for FN. */
bool
/* We don't want to process FN again, so pretend we've written
it out, even though we haven't. */
TREE_ASM_WRITTEN (fn) = 1;
- DECL_SAVED_TREE (fn) = NULL_TREE;
+ /* If this is an instantiation of a constexpr function, keep
+ DECL_SAVED_TREE for explain_invalid_constexpr_fn. */
+ if (!is_instantiation_of_constexpr (fn))
+ DECL_SAVED_TREE (fn) = NULL_TREE;
return false;
}
&& !DECL_REALLY_EXTERN (fn))
|| (flag_keep_inline_dllexport
&& lookup_attribute ("dllexport", DECL_ATTRIBUTES (fn))))
- mark_needed (fn);
+ {
+ mark_needed (fn);
+ DECL_EXTERNAL (fn) = 0;
+ }
}
/* There's no reason to do any of the work here if we're only doing
OMP_CLAUSE_IF_EXPR (c) = t;
break;
+ case OMP_CLAUSE_FINAL:
+ t = OMP_CLAUSE_FINAL_EXPR (c);
+ t = maybe_convert_cond (t);
+ if (t == error_mark_node)
+ remove = true;
+ OMP_CLAUSE_FINAL_EXPR (c) = t;
+ break;
+
case OMP_CLAUSE_NUM_THREADS:
t = OMP_CLAUSE_NUM_THREADS_EXPR (c);
if (t == error_mark_node)
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_MERGEABLE:
break;
default:
case PLUS_EXPR:
case MULT_EXPR:
case MINUS_EXPR:
+ case MIN_EXPR:
+ case MAX_EXPR:
break;
default:
error ("%qE has invalid type for %<reduction(%s)%>",
case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
break;
case OMP_CLAUSE_DEFAULT_SHARED:
+ /* const vars may be specified in firstprivate clause. */
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+ && cxx_omp_const_qual_no_mutable (t))
+ break;
share_name = "shared";
break;
case OMP_CLAUSE_DEFAULT_PRIVATE:
}
void
-finish_omp_atomic (enum tree_code code, tree lhs, tree rhs)
+finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs,
+ tree rhs, tree v, tree lhs1, tree rhs1)
{
tree orig_lhs;
tree orig_rhs;
+ tree orig_v;
+ tree orig_lhs1;
+ tree orig_rhs1;
bool dependent_p;
tree stmt;
orig_lhs = lhs;
orig_rhs = rhs;
+ orig_v = v;
+ orig_lhs1 = lhs1;
+ orig_rhs1 = rhs1;
dependent_p = false;
stmt = NULL_TREE;
if (processing_template_decl)
{
dependent_p = (type_dependent_expression_p (lhs)
- || type_dependent_expression_p (rhs));
+ || (rhs && type_dependent_expression_p (rhs))
+ || (v && type_dependent_expression_p (v))
+ || (lhs1 && type_dependent_expression_p (lhs1))
+ || (rhs1 && type_dependent_expression_p (rhs1)));
if (!dependent_p)
{
lhs = build_non_dependent_expr (lhs);
- rhs = build_non_dependent_expr (rhs);
+ if (rhs)
+ rhs = build_non_dependent_expr (rhs);
+ if (v)
+ v = build_non_dependent_expr (v);
+ if (lhs1)
+ lhs1 = build_non_dependent_expr (lhs1);
+ if (rhs1)
+ rhs1 = build_non_dependent_expr (rhs1);
}
}
if (!dependent_p)
{
- stmt = c_finish_omp_atomic (input_location, code, lhs, rhs);
+ stmt = c_finish_omp_atomic (input_location, code, opcode, lhs, rhs,
+ v, lhs1, rhs1);
if (stmt == error_mark_node)
return;
}
if (processing_template_decl)
- stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node,
- build2 (code, void_type_node, orig_lhs, orig_rhs));
+ {
+ if (code == OMP_ATOMIC_READ)
+ {
+ stmt = build_min_nt (OMP_ATOMIC_READ, orig_lhs);
+ stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt);
+ }
+ else
+ {
+ if (opcode == NOP_EXPR)
+ stmt = build2 (MODIFY_EXPR, void_type_node, orig_lhs, orig_rhs);
+ else
+ stmt = build2 (opcode, void_type_node, orig_lhs, orig_rhs);
+ if (orig_rhs1)
+ stmt = build_min_nt (COMPOUND_EXPR, orig_rhs1, stmt);
+ if (code != OMP_ATOMIC)
+ {
+ stmt = build_min_nt (code, orig_lhs1, stmt);
+ stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt);
+ }
+ }
+ stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node, stmt);
+ }
add_stmt (stmt);
}
void
finish_omp_barrier (void)
{
- tree fn = built_in_decls[BUILT_IN_GOMP_BARRIER];
+ tree fn = builtin_decl_explicit (BUILT_IN_GOMP_BARRIER);
VEC(tree,gc) *vec = make_tree_vector ();
tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
release_tree_vector (vec);
void
finish_omp_flush (void)
{
- tree fn = built_in_decls[BUILT_IN_SYNC_SYNCHRONIZE];
+ tree fn = builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE);
VEC(tree,gc) *vec = make_tree_vector ();
tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
release_tree_vector (vec);
void
finish_omp_taskwait (void)
{
- tree fn = built_in_decls[BUILT_IN_GOMP_TASKWAIT];
+ tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKWAIT);
+ VEC(tree,gc) *vec = make_tree_vector ();
+ tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+ release_tree_vector (vec);
+ finish_expr_stmt (stmt);
+}
+
+void
+finish_omp_taskyield (void)
+{
+ tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKYIELD);
VEC(tree,gc) *vec = make_tree_vector ();
tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
release_tree_vector (vec);
finish_expr_stmt (stmt);
}
\f
+/* Begin a __transaction_atomic or __transaction_relaxed statement.
+ If PCOMPOUND is non-null, this is for a function-transaction-block, and we
+ should create an extra compound stmt. */
+
+tree
+begin_transaction_stmt (location_t loc, tree *pcompound, int flags)
+{
+ tree r;
+
+ if (pcompound)
+ *pcompound = begin_compound_stmt (0);
+
+ r = build_stmt (loc, TRANSACTION_EXPR, NULL_TREE);
+
+ /* Only add the statement to the function if support enabled. */
+ if (flag_tm)
+ add_stmt (r);
+ else
+ error_at (loc, ((flags & TM_STMT_ATTR_RELAXED) != 0
+ ? G_("%<__transaction_relaxed%> without "
+ "transactional memory support enabled")
+ : G_("%<__transaction_atomic%> without "
+ "transactional memory support enabled")));
+
+ TRANSACTION_EXPR_BODY (r) = push_stmt_list ();
+ return r;
+}
+
+/* End a __transaction_atomic or __transaction_relaxed statement.
+ If COMPOUND_STMT is non-null, this is for a function-transaction-block,
+ and we should end the compound. */
+
+void
+finish_transaction_stmt (tree stmt, tree compound_stmt, int flags)
+{
+ TRANSACTION_EXPR_BODY (stmt) = pop_stmt_list (TRANSACTION_EXPR_BODY (stmt));
+ TRANSACTION_EXPR_OUTER (stmt) = (flags & TM_STMT_ATTR_OUTER) != 0;
+ TRANSACTION_EXPR_RELAXED (stmt) = (flags & TM_STMT_ATTR_RELAXED) != 0;
+ TRANSACTION_EXPR_IS_STMT (stmt) = 1;
+
+ if (compound_stmt)
+ finish_compound_stmt (compound_stmt);
+ finish_stmt ();
+}
+
+/* Build a __transaction_atomic or __transaction_relaxed expression. */
+
+tree
+build_transaction_expr (location_t loc, tree expr, int flags)
+{
+ tree ret;
+ ret = build1 (TRANSACTION_EXPR, TREE_TYPE (expr), expr);
+ if (flags & TM_STMT_ATTR_RELAXED)
+ TRANSACTION_EXPR_RELAXED (ret) = 1;
+ SET_EXPR_LOCATION (ret, loc);
+ return ret;
+}
+\f
void
init_cp_semantics (void)
{
return error_mark_node;
}
+ if (invalid_nonstatic_memfn_p (expr, complain))
+ 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
step. */
expr = TREE_OPERAND (expr, 1);
- if (TREE_CODE (expr) == BASELINK)
+ if (BASELINK_P (expr))
/* See through BASELINK nodes to the underlying function. */
expr = BASELINK_FUNCTIONS (expr);
}
}
-/* Returns true if TYPE is a complete type, an array of unknown bound,
- or (possibly cv-qualified) void, returns false otherwise. */
+/* If TYPE is an array of unknown bound, or (possibly cv-qualified)
+ void, or a complete type, returns it, otherwise NULL_TREE. */
-static bool
+static tree
check_trait_type (tree type)
{
- if (COMPLETE_TYPE_P (type))
- return true;
-
if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type)
&& COMPLETE_TYPE_P (TREE_TYPE (type)))
- return true;
+ return type;
if (VOID_TYPE_P (type))
- return true;
+ return type;
- return false;
+ return complete_type_or_else (strip_array_types (type), NULL_TREE);
}
/* Process a trait expression. */
return trait_expr;
}
- complete_type (type1);
- if (type2)
- complete_type (type2);
-
switch (kind)
{
case CPTK_HAS_NOTHROW_ASSIGN:
case CPTK_IS_STD_LAYOUT:
case CPTK_IS_TRIVIAL:
if (!check_trait_type (type1))
- {
- error ("incomplete type %qT not allowed", type1);
- return error_mark_node;
- }
+ return error_mark_node;
break;
case CPTK_IS_BASE_OF:
if (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
&& !same_type_ignoring_top_level_qualifiers_p (type1, type2)
- && !COMPLETE_TYPE_P (type2))
- {
- error ("incomplete type %qT not allowed", type2);
- return error_mark_node;
- }
+ && !complete_type_or_else (type2, NULL_TREE))
+ /* We already issued an error. */
+ return error_mark_node;
break;
case CPTK_IS_CLASS:
{
error ("the type %qT of constexpr variable %qD is not literal",
type, decl);
+ explain_non_literal_class (type);
return NULL;
}
}
{
ret = false;
if (complain)
- error ("invalid type for parameter %d of constexpr "
- "function %q+#D", DECL_PARM_INDEX (parm), fun);
+ {
+ error ("invalid type for parameter %d of constexpr "
+ "function %q+#D", DECL_PARM_INDEX (parm), fun);
+ explain_non_literal_class (TREE_TYPE (parm));
+ }
}
if (!DECL_CONSTRUCTOR_P (fun))
{
ret = false;
if (complain)
- error ("invalid return type %qT of constexpr function %q+D",
- rettype, fun);
+ {
+ error ("invalid return type %qT of constexpr function %q+D",
+ rettype, fun);
+ explain_non_literal_class (rettype);
+ }
}
- /* Check this again here for cxx_eval_call_expression. */
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);
+ {
+ error ("enclosing class of constexpr non-static member "
+ "function %q+#D is not a literal type", fun);
+ explain_non_literal_class (DECL_CONTEXT (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
- of the function. */
-
-tree
-validate_constexpr_fundecl (tree 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;
-
- if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun)))
- {
- DECL_DECLARED_CONSTEXPR_P (fun) = false;
- return NULL;
- }
-
- 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
return NULL_TREE;
return error_mark_node;
+ case CLEANUP_POINT_EXPR:
+ return constexpr_fn_retval (TREE_OPERAND (body, 0));
+
case USING_STMT:
return NULL_TREE;
}
}
-/* 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. */
+/* Subroutine of register_constexpr_fundef. BODY is the DECL_SAVED_TREE of
+ FUN; do the necessary transformations to turn it into a single expression
+ that we can store in the hash table. */
-tree
-register_constexpr_fundef (tree fun, tree body)
+static tree
+massage_constexpr_body (tree fun, tree body)
{
- constexpr_fundef entry;
- constexpr_fundef **slot;
-
if (DECL_CONSTRUCTOR_P (fun))
body = build_constexpr_constructor_member_initializers
(DECL_CONTEXT (fun), body);
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;
- }
+ }
+ return body;
+}
+
+/* FUN is a constexpr constructor with massaged body BODY. Return true
+ if some bases/fields are uninitialized, and complain if COMPLAIN. */
+
+static bool
+cx_check_missing_mem_inits (tree fun, tree body, bool complain)
+{
+ bool bad;
+ tree field;
+ unsigned i, nelts;
+
+ if (TREE_CODE (body) != CONSTRUCTOR)
+ return false;
+
+ bad = false;
+ nelts = CONSTRUCTOR_NELTS (body);
+ field = TYPE_FIELDS (DECL_CONTEXT (fun));
+ for (i = 0; i <= nelts; ++i)
+ {
+ tree index;
+ if (i == nelts)
+ index = NULL_TREE;
+ else
+ {
+ index = CONSTRUCTOR_ELT (body, i)->index;
+ /* Skip base and vtable inits. */
+ if (TREE_CODE (index) != FIELD_DECL)
+ continue;
+ }
+ for (; field != index; field = DECL_CHAIN (field))
+ {
+ tree ftype;
+ if (TREE_CODE (field) != FIELD_DECL
+ || (DECL_C_BIT_FIELD (field) && !DECL_NAME (field)))
+ continue;
+ if (!complain)
+ return true;
+ ftype = strip_array_types (TREE_TYPE (field));
+ if (type_has_constexpr_default_constructor (ftype))
+ {
+ /* It's OK to skip a member with a trivial constexpr ctor.
+ A constexpr ctor that isn't trivial should have been
+ added in by now. */
+ gcc_checking_assert (!TYPE_HAS_COMPLEX_DFLT (ftype));
+ continue;
+ }
+ error ("uninitialized member %qD in %<constexpr%> constructor",
+ field);
+ bad = true;
+ }
+ if (field == NULL_TREE)
+ break;
+ field = DECL_CHAIN (field);
+ }
+
+ return bad;
+}
+
+/* We are processing the definition of the constexpr function FUN.
+ Check that its BODY fulfills the propriate requirements and
+ enter it in the constexpr function definition table.
+ For constructor BODY is actually the TREE_LIST of the
+ member-initializer list. */
+
+tree
+register_constexpr_fundef (tree fun, tree body)
+{
+ constexpr_fundef entry;
+ constexpr_fundef **slot;
+
+ if (!is_valid_constexpr_fn (fun, !DECL_GENERATED_P (fun)))
+ return NULL;
+
+ body = massage_constexpr_body (fun, body);
+ if (body == NULL_TREE || body == error_mark_node)
+ {
+ if (!DECL_CONSTRUCTOR_P (fun))
+ error ("body of constexpr function %qD not a return-statement", fun);
+ return NULL;
}
if (!potential_rvalue_constant_expression (body))
{
- DECL_DECLARED_CONSTEXPR_P (fun) = false;
- if (!DECL_TEMPLATE_INFO (fun))
+ if (!DECL_GENERATED_P (fun))
require_potential_rvalue_constant_expression (body);
return NULL;
}
+ if (DECL_CONSTRUCTOR_P (fun)
+ && cx_check_missing_mem_inits (fun, body, !DECL_GENERATED_P (fun)))
+ return NULL;
+
/* Create the constexpr function table if necessary. */
if (constexpr_fundef_table == NULL)
constexpr_fundef_table = htab_create_ggc (101,
return fun;
}
+/* FUN is a non-constexpr function called in a context that requires a
+ constant expression. If it comes from a constexpr template, explain why
+ the instantiation isn't constexpr. */
+
+void
+explain_invalid_constexpr_fn (tree fun)
+{
+ static struct pointer_set_t *diagnosed;
+ tree body;
+ location_t save_loc;
+ /* Only diagnose defaulted functions or instantiations. */
+ if (!DECL_DEFAULTED_FN (fun)
+ && !is_instantiation_of_constexpr (fun))
+ return;
+ if (diagnosed == NULL)
+ diagnosed = pointer_set_create ();
+ if (pointer_set_insert (diagnosed, fun) != 0)
+ /* Already explained. */
+ return;
+
+ save_loc = input_location;
+ input_location = DECL_SOURCE_LOCATION (fun);
+ inform (0, "%q+D is not usable as a constexpr function because:", fun);
+ /* First check the declaration. */
+ if (is_valid_constexpr_fn (fun, true))
+ {
+ /* Then if it's OK, the body. */
+ if (DECL_DEFAULTED_FN (fun))
+ explain_implicit_non_constexpr (fun);
+ else
+ {
+ body = massage_constexpr_body (fun, DECL_SAVED_TREE (fun));
+ require_potential_rvalue_constant_expression (body);
+ if (DECL_CONSTRUCTOR_P (fun))
+ cx_check_missing_mem_inits (fun, body, true);
+ }
+ }
+ input_location = save_loc;
+}
+
/* Objects of this type represent calls to constexpr functions
along with the bindings of parameters to their arguments, for
the purpose of compile time evaluation. */
}
if (TREE_CODE (fun) != FUNCTION_DECL)
{
- if (!allow_non_constant)
+ if (!allow_non_constant && !*non_constant_p)
error_at (loc, "expression %qE does not designate a constexpr "
"function", fun);
*non_constant_p = true;
{
if (!allow_non_constant)
{
- error_at (loc, "%qD is not a constexpr function", fun);
- if (DECL_TEMPLATE_INFO (fun)
- && DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
- (DECL_TI_TEMPLATE (fun))))
- is_valid_constexpr_fn (fun, true);
+ error_at (loc, "call to non-constexpr function %qD", fun);
+ explain_invalid_constexpr_fn (fun);
}
*non_constant_p = true;
return t;
if (new_call.fundef == NULL || new_call.fundef->body == NULL)
{
if (!allow_non_constant)
- error_at (loc, "%qD used before its definition", fun);
+ {
+ if (DECL_INITIAL (fun))
+ {
+ /* The definition of fun was somehow unsuitable. */
+ error_at (loc, "%qD called in a constant expression", fun);
+ explain_invalid_constexpr_fn (fun);
+ }
+ else
+ error_at (loc, "%qD used before its definition", fun);
+ }
*non_constant_p = true;
return t;
}
elem_type = TREE_TYPE (TREE_TYPE (ary));
if (TREE_CODE (ary) == CONSTRUCTOR)
len = CONSTRUCTOR_NELTS (ary);
- else
+ else if (TREE_CODE (ary) == STRING_CST)
{
elem_nchars = (TYPE_PRECISION (elem_type)
/ TYPE_PRECISION (char_type_node));
len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
}
+ else
+ {
+ /* We can't do anything with other tree codes, so use
+ VERIFY_CONSTANT to complain and fail. */
+ VERIFY_CONSTANT (ary);
+ gcc_unreachable ();
+ }
if (compare_tree_int (index, len) >= 0)
{
if (tree_int_cst_lt (index, array_type_nelts_top (TREE_TYPE (ary))))
error ("%qE is not a constant expression", orig_whole);
*non_constant_p = true;
}
+ if (DECL_MUTABLE_P (part))
+ {
+ if (!allow_non_constant)
+ error ("mutable %qD is not usable in a constant expression", part);
+ *non_constant_p = true;
+ }
if (*non_constant_p)
return t;
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value)
if (field == part)
return value;
}
- if (TREE_CODE (TREE_TYPE (whole)) == UNION_TYPE)
+ if (TREE_CODE (TREE_TYPE (whole)) == UNION_TYPE
+ && CONSTRUCTOR_NELTS (whole) > 0)
{
- /* FIXME Mike Miller wants this to be OK. */
+ /* DR 1188 says we don't have to deal with this. */
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;
+
+ /* If there's no explicit init for this field, it's value-initialized. */
+ value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
+ return cxx_eval_constant_expression (call, value,
+ allow_non_constant, addr,
+ non_constant_p);
}
/* Subroutine of cxx_eval_constant_expression.
allow_non_constant, addr,
non_constant_p);
VERIFY_CONSTANT (lhs);
- if (lhs == bailout_value)
+ if (tree_int_cst_equal (lhs, bailout_value))
return lhs;
- gcc_assert (lhs == continue_value);
+ gcc_assert (tree_int_cst_equal (lhs, continue_value));
r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
allow_non_constant, addr, non_constant_p);
VERIFY_CONSTANT (r);
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);
+ bool pre_init = false;
int i;
/* For the default constructor, build up a call to the default
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);
+ if (TREE_CODE (elttype) == ARRAY_TYPE)
+ /* We only do this at the lowest level. */;
+ else if (value_init)
+ {
+ init = build_value_init (elttype, tf_warning_or_error);
+ init = cxx_eval_constant_expression
+ (call, init, allow_non_constant, addr, non_constant_p);
+ pre_init = true;
+ }
else if (!init)
{
VEC(tree,gc) *argvec = make_tree_vector ();
release_tree_vector (argvec);
init = cxx_eval_constant_expression (call, init, allow_non_constant,
addr, non_constant_p);
+ pre_init = true;
}
if (*non_constant_p && !allow_non_constant)
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)
+ else if (pre_init)
{
- /* Initializing an element using the call to the default
- constructor we just built above. */
- eltinit = unshare_expr (init);
+ /* Initializing an element using value or default initialization
+ we just pre-built above. */
+ if (i == 0)
+ eltinit = init;
+ else
+ eltinit = unshare_expr (init);
}
else
{
if (!*non_constant_p)
{
- init = build_constructor (TREE_TYPE (atype), n);
+ init = build_constructor (atype, n);
TREE_CONSTANT (init) = true;
return init;
}
{
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. */
+ /* DR 1188 says we don't have to deal with this. */
if (!allow_non_constant)
error ("accessing value of %qE through a %qT glvalue in a "
"constant expression", build_fold_indirect_ref (sub),
case PARM_DECL:
if (call && DECL_CONTEXT (t) == call->fundef->decl)
- r = lookup_parameter_binding (call, t);
+ {
+ if (DECL_ARTIFICIAL (t) && DECL_CONSTRUCTOR_P (DECL_CONTEXT (t)))
+ {
+ if (!allow_non_constant)
+ sorry ("use of the value of the object being constructed "
+ "in a constant expression");
+ *non_constant_p = true;
+ }
+ else
+ r = lookup_parameter_binding (call, t);
+ }
else if (addr)
/* Defer in case this is only used for its type. */;
else
break;
case TARGET_EXPR:
+ if (!literal_type_p (TREE_TYPE (t)))
+ {
+ if (!allow_non_constant)
+ {
+ error ("temporary of non-literal type %qT in a "
+ "constant expression", TREE_TYPE (t));
+ explain_non_literal_class (TREE_TYPE (t));
+ }
+ *non_constant_p = true;
+ break;
+ }
+ /* else fall through. */
case INIT_EXPR:
/* Pass false for 'addr' because these codes indicate
initialization of a temporary. */
return t;
case LAMBDA_EXPR:
- case DYNAMIC_CAST_EXPR:
- case PSEUDO_DTOR_EXPR:
case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
case PREDECREMENT_EXPR:
verify_constant (r, allow_non_constant, &non_constant_p);
+ if (TREE_CODE (t) != CONSTRUCTOR
+ && cp_has_mutable_p (TREE_TYPE (t)))
+ {
+ /* We allow a mutable type if the original expression was a
+ CONSTRUCTOR so that we can do aggregate initialization of
+ constexpr variables. */
+ if (!allow_non_constant)
+ error ("%qT cannot be the type of a complete constant expression "
+ "because it has mutable sub-objects", TREE_TYPE (t));
+ non_constant_p = true;
+ }
+
if (non_constant_p && !allow_non_constant)
return error_mark_node;
else if (non_constant_p && TREE_CONSTANT (t))
if (type_dependent_expression_p (t)
|| type_unknown_p (t)
+ || BRACE_ENCLOSED_INITIALIZER_P (t)
|| !potential_constant_expression (t)
|| value_dependent_expression_p (t))
{
}
#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.
case TEMPLATE_PARM_INDEX:
case TRAIT_EXPR:
case IDENTIFIER_NODE:
+ case USERDEF_LITERAL:
/* We can see a FIELD_DECL in a pointer-to-member expression. */
case FIELD_DECL:
- 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;
- }
+ case USING_DECL:
return true;
case AGGR_INIT_EXPR:
if (builtin_valid_in_constant_expr_p (fun))
return true;
if (!DECL_DECLARED_CONSTEXPR_P (fun)
- && !morally_constexpr_builtin_function_p (fun))
+ /* Allow any built-in function; if the expansion
+ isn't constant, we'll deal with that then. */
+ && !is_builtin_fn (fun))
{
if (flags & tf_error)
- error ("%qD is not %<constexpr%>", fun);
+ {
+ error_at (EXPR_LOC_OR_HERE (t),
+ "call to non-constexpr function %qD", fun);
+ explain_invalid_constexpr_fn (fun);
+ }
return false;
}
/* A call to a non-static member function takes the address
{
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;
+ if (DECL_CONSTRUCTOR_P (DECL_CONTEXT (x)))
+ {
+ if (flags & tf_error)
+ sorry ("calling a member function of the "
+ "object being constructed in a constant "
+ "expression");
+ return false;
+ }
+ /* Otherwise OK. */;
}
+ else if (!potential_constant_expression_1 (x, rval, flags))
+ return false;
i = 1;
}
}
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;
- }
+ 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 false;
}
return true;
}
STRIP_NOPS (x);
if (is_this_parameter (x))
{
- if (DECL_CONSTRUCTOR_P (DECL_CONTEXT (x)) && want_rval)
+ if (want_rval && DECL_CONTEXT (x)
+ && DECL_CONSTRUCTOR_P (DECL_CONTEXT (x)))
{
if (flags & tf_error)
sorry ("use of the value of the object being constructed "
case STMT_EXPR:
case EXPR_STMT:
case BIND_EXPR:
+ case TRANSACTION_EXPR:
if (flags & tf_error)
error ("expression %qE is not a constant-expression", t);
return false;
case CONST_CAST_EXPR:
case STATIC_CAST_EXPR:
case REINTERPRET_CAST_EXPR:
+ case IMPLICIT_CONV_EXPR:
return (potential_constant_expression_1
(TREE_OPERAND (t, 0),
TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE, flags));
return potential_constant_expression_1 (TREE_OPERAND (t, 1),
want_rval, flags);
- case INIT_EXPR:
case TARGET_EXPR:
+ if (!literal_type_p (TREE_TYPE (t)))
+ {
+ if (flags & tf_error)
+ {
+ error ("temporary of non-literal type %qT in a "
+ "constant expression", TREE_TYPE (t));
+ explain_non_literal_class (TREE_TYPE (t));
+ }
+ return false;
+ }
+ case INIT_EXPR:
return potential_constant_expression_1 (TREE_OPERAND (t, 1),
rval, flags);
return false;
return true;
+ case FMA_EXPR:
+ for (i = 0; i < 3; ++i)
+ if (!potential_constant_expression_1 (TREE_OPERAND (t, i),
+ true, 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
return false;
default:
- sorry ("unexpected ast of kind %s", tree_code_name[TREE_CODE (t)]);
+ sorry ("unexpected AST of kind %s", tree_code_name[TREE_CODE (t)]);
gcc_unreachable();
return false;
}
/* N2927: "[The closure] class type is not an aggregate."
But we briefly treat it as an aggregate to make this simpler. */
- type = TREE_TYPE (lambda_expr);
+ type = LAMBDA_EXPR_CLOSURE (lambda_expr);
CLASSTYPE_NON_AGGREGATE (type) = 0;
expr = finish_compound_literal (type, expr, tf_warning_or_error);
CLASSTYPE_NON_AGGREGATE (type) = 1;
type = begin_class_definition (type, /*attributes=*/NULL_TREE);
/* Cross-reference the expression and the type. */
- TREE_TYPE (lambda) = type;
+ LAMBDA_EXPR_CLOSURE (lambda) = type;
CLASSTYPE_LAMBDA_EXPR (type) = lambda;
return type;
lambda_return_type (tree expr)
{
tree type;
- if (BRACE_ENCLOSED_INITIALIZER_P (expr))
+ if (type_unknown_p (expr)
+ || BRACE_ENCLOSED_INITIALIZER_P (expr))
{
- warning (0, "cannot deduce lambda return type from a braced-init-list");
+ cxx_incomplete_type_error (expr, TREE_TYPE (expr));
return void_type_node;
}
if (type_dependent_expression_p (expr))
- {
- type = cxx_make_type (DECLTYPE_TYPE);
- DECLTYPE_TYPE_EXPR (type) = expr;
- DECLTYPE_FOR_LAMBDA_RETURN (type) = true;
- SET_TYPE_STRUCTURAL_EQUALITY (type);
- }
+ type = dependent_lambda_return_type_node;
else
- type = type_decays_to (unlowered_expr_type (expr));
+ type = cv_unqualified (type_decays_to (unlowered_expr_type (expr)));
return type;
}
{
tree type;
if (TREE_CODE (lambda) == LAMBDA_EXPR)
- type = TREE_TYPE (lambda);
+ type = LAMBDA_EXPR_CLOSURE (lambda);
else
type = lambda;
gcc_assert (LAMBDA_TYPE_P (type));
LAMBDA_EXPR_RETURN_TYPE (lambda) = return_type;
- /* If we got a DECLTYPE_TYPE, don't stick it in the function yet,
- it would interfere with instantiating the closure type. */
- if (dependent_type_p (return_type))
- return;
if (return_type == error_mark_node)
return;
+ if (TREE_TYPE (TREE_TYPE (fco)) == return_type)
+ return;
/* TREE_TYPE (FUNCTION_DECL) == METHOD_TYPE
TREE_TYPE (METHOD_TYPE) == return-type */
/* We already have a DECL_RESULT from start_preparsed_function.
Now we need to redo the work it and allocate_struct_function
did to reflect the new type. */
+ gcc_assert (current_function_decl == fco);
result = build_decl (input_location, RESULT_DECL, NULL_TREE,
TYPE_MAIN_VARIANT (return_type));
DECL_ARTIFICIAL (result) = 1;
static inline void
insert_capture_proxy (tree var)
{
- cxx_scope *b;
+ cp_binding_level *b;
int skip;
tree stmt_list;
b = current_binding_level;
for (skip = 0; ; ++skip)
{
- cxx_scope *n = b->level_chain;
+ cp_binding_level *n = b->level_chain;
if (n->kind == sk_function_parms)
break;
b = n;
LAMBDA_EXPR_PENDING_PROXIES (lam) = NULL;
}
+/* Given REF, a COMPONENT_REF designating a field in the lambda closure,
+ return the type we want the proxy to have: the type of the field itself,
+ with added const-qualification if the lambda isn't mutable and the
+ capture is by value. */
+
+tree
+lambda_proxy_type (tree ref)
+{
+ tree type;
+ if (REFERENCE_REF_P (ref))
+ ref = TREE_OPERAND (ref, 0);
+ type = TREE_TYPE (ref);
+ if (!dependent_type_p (type))
+ return type;
+ type = cxx_make_type (DECLTYPE_TYPE);
+ DECLTYPE_TYPE_EXPR (type) = ref;
+ DECLTYPE_FOR_LAMBDA_PROXY (type) = true;
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
+ return type;
+}
+
/* MEMBER is a capture field in a lambda closure class. Now that we're
inside the operator(), build a placeholder var for future lookups and
debugging. */
tree
build_capture_proxy (tree member)
{
- tree var, object, fn, closure, name, lam;
+ tree var, object, fn, closure, name, lam, type;
closure = DECL_CONTEXT (member);
fn = lambda_function (closure);
/* Remove the __ inserted by add_capture. */
name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
- var = build_decl (input_location, VAR_DECL, name, TREE_TYPE (object));
+ type = lambda_proxy_type (object);
+ var = build_decl (input_location, VAR_DECL, name, type);
SET_DECL_VALUE_EXPR (var, object);
DECL_HAS_VALUE_EXPR_P (var) = 1;
DECL_ARTIFICIAL (var) = 1;
if (!real_lvalue_p (initializer))
error ("cannot capture %qE by reference", initializer);
}
+ else
+ /* Capture by copy requires a complete type. */
+ type = complete_type (type);
/* Add __ to the beginning of the field name so that user code
won't find the field with name lookup. We can't just leave the name
/* If TREE_TYPE isn't set, we're still in the introducer, so check
for duplicates. */
- if (!TREE_TYPE (lambda))
+ if (!LAMBDA_EXPR_CLOSURE (lambda))
{
if (IDENTIFIER_MARKED (name))
{
LAMBDA_EXPR_THIS_CAPTURE (lambda) = member;
/* Add it to the appropriate closure class if we've started it. */
- if (current_class_type && current_class_type == TREE_TYPE (lambda))
+ if (current_class_type
+ && current_class_type == LAMBDA_EXPR_CLOSURE (lambda))
finish_member_declaration (member);
LAMBDA_EXPR_CAPTURE_LIST (lambda)
= tree_cons (member, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
- if (TREE_TYPE (lambda))
+ if (LAMBDA_EXPR_CLOSURE (lambda))
return build_capture_proxy (member);
/* For explicit captures we haven't started the function yet, so we wait
and build the proxy from cp_parser_lambda_body. */
{
tree lambda = TREE_VALUE (node);
- current_class_type = TREE_TYPE (lambda);
+ current_class_type = LAMBDA_EXPR_CLOSURE (lambda);
var = add_capture (lambda,
id,
initializer,
if (!this_capture
&& LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE)
{
- tree containing_function = TYPE_CONTEXT (TREE_TYPE (lambda));
+ tree containing_function = TYPE_CONTEXT (LAMBDA_EXPR_CLOSURE (lambda));
tree lambda_stack = tree_cons (NULL_TREE, lambda, NULL_TREE);
tree init = NULL_TREE;
else
{
/* To make sure that current_class_ref is for the lambda. */
- gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)) == TREE_TYPE (lambda));
+ gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref))
+ == LAMBDA_EXPR_CLOSURE (lambda));
result = this_capture;
if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE)
return;
+ if (processing_template_decl)
+ return;
+
stattype = build_function_type (TREE_TYPE (TREE_TYPE (callop)),
FUNCTION_ARG_CHAIN (callop));
if (nested)
push_function_context ();
+ else
+ /* Still increment function_depth so that we don't GC in the
+ middle of an expression. */
+ ++function_depth;
/* Generate the body of the thunk. */
if (DECL_ONE_ONLY (statfn))
{
/* Put the thunk in the same comdat group as the call op. */
- struct cgraph_node *callop_node, *thunk_node;
- DECL_COMDAT_GROUP (statfn) = cxx_comdat_group (callop);
- 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;
- thunk_node->same_comdat_group = callop_node;
+ cgraph_add_to_same_comdat_group (cgraph_get_create_node (statfn),
+ cgraph_get_create_node (callop));
}
body = begin_function_body ();
compound_stmt = begin_compound_stmt (0);
argvec = make_tree_vector ();
VEC_quick_push (tree, argvec, arg);
for (arg = DECL_ARGUMENTS (statfn); arg; arg = DECL_CHAIN (arg))
- VEC_safe_push (tree, gc, argvec, arg);
+ {
+ mark_exp_read (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 (nested)
pop_function_context ();
+ else
+ --function_depth;
}
/* Returns true iff VAL is a lambda-related declaration which should