and during the instantiation of template functions.
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
Written by Mark Mitchell (mmitchell@usa.net) based on code found
formerly in parse.y and pt.c.
#include "c-family/c-common.h"
#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 ())
tree
finish_break_stmt (void)
{
+ /* In switch statements break is sometimes stylistically used after
+ a return statement. This can lead to spurious warnings about
+ control reaching the end of a non-void function when it is
+ inlined. Note that we are calling block_may_fallthru with
+ language specific tree nodes; this works because
+ block_may_fallthru returns true when given something it does not
+ understand. */
+ if (!block_may_fallthru (cur_stmt_list))
+ return void_zero_node;
return add_stmt (build_stmt (input_location, BREAK_STMT));
}
else
{
/* Set the cv qualifiers. */
- int quals = (current_class_ref
- ? cp_type_quals (TREE_TYPE (current_class_ref))
- : TYPE_UNQUALIFIED);
+ int quals = cp_type_quals (TREE_TYPE (object));
if (DECL_MUTABLE_P (decl))
quals &= ~TYPE_QUAL_CONST;
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 (cxx_dialect >= cxx0x && SCALAR_TYPE_P (type)
- && !BRACE_ENCLOSED_INITIALIZER_P (compound_literal))
+ if (SCALAR_TYPE_P (type)
+ && !BRACE_ENCLOSED_INITIALIZER_P (compound_literal)
+ && (complain & tf_warning_or_error))
check_narrowing (type, compound_literal);
if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_DOMAIN (type) == NULL_TREE)
/* Begin a class definition, as indicated by T. */
tree
-begin_class_definition (tree t, tree attributes)
+begin_class_definition (tree t)
{
if (error_operand_p (t) || error_operand_p (TYPE_MAIN_DECL (t)))
return error_mark_node;
pushclass (t);
TYPE_BEING_DEFINED (t) = 1;
- cplus_decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
- fixup_attribute_variants (t);
-
if (flag_pack_struct)
{
tree v;
}
}
/* Enter the DECL into the scope of the class. */
- else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl))
- || pushdecl_class_level (decl))
+ else if (pushdecl_class_level (decl))
{
+ if (TREE_CODE (decl) == USING_DECL)
+ {
+ /* For now, ignore class-scope USING_DECLS, so that
+ debugging backends do not see them. */
+ DECL_IGNORED_P (decl) = 1;
+ }
+
/* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields
go at the beginning. The reason is that lookup_field_1
searches the list in order, and we want a field name to
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
baselink_for_fns (tree fns)
{
- tree fn;
+ tree scope;
tree cl;
if (BASELINK_P (fns)
|| error_operand_p (fns))
return fns;
-
- fn = fns;
- if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
- fn = TREE_OPERAND (fn, 0);
- fn = get_first_fn (fn);
- if (!DECL_FUNCTION_MEMBER_P (fn))
+
+ scope = ovl_scope (fns);
+ if (!CLASS_TYPE_P (scope))
return fns;
- cl = currently_open_derived_class (DECL_CONTEXT (fn));
+ cl = currently_open_derived_class (scope);
if (!cl)
- cl = DECL_CONTEXT (fn);
+ cl = scope;
cl = TYPE_BINFO (cl);
return build_baselink (cl, cl, fns, /*optype=*/NULL_TREE);
}
-/* Returns true iff DECL is an automatic variable from a function outside
+/* Returns true iff DECL is a variable from a function outside
the current one. */
static bool
-outer_automatic_var_p (tree decl)
+outer_var_p (tree decl)
{
return ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
&& DECL_FUNCTION_SCOPE_P (decl)
- && !TREE_STATIC (decl)
&& DECL_CONTEXT (decl) != current_function_decl);
}
+/* As above, but also checks that DECL is automatic. */
+
+static bool
+outer_automatic_var_p (tree decl)
+{
+ return (outer_var_p (decl)
+ && !TREE_STATIC (decl));
+}
+
/* ID_EXPRESSION is a representation of parsed, but unprocessed,
id-expression. (See cp_parser_id_expression for details.) SCOPE,
if non-NULL, is the type or namespace used to explicitly qualify
const char **error_msg,
location_t location)
{
+ decl = strip_using_decl (decl);
+
/* Initialize the output parameters. */
*idk = CP_ID_KIND_NONE;
*error_msg = NULL;
/* Disallow uses of local variables from containing functions, except
within lambda-expressions. */
- if (outer_automatic_var_p (decl)
+ if (!outer_var_p (decl)
/* It's not a use (3.2) if we're in an unevaluated context. */
- && !cp_unevaluated_operand)
+ || cp_unevaluated_operand)
+ /* OK. */;
+ else if (TREE_STATIC (decl))
+ {
+ if (processing_template_decl)
+ /* For a use of an outer static var, return the identifier so
+ that we'll look it up again in the instantiation. */
+ return id_expression;
+ }
+ else
{
tree context = DECL_CONTEXT (decl);
tree containing_function = current_function_decl;
FIXME update for final resolution of core issue 696. */
if (decl_constant_var_p (decl))
- return integral_constant_value (decl);
+ {
+ if (processing_template_decl)
+ /* In a template, the constant value may not be in a usable
+ form, so look it up again at instantiation time. */
+ return id_expression;
+ else
+ return integral_constant_value (decl);
+ }
/* If we are in a lambda function, we can move out until we hit
1. the context,
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 (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
if (TREE_CODE (type) != ENUMERAL_TYPE)
{
- error ("%qE is not an enumeration type", type);
+ error ("%qT is not an enumeration type", type);
return error_mark_node;
}
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 (!complete_type_or_else (TREE_TYPE (object), object))
return error_mark_node;
}
- return fold_offsetof (expr, NULL_TREE);
+ return fold_offsetof (expr);
}
/* Replace the AGGR_INIT_EXPR at *TP with an equivalent CALL_EXPR. This
t = maybe_convert_cond (t);
if (t == error_mark_node)
remove = true;
+ else if (!processing_template_decl)
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
OMP_CLAUSE_IF_EXPR (c) = t;
break;
t = maybe_convert_cond (t);
if (t == error_mark_node)
remove = true;
+ else if (!processing_template_decl)
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
OMP_CLAUSE_FINAL_EXPR (c) = t;
break;
error ("num_threads expression must be integral");
remove = true;
}
+ else
+ {
+ t = mark_rvalue_use (t);
+ if (!processing_template_decl)
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ OMP_CLAUSE_NUM_THREADS_EXPR (c) = t;
+ }
break;
case OMP_CLAUSE_SCHEDULE:
error ("schedule chunk size expression must be integral");
remove = true;
}
+ else
+ {
+ t = mark_rvalue_use (t);
+ if (!processing_template_decl)
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t;
+ }
break;
case OMP_CLAUSE_NOWAIT:
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);
void
finish_omp_taskyield (void)
{
- tree fn = built_in_decls[BUILT_IN_GOMP_TASKYIELD];
+ 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. If NOEX is non-NULL, we wrap the body in
+ a MUST_NOT_THROW_EXPR with NOEX as condition. */
+
+void
+finish_transaction_stmt (tree stmt, tree compound_stmt, int flags, tree noex)
+{
+ 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;
+
+ /* noexcept specifications are not allowed for function transactions. */
+ gcc_assert (!(noex && compound_stmt));
+ if (noex)
+ {
+ tree body = build_must_not_throw_expr (TRANSACTION_EXPR_BODY (stmt),
+ noex);
+ SET_EXPR_LOCATION (body, EXPR_LOCATION (TRANSACTION_EXPR_BODY (stmt)));
+ TREE_SIDE_EFFECTS (body) = 1;
+ TRANSACTION_EXPR_BODY (stmt) = body;
+ }
+
+ if (compound_stmt)
+ finish_compound_stmt (compound_stmt);
+ finish_stmt ();
+}
+
+/* Build a __transaction_atomic or __transaction_relaxed expression. If
+ NOEX is non-NULL, we wrap the body in a MUST_NOT_THROW_EXPR with NOEX as
+ condition. */
+
+tree
+build_transaction_expr (location_t loc, tree expr, int flags, tree noex)
+{
+ tree ret;
+ if (noex)
+ {
+ expr = build_must_not_throw_expr (expr, noex);
+ SET_EXPR_LOCATION (expr, loc);
+ TREE_SIDE_EFFECTS (expr) = 1;
+ }
+ 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)
{
if (TREE_CODE (condition) == INTEGER_CST
&& integer_zerop (condition))
/* Report the error. */
- error ("static assertion failed: %E", message);
+ error ("static assertion failed: %s", TREE_STRING_POINTER (message));
else if (condition && condition != error_mark_node)
{
error ("non-constant condition for static assertion");
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);
gcc_unreachable ();
case INTEGER_CST:
+ case PTRMEM_CST:
/* We can get here when the id-expression refers to an
- enumerator. */
+ enumerator or non-type template parameter. */
type = TREE_TYPE (expr);
break;
else if (copy_fn_p (fn) <= 0)
continue;
+ maybe_instantiate_noexcept (fn);
if (!TYPE_NOTHROW_P (TREE_TYPE (fn)))
return false;
}
return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
|| (CLASS_TYPE_P (type1)
&& (t = locate_ctor (type1))
- && TYPE_NOTHROW_P (TREE_TYPE (t))));
+ && (maybe_instantiate_noexcept (t),
+ TYPE_NOTHROW_P (TREE_TYPE (t)))));
case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
type1 = strip_array_types (type1);
case CPTK_IS_ENUM:
return (type_code1 == ENUMERAL_TYPE);
+ case CPTK_IS_FINAL:
+ return (CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1));
+
case CPTK_IS_LITERAL_TYPE:
return (literal_type_p (type1));
}
}
-/* 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. */
|| kind == CPTK_IS_CONVERTIBLE_TO
|| kind == CPTK_IS_EMPTY
|| kind == CPTK_IS_ENUM
+ || kind == CPTK_IS_FINAL
|| kind == CPTK_IS_LITERAL_TYPE
|| kind == CPTK_IS_POD
|| kind == CPTK_IS_POLYMORPHIC
return trait_expr;
}
- complete_type (type1);
- if (type2)
- complete_type (type2);
-
switch (kind)
{
case CPTK_HAS_NOTHROW_ASSIGN:
case CPTK_HAS_VIRTUAL_DESTRUCTOR:
case CPTK_IS_ABSTRACT:
case CPTK_IS_EMPTY:
+ case CPTK_IS_FINAL:
case CPTK_IS_LITERAL_TYPE:
case CPTK_IS_POD:
case CPTK_IS_POLYMORPHIC:
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:
}
}
}
+ else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun)))
+ {
+ ret = false;
+ if (complain)
+ error ("%q#T has virtual base classes", DECL_CONTEXT (fun));
+ }
return ret;
}
member = TREE_OPERAND (t, 0);
init = unshare_expr (TREE_OPERAND (t, 1));
}
- else
+ else if (TREE_CODE (t) == CALL_EXPR)
{
- 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);
}
+ else if (TREE_CODE (t) == DECL_EXPR)
+ /* Declaring a temporary, don't add it to the CONSTRUCTOR. */
+ return true;
+ else
+ gcc_unreachable ();
if (TREE_CODE (member) == INDIRECT_REF)
member = TREE_OPERAND (member, 0);
if (TREE_CODE (member) == NOP_EXPR)
the const_cast. */
member = op;
}
+ else if (op == current_class_ptr
+ && (same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (TREE_TYPE (member)),
+ current_class_type)))
+ /* Delegating constructor. */
+ member = op;
else
{
- /* We don't put out anything for an empty base. */
+ /* This is an initializer for an empty base; keep it for now so
+ we can check it in cxx_eval_bare_aggregate. */
gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (member))));
- /* 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)
return ok;
}
+/* VEC is a vector of constructor elements built up for the base and member
+ initializers of a constructor for TYPE. They need to be in increasing
+ offset order, which they might not be yet if TYPE has a primary base
+ which is not first in the base-clause or a vptr and at least one base
+ all of which are non-primary. */
+
+static VEC(constructor_elt,gc) *
+sort_constexpr_mem_initializers (tree type, VEC(constructor_elt,gc) *vec)
+{
+ tree pri = CLASSTYPE_PRIMARY_BINFO (type);
+ tree field_type;
+ constructor_elt elt;
+ int i;
+
+ if (pri)
+ field_type = BINFO_TYPE (pri);
+ else if (TYPE_CONTAINS_VPTR_P (type))
+ field_type = vtbl_ptr_type_node;
+ else
+ return vec;
+
+ /* Find the element for the primary base or vptr and move it to the
+ beginning of the vec. */
+ for (i = 0; ; ++i)
+ if (TREE_TYPE (VEC_index (constructor_elt, vec, i)->index) == field_type)
+ break;
+
+ if (i > 0)
+ {
+ elt = *VEC_index (constructor_elt, vec, i);
+ for (; i > 0; --i)
+ VEC_replace (constructor_elt, vec, i,
+ VEC_index (constructor_elt, vec, i-1));
+ VEC_replace (constructor_elt, vec, 0, &elt);
+ }
+ return vec;
+}
+
/* Build compile-time evalable representations of member-initializer list
for a constexpr constructor. */
break;
}
}
+ else if (EXPR_P (body))
+ ok = build_data_member_initialization (body, &vec);
else
gcc_assert (errorcount > 0);
if (ok)
- return build_constructor (type, vec);
+ {
+ if (VEC_length (constructor_elt, vec) > 0)
+ {
+ /* In a delegating constructor, return the target. */
+ constructor_elt *ce = VEC_index (constructor_elt, vec, 0);
+ if (ce->index == current_class_ptr)
+ {
+ body = ce->value;
+ VEC_free (constructor_elt, gc, vec);
+ return body;
+ }
+ }
+ vec = sort_constexpr_mem_initializers (type, vec);
+ return build_constructor (type, vec);
+ }
else
return error_mark_node;
}
(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) == BIND_EXPR)
+ body = BIND_EXPR_BODY (body);
body = constexpr_fn_retval (body);
}
return body;
bool bad;
tree field;
unsigned i, nelts;
+ tree ctype;
if (TREE_CODE (body) != CONSTRUCTOR)
return false;
- bad = false;
nelts = CONSTRUCTOR_NELTS (body);
- field = TYPE_FIELDS (DECL_CONTEXT (fun));
+ ctype = DECL_CONTEXT (fun);
+ field = TYPE_FIELDS (ctype);
+
+ if (TREE_CODE (ctype) == UNION_TYPE)
+ {
+ if (nelts == 0 && next_initializable_field (field))
+ {
+ if (complain)
+ error ("%<constexpr%> constructor for union %qT must "
+ "initialize exactly one non-static data member", ctype);
+ return true;
+ }
+ return false;
+ }
+
+ bad = false;
for (i = 0; i <= nelts; ++i)
{
tree index;
{
index = CONSTRUCTOR_ELT (body, i)->index;
/* Skip base and vtable inits. */
- if (TREE_CODE (index) != FIELD_DECL)
+ if (TREE_CODE (index) != FIELD_DECL
+ || DECL_ARTIFICIAL (index))
continue;
}
for (; field != index; field = DECL_CHAIN (field))
{
tree ftype;
if (TREE_CODE (field) != FIELD_DECL
- || (DECL_C_BIT_FIELD (field) && !DECL_NAME (field)))
+ || (DECL_C_BIT_FIELD (field) && !DECL_NAME (field))
+ || DECL_ARTIFICIAL (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));
+ gcc_checking_assert (!TYPE_HAS_COMPLEX_DFLT (ftype)
+ || errorcount != 0);
continue;
}
+ if (!complain)
+ return true;
error ("uninitialized member %qD in %<constexpr%> constructor",
field);
bad = true;
else
{
result = entry->result;
- if (!result || (result == error_mark_node && !allow_non_constant))
+ if (!result || result == error_mark_node)
result = (cxx_eval_constant_expression
(&new_call, new_call.fundef->body,
allow_non_constant, addr,
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)
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);
constructor_elt *inner = base_field_constructor_elt (n, ce->index);
inner->value = elt;
}
+ else if (TREE_CODE (ce->index) == NOP_EXPR)
+ {
+ /* This is an initializer for an empty base; now that we've
+ checked that it's constant, we can ignore it. */
+ gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (ce->index))));
+ }
else
CONSTRUCTOR_APPEND_ELT (n, ce->index, elt);
}
if (TREE_CODE (elttype) == ARRAY_TYPE)
{
/* A multidimensional array; recurse. */
- if (value_init)
+ if (value_init || init == NULL_TREE)
eltinit = NULL_TREE;
else
eltinit = cp_build_array_ref (input_location, init, idx,
sub = op0;
STRIP_NOPS (sub);
subtype = TREE_TYPE (sub);
- gcc_assert (POINTER_TYPE_P (subtype));
+ if (!POINTER_TYPE_P (subtype))
+ return NULL_TREE;
if (TREE_CODE (sub) == ADDR_EXPR)
{
}
}
}
- /* *(foo *)fooarrptreturn> (*fooarrptr)[0] */
+ /* *(foo *)fooarrptr => (*fooarrptr)[0] */
else if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
&& (same_type_ignoring_top_level_qualifiers_p
(type, TREE_TYPE (TREE_TYPE (subtype)))))
{
tree type_domain;
tree min_val = size_zero_node;
- sub = cxx_fold_indirect_ref (loc, TREE_TYPE (subtype), sub, NULL);
- if (!sub)
+ tree newsub = cxx_fold_indirect_ref (loc, TREE_TYPE (subtype), sub, NULL);
+ if (newsub)
+ sub = newsub;
+ else
sub = build1_loc (loc, INDIRECT_REF, TREE_TYPE (subtype), sub);
type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
if (type_domain && TYPE_MIN_VALUE (type_domain))
{
tree sub = op0;
STRIP_NOPS (sub);
- if (TREE_CODE (sub) == ADDR_EXPR
- || TREE_CODE (sub) == POINTER_PLUS_EXPR)
+ if (TREE_CODE (sub) == POINTER_PLUS_EXPR)
+ {
+ sub = TREE_OPERAND (sub, 0);
+ STRIP_NOPS (sub);
+ }
+ if (TREE_CODE (sub) == ADDR_EXPR)
{
+ /* We couldn't fold to a constant value. Make sure it's not
+ something we should have been able to fold. */
gcc_assert (!same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t)));
/* DR 1188 says we don't have to deal with this. */
}
if (r == NULL_TREE)
- return t;
+ {
+ if (!addr)
+ VERIFY_CONSTANT (t);
+ return t;
+ }
return r;
}
/* Check that the LHS is constant and then discard it. */
cxx_eval_constant_expression (call, op0, allow_non_constant,
false, non_constant_p);
+ op1 = TREE_OPERAND (t, 1);
r = cxx_eval_constant_expression (call, op1, allow_non_constant,
addr, non_constant_p);
}
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);
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;
+ }
+
+ /* Technically we should check this for all subexpressions, but that
+ runs into problems with our internal representation of pointer
+ subtraction and the 5.19 rules are still in flux. */
+ if (CONVERT_EXPR_CODE_P (TREE_CODE (r))
+ && ARITHMETIC_TYPE_P (TREE_TYPE (r))
+ && TREE_CODE (TREE_OPERAND (r, 0)) == ADDR_EXPR)
+ {
+ if (!allow_non_constant)
+ error ("conversion from pointer type %qT "
+ "to arithmetic type %qT in a constant-expression",
+ TREE_TYPE (TREE_OPERAND (r, 0)), TREE_TYPE (r));
+ non_constant_p = true;
+ }
+
if (non_constant_p && !allow_non_constant)
return error_mark_node;
else if (non_constant_p && TREE_CONSTANT (t))
case TEMPLATE_PARM_INDEX:
case TRAIT_EXPR:
case IDENTIFIER_NODE:
+ case USERDEF_LITERAL:
/* We can see a FIELD_DECL in a pointer-to-member expression. */
case FIELD_DECL:
case PARM_DECL:
case 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. */
+ /* -- a reinterpret_cast. FIXME not implemented, and this rule
+ may change to something more specific to type-punning (DR 1312). */
{
tree from = TREE_OPERAND (t, 0);
- 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 STMT_EXPR:
case EXPR_STMT:
case BIND_EXPR:
+ case TRANSACTION_EXPR:
+ case IF_STMT:
+ case DO_STMT:
+ case FOR_STMT:
+ case WHILE_STMT:
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));
case UNGT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
+ case LTGT_EXPR:
case RANGE_EXPR:
case COMPLEX_EXPR:
want_rval = true;
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;
xref_basetypes (type, /*bases=*/NULL_TREE);
/* Start the class. */
- type = begin_class_definition (type, /*attributes=*/NULL_TREE);
+ type = begin_class_definition (type);
+ if (type == error_mark_node)
+ return error_mark_node;
/* Cross-reference the expression and the type. */
- TREE_TYPE (lambda) = type;
+ LAMBDA_EXPR_CLOSURE (lambda) = type;
CLASSTYPE_LAMBDA_EXPR (type) = lambda;
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));
&& !COMPLETE_OR_OPEN_TYPE_P (type))
return NULL_TREE;
lambda = lookup_member (type, ansi_opname (CALL_EXPR),
- /*protect=*/0, /*want_type=*/false);
+ /*protect=*/0, /*want_type=*/false,
+ tf_warning_or_error);
if (lambda)
lambda = BASELINK_FUNCTIONS (lambda);
return lambda;
lambda_capture_field_type (tree expr)
{
tree type;
- if (type_dependent_expression_p (expr))
+ if (type_dependent_expression_p (expr)
+ && !(TREE_TYPE (expr) && TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE))
{
type = cxx_make_type (DECLTYPE_TYPE);
DECLTYPE_TYPE_EXPR (type) = expr;
/* VAR is a capture proxy created by build_capture_proxy; add it to the
current function, which is the operator() for the appropriate lambda. */
-static inline void
+void
insert_capture_proxy (tree var)
{
cp_binding_level *b;
- int skip;
tree stmt_list;
/* Put the capture proxy in the extra body block so that it won't clash
with a later local variable. */
b = current_binding_level;
- for (skip = 0; ; ++skip)
+ for (;;)
{
cp_binding_level *n = b->level_chain;
if (n->kind == sk_function_parms)
/* And put a DECL_EXPR in the STATEMENT_LIST for the same block. */
var = build_stmt (DECL_SOURCE_LOCATION (var), DECL_EXPR, var);
- stmt_list = VEC_index (tree, stmt_list_stack,
- VEC_length (tree, stmt_list_stack) - 1 - skip);
+ stmt_list = VEC_index (tree, stmt_list_stack, 1);
gcc_assert (stmt_list);
append_to_statement_list_force (var, &stmt_list);
}
if (REFERENCE_REF_P (ref))
ref = TREE_OPERAND (ref, 0);
type = TREE_TYPE (ref);
- if (!dependent_type_p (type))
+ if (!dependent_type_p (type)
+ || (type && TREE_CODE (type) == POINTER_TYPE))
return type;
type = cxx_make_type (DECLTYPE_TYPE);
DECLTYPE_TYPE_EXPR (type) = ref;
/* 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;
body = begin_function_body ();
compound_stmt = begin_compound_stmt (0);
+ /* decl_needed_p needs to see that it's used. */
+ TREE_USED (statfn) = 1;
finish_return_stmt (decay_conversion (statfn));
finish_compound_stmt (compound_stmt);