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;
return error_mark_node;
compound_literal = reshape_init (type, compound_literal, complain);
if (SCALAR_TYPE_P (type)
- && !BRACE_ENCLOSED_INITIALIZER_P (compound_literal))
+ && !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;
{
if (TREE_CODE (decl) == USING_DECL)
{
- /* We need to add the target functions to the
- CLASSTYPE_METHOD_VEC if an enclosing scope is a template
- class, so that this function be found by lookup_fnfields_1
- when the using declaration is not instantiated yet. */
-
- tree target_decl = strip_using_decl (decl);
- if (dependent_type_p (current_class_type)
- && is_overloaded_fn (target_decl))
- {
- tree t = target_decl;
- for (; t; t = OVL_NEXT (t))
- add_method (current_class_type, OVL_CURRENT (t), decl);
- }
-
/* For now, ignore class-scope USING_DECLS, so that
debugging backends do not see them. */
DECL_IGNORED_P (decl) = 1;
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 (type) != ENUMERAL_TYPE)
{
- error ("%qE is not an enumeration type", type);
+ error ("%qT is not an enumeration type", type);
return error_mark_node;
}
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:
/* 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. */
+ 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)
+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. */
+/* 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)
+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;
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");
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,
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);
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 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 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;
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);