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"
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;
&& 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,
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;
}
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:
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));
|| 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
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:
}
}
}
+ 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)
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);
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 UNGT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
+ case LTGT_EXPR:
case RANGE_EXPR:
case COMPLEX_EXPR:
want_rval = true;
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. */
LAMBDA_EXPR_CLOSURE (lambda) = 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;
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);