merge in cxx0x-lambdas-branch@152308

From-SVN: r152318
This commit is contained in:
Jason Merrill 2009-09-29 23:01:30 -04:00
parent 300ea2831b
commit d5f4edddeb
66 changed files with 3004 additions and 142 deletions

View File

@ -328,6 +328,7 @@ Chris Fairles cfairles@gcc.gnu.org
Li Feng nemokingdom@gmail.com Li Feng nemokingdom@gmail.com
Thomas Fitzsimmons fitzsim@redhat.com Thomas Fitzsimmons fitzsim@redhat.com
Brian Ford ford@vss.fsi.com Brian Ford ford@vss.fsi.com
John Freeman jfreeman08@gmail.com
Nathan Froyd froydnj@codesourcery.com Nathan Froyd froydnj@codesourcery.com
Chao-ying Fu fu@mips.com Chao-ying Fu fu@mips.com
Gary Funck gary@intrepid.com Gary Funck gary@intrepid.com

View File

@ -1,3 +1,94 @@
2009-09-29 John Freeman <jfreeman08@gmail.com>
Jason Merrill <jason@redhat.com>
Add support for lambda-expressions as per N2927.
* cp-tree.def (VEC_INIT_EXPR, LAMBDA_EXPR): New.
* cp-tree.h (LAMBDA_TYPE_P, LAMBDA_FUNCTION_P): New.
(LAMBDA_EXPR_DEFAULT_CAPTURE_MODE): New.
(LAMBDA_EXPR_DEFAULT_CAPTURE_LIST): New.
(LAMBDA_EXPR_THIS_CAPTURE, LAMBDA_EXPR_CAPTURES_THIS_P): New.
(LAMBDA_EXPR_MUTABLE_P, LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P): New.
(LAMBDA_EXPR_RETURN_TYPE, LAMBDA_EXPR_LOCATION): New.
(LAMBDA_EXPR_EXTRA_SCOPE, LAMBDA_EXPR_DISCRIMINATOR): New.
(struct tree_lambda_expr): New.
(union lang_tree_node): Add lambda_expression.
(struct lang_type_class): Add lazy_move_ctor flag, lambda_expr field.
(CLASSTYPE_LAZY_MOVE_CTOR, CLASSTYPE_LAMBDA_EXPR): New.
(LAMBDA_TYPE_EXTRA_SCOPE, VEC_INIT_EXPR_SLOT): New.
(VEC_INIT_EXPR_INIT, DECLTYPE_FOR_LAMBDA_CAPTURE): New.
(DECLTYPE_FOR_LAMBDA_RETURN): New.
(enum special_function_kind): Add sfk_move_constructor.
(LAMBDANAME_PREFIX, LAMBDANAME_FORMAT, LAMBDANAME_P): New.
* parser.c (cp_parser_lambda_expression, cp_parser_lambda_introducer)
(cp_parser_lambda_declarator_opt, cp_parser_lambda_body): New.
(start_lambda_scope, record_lambda_scope, finish_lambda_scope): New.
(no_linkage_lambda_type_p): New.
(cp_parser_primary_expression): Recognize lambda expression.
(cp_parser_init_declarator): Note lambda scope.
(cp_parser_function_definition_after_declarator): Likewise.
(cp_parser_late_parsing_default_args): Likewise.
(cp_parser_skip_to_closing_parenthesis): Skip to end of lambda capture
lists, too.
(cp_parser_parameter_declaration): Don't defer lambda default args.
* semantics.c (finish_non_static_data_member, finish_id_expression):
Handle default capture for lambda expressions.
(finish_this_expr): Handle 'this' keyword inside of lambda expressions.
(outer_automatic_var_p): New.
(finish_decltype_type): Handle decltypes within lambda expressions.
(classtype_has_nothrow_assign_or_copy_p): Synthesized move constructor.
(build_lambda_expr, build_lambda_object, begin_lambda_type)
(lambda_return_type, lambda_capture_field_type, apply_lambda_return_type)
(capture_decltype, add_capture, add_default_capture)
(lambda_expr_this_capture): New.
* mangle.c (write_unnamed_type_name): New. Incomplete.
(write_closure_type_name): New.
(write_unqualified_name): Recognize unnamed, closure types.
(write_type): Do not write decltypes from lambda expressions.
(decl_mangling_context): New.
(write_name): Use it. Handle PARM_DECL scope.
(write_prefix): Likewise. Handle VAR_DECL/FIELD_DECL scope.
(write_compact_number): Factor out from...
(write_expression, write_template_param): ...here.
(discriminator_for_local_entity): Recognize lambdas.
(write_local_name): Handle PARM_DECL scope.
* typeck.c (structural_comptypes): Compare decltypes from lambda
expressions.
(check_return_expr): Deduce lambda return type from multiple return
statements.
* class.c (add_implicitly_declared_members): Add lazy move constructor
for lambda types.
(check_bases_and_members): Delete default constructor and assignment
operator for lambda types.
(maybe_note_name_used_in_class): Do not confuse lambda expression with
defining a class.
* decl.c (reshape_init_r): Array copy.
(grokfndecl): Synthesized move constructor.
(cp_tree_node_structure): Lambda expression.
* method.c (use_thunk): Synthesized move constructor.
(do_build_copy_constructor): Likewise.
(locate_copy): Likewise.
(implicitly_declare_fn): Likewise.
* cp-objcp-common.c (cp_tree_size): Handle LAMBDA_EXPR.
* error.c (dump_aggr_type): Recognize lambda type.
(dump_function_decl): Recognize lambda function.
(function_category): Likewise.
(dump_function_name): Hide lambda name.
* tree.c (build_array_copy, move): New.
(special_function_p): Synthesized move constructor.
(no_linkage_check): Handle lambdas.
* search.c (lookup_fnfields_1): Synthesized move constructor.
* cp-gimplify.c (cp_gimplify_init_expr, cp_gimplify_expr):
Handle VEC_INIT_EXPR.
* typeck2.c (digest_init_r): Array copy.
* pt.c (get_template_info): Don't touch typedefs.
(instantiate_decl): Don't resubstitute artificial decls.
(tsubst_decl, tsubst, tsubst_copy_and_build): Handle lambdas.
(lookup_template_class): Don't fall back on name lookup.
* name-lookup.c (make_lambda_name): New.
(pushdecl_class_level): Handle default capture for lambda expressions.
(qualify_lookup): Handle decltypes within lambda expressions.
(pushtag): Handle ts_within_enclosing_non_class in function scope.
2009-09-28 Janis Johnson <janis187@us.ibm.com> 2009-09-28 Janis Johnson <janis187@us.ibm.com>
* mangle.c (write_builtin_type): Support decimal float types. * mangle.c (write_builtin_type): Support decimal float types.

View File

@ -2677,6 +2677,10 @@ add_implicitly_declared_members (tree t,
CLASSTYPE_LAZY_COPY_CTOR (t) = 1; CLASSTYPE_LAZY_COPY_CTOR (t) = 1;
} }
/* Currently only lambdas get a lazy move ctor. */
if (LAMBDA_TYPE_P (t))
CLASSTYPE_LAZY_MOVE_CTOR (t) = 1;
/* If there is no assignment operator, one will be created if and /* If there is no assignment operator, one will be created if and
when it is needed. For now, just record whether or not the type when it is needed. For now, just record whether or not the type
of the parameter to the assignment operator will be a const or of the parameter to the assignment operator will be a const or
@ -4449,6 +4453,20 @@ check_bases_and_members (tree t)
cant_have_const_ctor, cant_have_const_ctor,
no_const_asn_ref); no_const_asn_ref);
if (LAMBDA_TYPE_P (t))
{
/* "The closure type associated with a lambda-expression has a deleted
default constructor and a deleted copy assignment operator." */
TYPE_NEEDS_CONSTRUCTING (t) = 1;
TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 0;
CLASSTYPE_LAZY_DEFAULT_CTOR (t) = 0;
TYPE_HAS_ASSIGN_REF (t) = 0;
CLASSTYPE_LAZY_ASSIGNMENT_OP (t) = 0;
/* "This class type is not an aggregate." */
CLASSTYPE_NON_AGGREGATE (t) = 1;
}
/* Create the in-charge and not-in-charge variants of constructors /* Create the in-charge and not-in-charge variants of constructors
and destructors. */ and destructors. */
clone_constructors_and_destructors (t); clone_constructors_and_destructors (t);
@ -6601,7 +6619,8 @@ maybe_note_name_used_in_class (tree name, tree decl)
/* If we're not defining a class, there's nothing to do. */ /* If we're not defining a class, there's nothing to do. */
if (!(innermost_scope_kind() == sk_class if (!(innermost_scope_kind() == sk_class
&& TYPE_BEING_DEFINED (current_class_type))) && TYPE_BEING_DEFINED (current_class_type)
&& !LAMBDA_TYPE_P (current_class_type)))
return; return;
/* If there's already a binding for this NAME, then we don't have /* If there's already a binding for this NAME, then we don't have

View File

@ -452,10 +452,14 @@ cp_gimplify_init_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
Should we add a target parm to gimplify_expr instead? No, as in this Should we add a target parm to gimplify_expr instead? No, as in this
case we want to replace the INIT_EXPR. */ case we want to replace the INIT_EXPR. */
if (TREE_CODE (sub) == AGGR_INIT_EXPR) if (TREE_CODE (sub) == AGGR_INIT_EXPR
|| TREE_CODE (sub) == VEC_INIT_EXPR)
{ {
gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue); gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
AGGR_INIT_EXPR_SLOT (sub) = to; if (TREE_CODE (sub) == AGGR_INIT_EXPR)
AGGR_INIT_EXPR_SLOT (sub) = to;
else
VEC_INIT_EXPR_SLOT (sub) = to;
*expr_p = from; *expr_p = from;
/* The initialization is now a side-effect, so the container can /* The initialization is now a side-effect, so the container can
@ -523,6 +527,19 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
ret = GS_OK; ret = GS_OK;
break; break;
case VEC_INIT_EXPR:
{
location_t loc = input_location;
gcc_assert (EXPR_HAS_LOCATION (*expr_p));
input_location = EXPR_LOCATION (*expr_p);
*expr_p = build_vec_init (VEC_INIT_EXPR_SLOT (*expr_p), NULL_TREE,
VEC_INIT_EXPR_INIT (*expr_p), false, 1,
tf_warning_or_error);
ret = GS_OK;
input_location = loc;
}
break;
case THROW_EXPR: case THROW_EXPR:
/* FIXME communicate throw type to back end, probably by moving /* FIXME communicate throw type to back end, probably by moving
THROW_EXPR into ../tree.def. */ THROW_EXPR into ../tree.def. */

View File

@ -138,6 +138,8 @@ cp_tree_size (enum tree_code code)
case TRAIT_EXPR: case TRAIT_EXPR:
return sizeof (struct tree_trait_expr); return sizeof (struct tree_trait_expr);
case LAMBDA_EXPR: return sizeof (struct tree_lambda_expr);
default: default:
gcc_unreachable (); gcc_unreachable ();
} }

View File

@ -81,6 +81,11 @@ DEFTREECODE (TYPE_EXPR, "type_expr", tcc_expression, 1)
the remaining operands are the arguments to the initialization function. */ the remaining operands are the arguments to the initialization function. */
DEFTREECODE (AGGR_INIT_EXPR, "aggr_init_expr", tcc_vl_exp, 3) DEFTREECODE (AGGR_INIT_EXPR, "aggr_init_expr", tcc_vl_exp, 3)
/* Initialization of an array from another array, expressed at a high level
so that it works with TARGET_EXPR. Operand 0 is the target, operand 1
is the initializer. */
DEFTREECODE (VEC_INIT_EXPR, "vec_init_expr", tcc_expression, 2)
/* A throw expression. operand 0 is the expression, if there was one, /* A throw expression. operand 0 is the expression, if there was one,
else it is NULL_TREE. */ else it is NULL_TREE. */
DEFTREECODE (THROW_EXPR, "throw_expr", tcc_expression, 1) DEFTREECODE (THROW_EXPR, "throw_expr", tcc_expression, 1)
@ -416,11 +421,22 @@ DEFTREECODE (ARGUMENT_PACK_SELECT, "argument_pack_select", tcc_exceptional, 0)
/* Represents a trait expression during template expansion. */ /* Represents a trait expression during template expansion. */
DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0) DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0)
/* A lambda expression. This is a C++0x extension.
LAMBDA_EXPR_DEFAULT_CAPTURE_MODE is an enum for the default, which may be
none.
LAMBDA_EXPR_CAPTURE_LIST holds the capture-list, including `this'.
LAMBDA_EXPR_THIS_CAPTURE goes straight to the capture of `this', if it exists.
LAMBDA_EXPR_MUTABLE_P signals whether this lambda was declared mutable.
LAMBDA_EXPR_RETURN_TYPE holds the return type, if it was specified. */
DEFTREECODE (LAMBDA_EXPR, "lambda_expr", tcc_exceptional, 0)
/* The declared type of an expression. This is a C++0x extension. /* The declared type of an expression. This is a C++0x extension.
DECLTYPE_TYPE_EXPR is the expression whose type we are computing. DECLTYPE_TYPE_EXPR is the expression whose type we are computing.
DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P states whether the DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P states whether the
expression was parsed as an id-expression or a member access expression was parsed as an id-expression or a member access
expression. When false, it was parsed as a full expression. */ expression. When false, it was parsed as a full expression.
DECLTYPE_FOR_LAMBDA_CAPTURE is set if we want lambda capture semantics.
DECLTYPE_FOR_LAMBDA_RETURN is set if we want lambda return deduction. */
DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0) DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0)
/* /*

View File

@ -77,6 +77,8 @@ framework extensions, you must include this file before toplev.h, not after.
TYPE_REF_IS_RVALUE (in REFERENCE_TYPE) TYPE_REF_IS_RVALUE (in REFERENCE_TYPE)
ATTR_IS_DEPENDENT (in the TREE_LIST for an attribute) ATTR_IS_DEPENDENT (in the TREE_LIST for an attribute)
CONSTRUCTOR_IS_DIRECT_INIT (in CONSTRUCTOR) CONSTRUCTOR_IS_DIRECT_INIT (in CONSTRUCTOR)
LAMBDA_EXPR_CAPTURES_THIS_P (in LAMBDA_EXPR)
DECLTYPE_FOR_LAMBDA_CAPTURE (in DECLTYPE_TYPE)
1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG. TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE. TEMPLATE_PARMS_FOR_INLINE.
@ -87,11 +89,14 @@ framework extensions, you must include this file before toplev.h, not after.
TYPENAME_IS_CLASS_P (in TYPENAME_TYPE) TYPENAME_IS_CLASS_P (in TYPENAME_TYPE)
STMT_IS_FULL_EXPR_P (in _STMT) STMT_IS_FULL_EXPR_P (in _STMT)
TARGET_EXPR_LIST_INIT_P (in TARGET_EXPR) TARGET_EXPR_LIST_INIT_P (in TARGET_EXPR)
LAMBDA_EXPR_MUTABLE_P (in LAMBDA_EXPR)
DECLTYPE_FOR_LAMBDA_RETURN (in DECLTYPE_TYPE)
2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE) 2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE)
ICS_THIS_FLAG (in _CONV) ICS_THIS_FLAG (in _CONV)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST) STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST)
TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE) TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE)
LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_EXPR)
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
ICS_BAD_FLAG (in _CONV) ICS_BAD_FLAG (in _CONV)
FN_TRY_BLOCK_P (in TRY_BLOCK) FN_TRY_BLOCK_P (in TRY_BLOCK)
@ -517,6 +522,81 @@ struct GTY (()) tree_trait_expr {
enum cp_trait_kind kind; enum cp_trait_kind kind;
}; };
/* Based off of TYPE_ANONYMOUS_P. */
#define LAMBDA_TYPE_P(NODE) \
(CLASS_TYPE_P (NODE) && LAMBDANAME_P (TYPE_LINKAGE_IDENTIFIER (NODE)))
/* Test if FUNCTION_DECL is a lambda function. */
#define LAMBDA_FUNCTION_P(FNDECL) \
(DECL_OVERLOADED_OPERATOR_P (FNDECL) == CALL_EXPR \
&& LAMBDA_TYPE_P (CP_DECL_CONTEXT (FNDECL)))
enum cp_lambda_default_capture_mode_type {
CPLD_NONE,
CPLD_COPY,
CPLD_REFERENCE
};
/* The method of default capture, if any. */
#define LAMBDA_EXPR_DEFAULT_CAPTURE_MODE(NODE) \
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->default_capture_mode)
/* The capture-list, including `this'. Each capture is stored as a FIELD_DECL
* so that the name, type, and field are all together, whether or not it has
* been added to the lambda's class type.
TREE_LIST:
TREE_PURPOSE: The FIELD_DECL for this capture.
TREE_VALUE: The initializer. This is part of a GNU extension. */
#define LAMBDA_EXPR_CAPTURE_LIST(NODE) \
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->capture_list)
/* The node in the capture-list that holds the 'this' capture. */
#define LAMBDA_EXPR_THIS_CAPTURE(NODE) \
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->this_capture)
/* Predicate tracking whether `this' is in the effective capture set. */
#define LAMBDA_EXPR_CAPTURES_THIS_P(NODE) \
LAMBDA_EXPR_THIS_CAPTURE(NODE)
/* Predicate tracking whether the lambda was declared 'mutable'. */
#define LAMBDA_EXPR_MUTABLE_P(NODE) \
TREE_LANG_FLAG_1 (LAMBDA_EXPR_CHECK (NODE))
/* True iff we should try to deduce the lambda return type from any return
statement. */
#define LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P(NODE) \
TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE))
/* The return type in the expression.
* NULL_TREE indicates that none was specified. */
#define LAMBDA_EXPR_RETURN_TYPE(NODE) \
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->return_type)
/* The source location of the lambda. */
#define LAMBDA_EXPR_LOCATION(NODE) \
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->locus)
/* The mangling scope for the lambda: FUNCTION_DECL, PARM_DECL, VAR_DECL,
FIELD_DECL or NULL_TREE. If this is NULL_TREE, we have no linkage. */
#define LAMBDA_EXPR_EXTRA_SCOPE(NODE) \
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->extra_scope)
/* If EXTRA_SCOPE, this is the number of the lambda within that scope. */
#define LAMBDA_EXPR_DISCRIMINATOR(NODE) \
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->discriminator)
struct GTY (()) tree_lambda_expr
{
struct tree_common common;
location_t locus;
enum cp_lambda_default_capture_mode_type default_capture_mode;
tree capture_list;
tree this_capture;
tree return_type;
tree extra_scope;
int discriminator;
};
enum cp_tree_node_structure_enum { enum cp_tree_node_structure_enum {
TS_CP_GENERIC, TS_CP_GENERIC,
TS_CP_IDENTIFIER, TS_CP_IDENTIFIER,
@ -530,6 +610,7 @@ enum cp_tree_node_structure_enum {
TS_CP_STATIC_ASSERT, TS_CP_STATIC_ASSERT,
TS_CP_ARGUMENT_PACK_SELECT, TS_CP_ARGUMENT_PACK_SELECT,
TS_CP_TRAIT_EXPR, TS_CP_TRAIT_EXPR,
TS_CP_LAMBDA_EXPR,
LAST_TS_CP_ENUM LAST_TS_CP_ENUM
}; };
@ -550,6 +631,8 @@ union GTY((desc ("cp_tree_node_structure (&%h)"),
argument_pack_select; argument_pack_select;
struct tree_trait_expr GTY ((tag ("TS_CP_TRAIT_EXPR"))) struct tree_trait_expr GTY ((tag ("TS_CP_TRAIT_EXPR")))
trait_expression; trait_expression;
struct tree_lambda_expr GTY ((tag ("TS_CP_LAMBDA_EXPR")))
lambda_expression;
}; };
@ -1127,6 +1210,7 @@ struct GTY(()) lang_type_class {
unsigned has_complex_dflt : 1; unsigned has_complex_dflt : 1;
unsigned has_list_ctor : 1; unsigned has_list_ctor : 1;
unsigned non_std_layout : 1; unsigned non_std_layout : 1;
unsigned lazy_move_ctor : 1;
/* When adding a flag here, consider whether or not it ought to /* When adding a flag here, consider whether or not it ought to
apply to a template instance if it applies to the template. If apply to a template instance if it applies to the template. If
@ -1135,7 +1219,7 @@ struct GTY(()) lang_type_class {
/* There are some bits left to fill out a 32-bit word. Keep track /* There are some bits left to fill out a 32-bit word. Keep track
of this by updating the size of this bitfield whenever you add or of this by updating the size of this bitfield whenever you add or
remove a flag. */ remove a flag. */
unsigned dummy : 9; unsigned dummy : 8;
tree primary_base; tree primary_base;
VEC(tree_pair_s,gc) *vcall_indices; VEC(tree_pair_s,gc) *vcall_indices;
@ -1159,6 +1243,8 @@ struct GTY(()) lang_type_class {
to resort it if pointers get rearranged. */ to resort it if pointers get rearranged. */
struct sorted_fields_type * GTY ((reorder ("resort_sorted_fields"))) struct sorted_fields_type * GTY ((reorder ("resort_sorted_fields")))
sorted_fields; sorted_fields;
/* FIXME reuse another field? */
tree lambda_expr;
}; };
struct GTY(()) lang_type_ptrmem { struct GTY(()) lang_type_ptrmem {
@ -1221,6 +1307,11 @@ struct GTY(()) lang_type {
#define CLASSTYPE_LAZY_COPY_CTOR(NODE) \ #define CLASSTYPE_LAZY_COPY_CTOR(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->lazy_copy_ctor) (LANG_TYPE_CLASS_CHECK (NODE)->lazy_copy_ctor)
/* Nonzero means that NODE (a class type) has a move constructor --
but that it has not yet been declared. */
#define CLASSTYPE_LAZY_MOVE_CTOR(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->lazy_move_ctor)
/* Nonzero means that NODE (a class type) has an assignment operator /* Nonzero means that NODE (a class type) has an assignment operator
-- but that it has not yet been declared. */ -- but that it has not yet been declared. */
#define CLASSTYPE_LAZY_ASSIGNMENT_OP(NODE) \ #define CLASSTYPE_LAZY_ASSIGNMENT_OP(NODE) \
@ -1426,6 +1517,13 @@ struct GTY(()) lang_type {
#define CLASSTYPE_BEFRIENDING_CLASSES(NODE) \ #define CLASSTYPE_BEFRIENDING_CLASSES(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->befriending_classes) (LANG_TYPE_CLASS_CHECK (NODE)->befriending_classes)
/* The associated LAMBDA_EXPR that made this class. */
#define CLASSTYPE_LAMBDA_EXPR(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->lambda_expr)
/* The extra mangling scope for this closure type. */
#define LAMBDA_TYPE_EXTRA_SCOPE(NODE) \
(LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR (NODE)))
/* Say whether this node was declared as a "class" or a "struct". */ /* Say whether this node was declared as a "class" or a "struct". */
#define CLASSTYPE_DECLARED_CLASS(NODE) \ #define CLASSTYPE_DECLARED_CLASS(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->declared_class) (LANG_TYPE_CLASS_CHECK (NODE)->declared_class)
@ -2625,6 +2723,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
for ((arg) = first_aggr_init_expr_arg ((call), &(iter)); (arg); \ for ((arg) = first_aggr_init_expr_arg ((call), &(iter)); (arg); \
(arg) = next_aggr_init_expr_arg (&(iter))) (arg) = next_aggr_init_expr_arg (&(iter)))
/* VEC_INIT_EXPR accessors. */
#define VEC_INIT_EXPR_SLOT(NODE) TREE_OPERAND (NODE, 0)
#define VEC_INIT_EXPR_INIT(NODE) TREE_OPERAND (NODE, 1)
/* The TYPE_MAIN_DECL for a class template type is a TYPE_DECL, not a /* The TYPE_MAIN_DECL for a class template type is a TYPE_DECL, not a
TEMPLATE_DECL. This macro determines whether or not a given class TEMPLATE_DECL. This macro determines whether or not a given class
type is really a template type, as opposed to an instantiation or type is really a template type, as opposed to an instantiation or
@ -3058,6 +3160,14 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P(NODE) \ #define DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P(NODE) \
(DECLTYPE_TYPE_CHECK (NODE))->type.string_flag (DECLTYPE_TYPE_CHECK (NODE))->type.string_flag
/* These flags indicate that we want different semantics from normal
decltype: lambda capture just drops references, lambda return also does
type decay. */
#define DECLTYPE_FOR_LAMBDA_CAPTURE(NODE) \
TREE_LANG_FLAG_0 (DECLTYPE_TYPE_CHECK (NODE))
#define DECLTYPE_FOR_LAMBDA_RETURN(NODE) \
TREE_LANG_FLAG_1 (DECLTYPE_TYPE_CHECK (NODE))
/* Nonzero for VAR_DECL and FUNCTION_DECL node means that `extern' was /* Nonzero for VAR_DECL and FUNCTION_DECL node means that `extern' was
specified in its declaration. This can also be set for an specified in its declaration. This can also be set for an
erroneously declared PARM_DECL. */ erroneously declared PARM_DECL. */
@ -3570,6 +3680,7 @@ typedef enum special_function_kind {
special_function_p. */ special_function_p. */
sfk_constructor, /* A constructor. */ sfk_constructor, /* A constructor. */
sfk_copy_constructor, /* A copy constructor. */ sfk_copy_constructor, /* A copy constructor. */
sfk_move_constructor, /* A move constructor. */
sfk_assignment_operator, /* An assignment operator. */ sfk_assignment_operator, /* An assignment operator. */
sfk_destructor, /* A destructor. */ sfk_destructor, /* A destructor. */
sfk_complete_destructor, /* A destructor for complete objects. */ sfk_complete_destructor, /* A destructor for complete objects. */
@ -3778,6 +3889,13 @@ extern GTY(()) VEC(tree,gc) *local_classes;
#define VTABLE_DELTA_NAME "__delta" #define VTABLE_DELTA_NAME "__delta"
#define VTABLE_PFN_NAME "__pfn" #define VTABLE_PFN_NAME "__pfn"
#define LAMBDANAME_PREFIX "__lambda"
#define LAMBDANAME_FORMAT LAMBDANAME_PREFIX "%d"
#define LAMBDANAME_P(ID_NODE) \
(!strncmp (IDENTIFIER_POINTER (ID_NODE), \
LAMBDANAME_PREFIX, \
sizeof (LAMBDANAME_PREFIX) - 1))
#if !defined(NO_DOLLAR_IN_LABEL) || !defined(NO_DOT_IN_LABEL) #if !defined(NO_DOLLAR_IN_LABEL) || !defined(NO_DOT_IN_LABEL)
#define VTABLE_NAME_P(ID_NODE) (IDENTIFIER_POINTER (ID_NODE)[1] == 'v' \ #define VTABLE_NAME_P(ID_NODE) (IDENTIFIER_POINTER (ID_NODE)[1] == 'v' \
@ -4377,6 +4495,7 @@ enum cp_tree_node_structure_enum cp_tree_node_structure
extern void finish_scope (void); extern void finish_scope (void);
extern void push_switch (tree); extern void push_switch (tree);
extern void pop_switch (void); extern void pop_switch (void);
extern tree make_lambda_name (void);
extern int decls_match (tree, tree); extern int decls_match (tree, tree);
extern tree duplicate_decls (tree, tree, bool); extern tree duplicate_decls (tree, tree, bool);
extern tree declare_local_label (tree); extern tree declare_local_label (tree);
@ -4897,6 +5016,16 @@ extern void finish_static_assert (tree, tree, location_t,
extern tree describable_type (tree); extern tree describable_type (tree);
extern tree finish_decltype_type (tree, bool); extern tree finish_decltype_type (tree, bool);
extern tree finish_trait_expr (enum cp_trait_kind, tree, tree); extern tree finish_trait_expr (enum cp_trait_kind, tree, tree);
extern tree build_lambda_expr (void);
extern tree build_lambda_object (tree);
extern tree begin_lambda_type (tree);
extern tree lambda_capture_field_type (tree);
extern tree lambda_return_type (tree);
extern tree lambda_function (tree);
extern void apply_lambda_return_type (tree, tree);
extern tree add_capture (tree, tree, tree, bool);
extern tree add_default_capture (tree, tree, tree);
extern tree lambda_expr_this_capture (tree);
/* in tree.c */ /* in tree.c */
void cp_free_lang_data (tree t); void cp_free_lang_data (tree t);
@ -4934,6 +5063,7 @@ extern tree build_aggr_init_expr (tree, tree);
extern tree get_target_expr (tree); extern tree get_target_expr (tree);
extern tree build_cplus_array_type (tree, tree); extern tree build_cplus_array_type (tree, tree);
extern tree build_array_of_n_type (tree, int); extern tree build_array_of_n_type (tree, int);
extern tree build_array_copy (tree);
extern tree hash_tree_cons (tree, tree, tree); extern tree hash_tree_cons (tree, tree, tree);
extern tree hash_tree_chain (tree, tree); extern tree hash_tree_chain (tree, tree);
extern tree build_qualified_name (tree, tree, tree, bool); extern tree build_qualified_name (tree, tree, tree, bool);
@ -4965,6 +5095,7 @@ extern const struct attribute_spec cxx_attribute_table[];
extern tree make_ptrmem_cst (tree, tree); extern tree make_ptrmem_cst (tree, tree);
extern tree cp_build_type_attribute_variant (tree, tree); extern tree cp_build_type_attribute_variant (tree, tree);
extern tree cp_build_reference_type (tree, bool); extern tree cp_build_reference_type (tree, bool);
extern tree move (tree);
extern tree cp_build_qualified_type_real (tree, int, tsubst_flags_t); extern tree cp_build_qualified_type_real (tree, int, tsubst_flags_t);
#define cp_build_qualified_type(TYPE, QUALS) \ #define cp_build_qualified_type(TYPE, QUALS) \
cp_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error) cp_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error)
@ -5157,6 +5288,9 @@ extern tree cxx_omp_clause_dtor (tree, tree);
extern void cxx_omp_finish_clause (tree); extern void cxx_omp_finish_clause (tree);
extern bool cxx_omp_privatize_by_reference (const_tree); extern bool cxx_omp_privatize_by_reference (const_tree);
/* in parser.c */
extern bool no_linkage_lambda_type_p (tree);
/* -- end of C++ */ /* -- end of C++ */
#endif /* ! GCC_CP_TREE_H */ #endif /* ! GCC_CP_TREE_H */

View File

@ -4921,7 +4921,8 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p)
looking through the outermost braces; A a2 = { a1 }; is not a looking through the outermost braces; A a2 = { a1 }; is not a
valid aggregate initialization. */ valid aggregate initialization. */
&& !first_initializer_p && !first_initializer_p
&& can_convert_arg (type, TREE_TYPE (init), init, LOOKUP_NORMAL)) && (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (init))
|| can_convert_arg (type, TREE_TYPE (init), init, LOOKUP_NORMAL)))
{ {
d->cur++; d->cur++;
return init; return init;
@ -6622,6 +6623,7 @@ grokfndecl (tree ctype,
{ {
case sfk_constructor: case sfk_constructor:
case sfk_copy_constructor: case sfk_copy_constructor:
case sfk_move_constructor:
DECL_CONSTRUCTOR_P (decl) = 1; DECL_CONSTRUCTOR_P (decl) = 1;
break; break;
case sfk_destructor: case sfk_destructor:
@ -12687,6 +12689,7 @@ cp_tree_node_structure (union lang_tree_node * t)
case STATIC_ASSERT: return TS_CP_STATIC_ASSERT; case STATIC_ASSERT: return TS_CP_STATIC_ASSERT;
case ARGUMENT_PACK_SELECT: return TS_CP_ARGUMENT_PACK_SELECT; case ARGUMENT_PACK_SELECT: return TS_CP_ARGUMENT_PACK_SELECT;
case TRAIT_EXPR: return TS_CP_TRAIT_EXPR; case TRAIT_EXPR: return TS_CP_TRAIT_EXPR;
case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR;
default: return TS_CP_GENERIC; default: return TS_CP_GENERIC;
} }
} }

View File

@ -597,6 +597,15 @@ dump_aggr_type (tree t, int flags)
else else
pp_printf (pp_base (cxx_pp), M_("<anonymous %s>"), variety); pp_printf (pp_base (cxx_pp), M_("<anonymous %s>"), variety);
} }
else if (LAMBDANAME_P (name))
{
/* A lambda's "type" is essentially its signature. */
pp_string (cxx_pp, M_("<lambda"));
if (lambda_function (t))
dump_parameters (FUNCTION_FIRST_USER_PARMTYPE (lambda_function (t)),
flags);
pp_character(cxx_pp, '>');
}
else else
pp_cxx_tree_identifier (cxx_pp, name); pp_cxx_tree_identifier (cxx_pp, name);
if (tmplate) if (tmplate)
@ -1224,6 +1233,14 @@ dump_function_decl (tree t, int flags)
tree exceptions; tree exceptions;
VEC(tree,gc) *typenames = NULL; VEC(tree,gc) *typenames = NULL;
if (LAMBDA_FUNCTION_P (t))
{
/* A lambda's signature is essentially its "type", so defer. */
gcc_assert (LAMBDA_TYPE_P (DECL_CONTEXT (t)));
dump_type (DECL_CONTEXT (t), flags);
return;
}
flags &= ~TFF_UNQUALIFIED_NAME; flags &= ~TFF_UNQUALIFIED_NAME;
if (TREE_CODE (t) == TEMPLATE_DECL) if (TREE_CODE (t) == TEMPLATE_DECL)
t = DECL_TEMPLATE_RESULT (t); t = DECL_TEMPLATE_RESULT (t);
@ -1401,7 +1418,12 @@ dump_function_name (tree t, int flags)
/* Don't let the user see __comp_ctor et al. */ /* Don't let the user see __comp_ctor et al. */
if (DECL_CONSTRUCTOR_P (t) if (DECL_CONSTRUCTOR_P (t)
|| DECL_DESTRUCTOR_P (t)) || DECL_DESTRUCTOR_P (t))
name = constructor_name (DECL_CONTEXT (t)); {
if (LAMBDA_TYPE_P (DECL_CONTEXT (t)))
name = get_identifier ("<lambda>");
else
name = constructor_name (DECL_CONTEXT (t));
}
if (DECL_DESTRUCTOR_P (t)) if (DECL_DESTRUCTOR_P (t))
{ {
@ -2676,6 +2698,8 @@ function_category (tree fn)
return _("In constructor %qs"); return _("In constructor %qs");
else if (DECL_DESTRUCTOR_P (fn)) else if (DECL_DESTRUCTOR_P (fn))
return _("In destructor %qs"); return _("In destructor %qs");
else if (LAMBDA_FUNCTION_P (fn))
return _("In lambda function");
else else
return _("In member function %qs"); return _("In member function %qs");
} }

View File

@ -182,10 +182,13 @@ static void write_template_prefix (const tree);
static void write_unqualified_name (const tree); static void write_unqualified_name (const tree);
static void write_conversion_operator_name (const tree); static void write_conversion_operator_name (const tree);
static void write_source_name (tree); static void write_source_name (tree);
static void write_unnamed_type_name (const tree);
static void write_closure_type_name (const tree);
static int hwint_to_ascii (unsigned HOST_WIDE_INT, const unsigned int, char *, static int hwint_to_ascii (unsigned HOST_WIDE_INT, const unsigned int, char *,
const unsigned int); const unsigned int);
static void write_number (unsigned HOST_WIDE_INT, const int, static void write_number (unsigned HOST_WIDE_INT, const int,
const unsigned int); const unsigned int);
static void write_compact_number (int num);
static void write_integer_cst (const tree); static void write_integer_cst (const tree);
static void write_real_cst (const tree); static void write_real_cst (const tree);
static void write_identifier (const char *); static void write_identifier (const char *);
@ -211,7 +214,7 @@ static void write_substitution (const int);
static int discriminator_for_local_entity (tree); static int discriminator_for_local_entity (tree);
static int discriminator_for_string_literal (tree, tree); static int discriminator_for_string_literal (tree, tree);
static void write_discriminator (const int); static void write_discriminator (const int);
static void write_local_name (const tree, const tree, const tree); static void write_local_name (tree, const tree, const tree);
static void dump_substitution_candidates (void); static void dump_substitution_candidates (void);
static tree mangle_decl_string (const tree); static tree mangle_decl_string (const tree);
@ -744,6 +747,22 @@ needs_fake_anon (const_tree decl)
&& TREE_CODE (decl) == FUNCTION_DECL); && TREE_CODE (decl) == FUNCTION_DECL);
} }
/* Lambdas can have a bit more context for mangling, specifically VAR_DECL
or PARM_DECL context, which doesn't belong in DECL_CONTEXT. */
static tree
decl_mangling_context (tree decl)
{
if (TREE_CODE (decl) == TYPE_DECL
&& LAMBDA_TYPE_P (TREE_TYPE (decl)))
{
tree extra = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl));
if (extra)
return extra;
}
return CP_DECL_CONTEXT (decl);
}
/* <name> ::= <unscoped-name> /* <name> ::= <unscoped-name>
::= <unscoped-template-name> <template-args> ::= <unscoped-template-name> <template-args>
::= <nested-name> ::= <nested-name>
@ -767,10 +786,9 @@ write_name (tree decl, const int ignore_local_scope)
/* In case this is a typedef, fish out the corresponding /* In case this is a typedef, fish out the corresponding
TYPE_DECL for the main variant. */ TYPE_DECL for the main variant. */
decl = TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); decl = TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
context = CP_TYPE_CONTEXT (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
} }
else
context = CP_DECL_CONTEXT (decl); context = decl_mangling_context (decl);
gcc_assert (context != NULL_TREE); gcc_assert (context != NULL_TREE);
@ -822,7 +840,8 @@ write_name (tree decl, const int ignore_local_scope)
if (TYPE_P (context)) if (TYPE_P (context))
context = TYPE_NAME (context); context = TYPE_NAME (context);
/* Is this a function? */ /* Is this a function? */
if (TREE_CODE (context) == FUNCTION_DECL) if (TREE_CODE (context) == FUNCTION_DECL
|| TREE_CODE (context) == PARM_DECL)
{ {
/* Yes, we have local scope. Use the <local-name> /* Yes, we have local scope. Use the <local-name>
production for the innermost function scope. */ production for the innermost function scope. */
@ -831,7 +850,7 @@ write_name (tree decl, const int ignore_local_scope)
} }
/* Up one scope level. */ /* Up one scope level. */
local_entity = context; local_entity = context;
context = CP_DECL_CONTEXT (context); context = decl_mangling_context (context);
} }
/* No local scope found? Fall through to <nested-name>. */ /* No local scope found? Fall through to <nested-name>. */
@ -955,23 +974,24 @@ write_prefix (const tree node)
/* Non-NULL if NODE represents a template-id. */ /* Non-NULL if NODE represents a template-id. */
tree template_info = NULL; tree template_info = NULL;
MANGLE_TRACE_TREE ("prefix", node);
if (node == NULL if (node == NULL
|| node == global_namespace) || node == global_namespace)
return; return;
MANGLE_TRACE_TREE ("prefix", node);
if (find_substitution (node)) if (find_substitution (node))
return; return;
if (DECL_P (node)) if (DECL_P (node))
{ {
/* If this is a function decl, that means we've hit function /* If this is a function or parm decl, that means we've hit function
scope, so this prefix must be for a local name. In this scope, so this prefix must be for a local name. In this
case, we're under the <local-name> production, which encodes case, we're under the <local-name> production, which encodes
the enclosing function scope elsewhere. So don't continue the enclosing function scope elsewhere. So don't continue
here. */ here. */
if (TREE_CODE (node) == FUNCTION_DECL) if (TREE_CODE (node) == FUNCTION_DECL
|| TREE_CODE (node) == PARM_DECL)
return; return;
decl = node; decl = node;
@ -1016,8 +1036,15 @@ write_prefix (const tree node)
else else
/* Not templated. */ /* Not templated. */
{ {
write_prefix (CP_DECL_CONTEXT (decl)); write_prefix (decl_mangling_context (decl));
write_unqualified_name (decl); write_unqualified_name (decl);
if (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == FIELD_DECL)
{
/* <data-member-prefix> := <member source-name> M */
write_char ('M');
return;
}
} }
add_substitution (node); add_substitution (node);
@ -1107,6 +1134,7 @@ write_template_prefix (const tree node)
<unqualified-name> ::= <operator-name> <unqualified-name> ::= <operator-name>
::= <special-name> ::= <special-name>
::= <source-name> ::= <source-name>
::= <unnamed-type-name>
::= <local-source-name> ::= <local-source-name>
<local-source-name> ::= L <source-name> <discriminator> */ <local-source-name> ::= L <source-name> <discriminator> */
@ -1172,7 +1200,19 @@ write_unqualified_name (const tree decl)
so there's no code to output one here. */ so there's no code to output one here. */
} }
else else
write_source_name (DECL_NAME (decl)); {
tree type = TREE_TYPE (decl);
if (TREE_CODE (decl) == TYPE_DECL
&& TYPE_ANONYMOUS_P (type)
&& !ANON_UNION_TYPE_P (type))
write_unnamed_type_name (type);
else if (TREE_CODE (decl) == TYPE_DECL
&& LAMBDA_TYPE_P (type))
write_closure_type_name (type);
else
write_source_name (DECL_NAME (decl));
}
} }
/* Write the unqualified-name for a conversion operator to TYPE. */ /* Write the unqualified-name for a conversion operator to TYPE. */
@ -1202,6 +1242,44 @@ write_source_name (tree identifier)
write_identifier (IDENTIFIER_POINTER (identifier)); write_identifier (IDENTIFIER_POINTER (identifier));
} }
/* Encode 0 as _, and 1+ as n-1_. */
static void
write_compact_number (int num)
{
if (num > 0)
write_unsigned_number (num - 1);
write_char ('_');
}
static void
write_unnamed_type_name (const tree type __attribute__ ((__unused__)))
{
MANGLE_TRACE_TREE ("unnamed-type-name", type);
write_string ("Ut");
/* TODO: Implement discriminators for unnamed-types. */
write_char ('_');
}
/* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
<lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters */
static void
write_closure_type_name (const tree type)
{
tree fn = lambda_function (type);
tree lambda = CLASSTYPE_LAMBDA_EXPR (type);
tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
MANGLE_TRACE_TREE ("closure-type-name", type);
write_string ("Ul");
write_method_parms (parms, /*method_p=*/1, fn);
write_char ('E');
write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda));
}
/* Convert NUMBER to ascii using base BASE and generating at least /* Convert NUMBER to ascii using base BASE and generating at least
MIN_DIGITS characters. BUFFER points to the _end_ of the buffer MIN_DIGITS characters. BUFFER points to the _end_ of the buffer
into which to store the characters. Returns the number of into which to store the characters. Returns the number of
@ -1479,6 +1557,11 @@ discriminator_for_local_entity (tree entity)
/* Scan the list of local classes. */ /* Scan the list of local classes. */
entity = TREE_TYPE (entity); entity = TREE_TYPE (entity);
/* Lambdas and unnamed types have their own discriminators. */
if (LAMBDA_TYPE_P (entity) || TYPE_ANONYMOUS_P (entity))
return 0;
for (ix = 0; ; ix++) for (ix = 0; ; ix++)
{ {
tree type = VEC_index (tree, local_classes, ix); tree type = VEC_index (tree, local_classes, ix);
@ -1523,23 +1606,49 @@ write_discriminator (const int discriminator)
} }
/* Mangle the name of a function-scope entity. FUNCTION is the /* Mangle the name of a function-scope entity. FUNCTION is the
FUNCTION_DECL for the enclosing function. ENTITY is the decl for FUNCTION_DECL for the enclosing function, or a PARM_DECL for lambdas in
the entity itself. LOCAL_ENTITY is the entity that's directly default argument scope. ENTITY is the decl for the entity itself.
scoped in FUNCTION_DECL, either ENTITY itself or an enclosing scope LOCAL_ENTITY is the entity that's directly scoped in FUNCTION_DECL,
of ENTITY. either ENTITY itself or an enclosing scope of ENTITY.
<local-name> := Z <function encoding> E <entity name> [<discriminator>] <local-name> := Z <function encoding> E <entity name> [<discriminator>]
:= Z <function encoding> E s [<discriminator>] */ := Z <function encoding> E s [<discriminator>]
:= Z <function encoding> Ed [ <parameter number> ] _ <entity name> */
static void static void
write_local_name (const tree function, const tree local_entity, write_local_name (tree function, const tree local_entity,
const tree entity) const tree entity)
{ {
tree parm = NULL_TREE;
MANGLE_TRACE_TREE ("local-name", entity); MANGLE_TRACE_TREE ("local-name", entity);
if (TREE_CODE (function) == PARM_DECL)
{
parm = function;
function = DECL_CONTEXT (parm);
}
write_char ('Z'); write_char ('Z');
write_encoding (function); write_encoding (function);
write_char ('E'); write_char ('E');
/* For this purpose, parameters are numbered from right-to-left. */
if (parm)
{
tree t;
int i = 0;
for (t = DECL_ARGUMENTS (function); t; t = TREE_CHAIN (t))
{
if (t == parm)
i = 1;
else if (i)
++i;
}
write_char ('d');
write_compact_number (i - 1);
}
if (TREE_CODE (entity) == STRING_CST) if (TREE_CODE (entity) == STRING_CST)
{ {
write_char ('s'); write_char ('s');
@ -1718,6 +1827,10 @@ write_type (tree type)
break; break;
case DECLTYPE_TYPE: case DECLTYPE_TYPE:
/* These shouldn't make it into mangling. */
gcc_assert (!DECLTYPE_FOR_LAMBDA_CAPTURE (type)
&& !DECLTYPE_FOR_LAMBDA_RETURN (type));
write_char ('D'); write_char ('D');
if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type)) if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type))
write_char ('t'); write_char ('t');
@ -2236,9 +2349,7 @@ write_expression (tree expr)
int index = DECL_PARM_INDEX (expr); int index = DECL_PARM_INDEX (expr);
gcc_assert (index >= 1); gcc_assert (index >= 1);
write_string ("fp"); write_string ("fp");
if (index > 1) write_compact_number (index - 1);
write_unsigned_number (index - 2);
write_char ('_');
} }
else if (DECL_P (expr)) else if (DECL_P (expr))
{ {
@ -2701,9 +2812,7 @@ write_template_param (const tree parm)
write_char ('T'); write_char ('T');
/* NUMBER as it appears in the mangling is (-1)-indexed, with the /* NUMBER as it appears in the mangling is (-1)-indexed, with the
earliest template param denoted by `_'. */ earliest template param denoted by `_'. */
if (parm_index > 0) write_compact_number (parm_index);
write_unsigned_number (parm_index - 1);
write_char ('_');
} }
/* <template-template-param> /* <template-template-param>

View File

@ -530,12 +530,13 @@ use_thunk (tree thunk_fndecl, bool emit_p)
/* Code for synthesizing methods which have default semantics defined. */ /* Code for synthesizing methods which have default semantics defined. */
/* Generate code for default X(X&) constructor. */ /* Generate code for default X(X&) or X(X&&) constructor. */
static void static void
do_build_copy_constructor (tree fndecl) do_build_copy_constructor (tree fndecl)
{ {
tree parm = FUNCTION_FIRST_USER_PARM (fndecl); tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl);
parm = convert_from_reference (parm); parm = convert_from_reference (parm);
@ -555,6 +556,7 @@ do_build_copy_constructor (tree fndecl)
int cvquals = cp_type_quals (TREE_TYPE (parm)); int cvquals = cp_type_quals (TREE_TYPE (parm));
int i; int i;
tree binfo, base_binfo; tree binfo, base_binfo;
tree init;
VEC(tree,gc) *vbases; VEC(tree,gc) *vbases;
/* Initialize all the base-classes with the parameter converted /* Initialize all the base-classes with the parameter converted
@ -565,11 +567,12 @@ do_build_copy_constructor (tree fndecl)
for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0; for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0;
VEC_iterate (tree, vbases, i, binfo); i++) VEC_iterate (tree, vbases, i, binfo); i++)
{ {
init = build_base_path (PLUS_EXPR, parm, binfo, 1);
if (move_p)
init = move (init);
member_init_list member_init_list
= tree_cons (binfo, = tree_cons (binfo,
build_tree_list (NULL_TREE, build_tree_list (NULL_TREE, init),
build_base_path (PLUS_EXPR, parm,
binfo, 1)),
member_init_list); member_init_list);
} }
@ -579,17 +582,17 @@ do_build_copy_constructor (tree fndecl)
if (BINFO_VIRTUAL_P (base_binfo)) if (BINFO_VIRTUAL_P (base_binfo))
continue; continue;
init = build_base_path (PLUS_EXPR, parm, base_binfo, 1);
if (move_p)
init = move (init);
member_init_list member_init_list
= tree_cons (base_binfo, = tree_cons (base_binfo,
build_tree_list (NULL_TREE, build_tree_list (NULL_TREE, init),
build_base_path (PLUS_EXPR, parm,
base_binfo, 1)),
member_init_list); member_init_list);
} }
for (; fields; fields = TREE_CHAIN (fields)) for (; fields; fields = TREE_CHAIN (fields))
{ {
tree init = parm;
tree field = fields; tree field = fields;
tree expr_type; tree expr_type;
@ -622,7 +625,9 @@ do_build_copy_constructor (tree fndecl)
expr_type = cp_build_qualified_type (expr_type, quals); expr_type = cp_build_qualified_type (expr_type, quals);
} }
init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE); init = build3 (COMPONENT_REF, expr_type, parm, field, NULL_TREE);
if (move_p && TREE_CODE (expr_type) != REFERENCE_TYPE)
init = move (init);
init = build_tree_list (NULL_TREE, init); init = build_tree_list (NULL_TREE, init);
member_init_list = tree_cons (field, init, member_init_list); member_init_list = tree_cons (field, init, member_init_list);
@ -936,6 +941,8 @@ locate_copy (tree type, void *client_)
it now. */ it now. */
if (CLASSTYPE_LAZY_COPY_CTOR (type)) if (CLASSTYPE_LAZY_COPY_CTOR (type))
lazily_declare_fn (sfk_copy_constructor, type); lazily_declare_fn (sfk_copy_constructor, type);
if (CLASSTYPE_LAZY_MOVE_CTOR (type))
lazily_declare_fn (sfk_move_constructor, type);
fns = CLASSTYPE_CONSTRUCTORS (type); fns = CLASSTYPE_CONSTRUCTORS (type);
} }
else else
@ -1036,6 +1043,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
case sfk_copy_constructor: case sfk_copy_constructor:
case sfk_assignment_operator: case sfk_assignment_operator:
case sfk_move_constructor:
{ {
struct copy_data data; struct copy_data data;
@ -1057,7 +1065,9 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
} }
else else
rhs_parm_type = type; rhs_parm_type = type;
rhs_parm_type = build_reference_type (rhs_parm_type); rhs_parm_type
= cp_build_reference_type (rhs_parm_type,
kind == sfk_move_constructor);
parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types); parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types);
raises = synthesize_exception_spec (type, &locate_copy, &data); raises = synthesize_exception_spec (type, &locate_copy, &data);
break; break;
@ -1072,7 +1082,8 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
fn_type = build_exception_variant (fn_type, raises); fn_type = build_exception_variant (fn_type, raises);
fn = build_lang_decl (FUNCTION_DECL, name, fn_type); fn = build_lang_decl (FUNCTION_DECL, name, fn_type);
DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (TYPE_NAME (type)); DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (TYPE_NAME (type));
if (kind == sfk_constructor || kind == sfk_copy_constructor) if (kind == sfk_constructor || kind == sfk_copy_constructor
|| kind == sfk_move_constructor)
DECL_CONSTRUCTOR_P (fn) = 1; DECL_CONSTRUCTOR_P (fn) = 1;
else if (kind == sfk_destructor) else if (kind == sfk_destructor)
DECL_DESTRUCTOR_P (fn) = 1; DECL_DESTRUCTOR_P (fn) = 1;
@ -1175,6 +1186,8 @@ lazily_declare_fn (special_function_kind sfk, tree type)
CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0; CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0;
else if (sfk == sfk_copy_constructor) else if (sfk == sfk_copy_constructor)
CLASSTYPE_LAZY_COPY_CTOR (type) = 0; CLASSTYPE_LAZY_COPY_CTOR (type) = 0;
else if (sfk == sfk_move_constructor)
CLASSTYPE_LAZY_MOVE_CTOR (type) = 0;
else if (sfk == sfk_destructor) else if (sfk == sfk_destructor)
CLASSTYPE_LAZY_DESTRUCTOR (type) = 0; CLASSTYPE_LAZY_DESTRUCTOR (type) = 0;
/* Create appropriate clones. */ /* Create appropriate clones. */

View File

@ -1834,6 +1834,23 @@ make_anon_name (void)
return get_identifier (buf); return get_identifier (buf);
} }
/* This code is practically identical to that for creating
anonymous names, but is just used for lambdas instead. This is necessary
because anonymous names are recognized and cannot be passed to template
functions. */
/* FIXME is this still necessary? */
static GTY(()) int lambda_cnt = 0;
tree
make_lambda_name (void)
{
char buf[32];
sprintf (buf, LAMBDANAME_FORMAT, lambda_cnt++);
return get_identifier (buf);
}
/* Return (from the stack of) the BINDING, if any, established at SCOPE. */ /* Return (from the stack of) the BINDING, if any, established at SCOPE. */
static inline cxx_binding * static inline cxx_binding *
@ -2637,6 +2654,11 @@ pushdecl_class_level (tree x)
tree name; tree name;
bool is_valid = true; bool is_valid = true;
/* Do nothing if we're adding to an outer lambda closure type,
outer_binding will add it later if it's needed. */
if (current_class_type != class_binding_level->this_entity)
return true;
timevar_push (TV_NAME_LOOKUP); timevar_push (TV_NAME_LOOKUP);
/* Get the name of X. */ /* Get the name of X. */
if (TREE_CODE (x) == OVERLOAD) if (TREE_CODE (x) == OVERLOAD)
@ -3735,6 +3757,11 @@ qualify_lookup (tree val, int flags)
return true; return true;
if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES)) if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES))
return false; return false;
/* In unevaluated context, look past capture fields. */
/* FIXME this will cause trouble with the initializer extension. */
if (cp_unevaluated_operand && TREE_CODE (val) == FIELD_DECL
&& LAMBDA_TYPE_P (DECL_CONTEXT (val)))
return false;
return true; return true;
} }
@ -5114,7 +5141,8 @@ pushtag (tree name, tree type, tag_scope scope)
{ {
tree cs = current_scope (); tree cs = current_scope ();
if (scope == ts_current) if (scope == ts_current
|| (cs && TREE_CODE (cs) == FUNCTION_DECL))
context = cs; context = cs;
else if (cs != NULL_TREE && TYPE_P (cs)) else if (cs != NULL_TREE && TYPE_P (cs))
/* When declaring a friend class of a local class, we want /* When declaring a friend class of a local class, we want

View File

@ -1626,6 +1626,14 @@ static tree cp_parser_constant_expression
(cp_parser *, bool, bool *); (cp_parser *, bool, bool *);
static tree cp_parser_builtin_offsetof static tree cp_parser_builtin_offsetof
(cp_parser *); (cp_parser *);
static tree cp_parser_lambda_expression
(cp_parser *);
static void cp_parser_lambda_introducer
(cp_parser *, tree);
static void cp_parser_lambda_declarator_opt
(cp_parser *, tree);
static void cp_parser_lambda_body
(cp_parser *, tree);
/* Statements [gram.stmt.stmt] */ /* Statements [gram.stmt.stmt] */
@ -2452,6 +2460,7 @@ cp_parser_skip_to_closing_parenthesis (cp_parser *parser,
{ {
unsigned paren_depth = 0; unsigned paren_depth = 0;
unsigned brace_depth = 0; unsigned brace_depth = 0;
unsigned square_depth = 0;
if (recovering && !or_comma if (recovering && !or_comma
&& cp_parser_uncommitted_to_tentative_parse_p (parser)) && cp_parser_uncommitted_to_tentative_parse_p (parser))
@ -2468,6 +2477,15 @@ cp_parser_skip_to_closing_parenthesis (cp_parser *parser,
/* If we've run out of tokens, then there is no closing `)'. */ /* If we've run out of tokens, then there is no closing `)'. */
return 0; return 0;
/* This is good for lambda expression capture-lists. */
case CPP_OPEN_SQUARE:
++square_depth;
break;
case CPP_CLOSE_SQUARE:
if (!square_depth--)
return 0;
break;
case CPP_SEMICOLON: case CPP_SEMICOLON:
/* This matches the processing in skip_to_end_of_statement. */ /* This matches the processing in skip_to_end_of_statement. */
if (!brace_depth) if (!brace_depth)
@ -2483,7 +2501,8 @@ cp_parser_skip_to_closing_parenthesis (cp_parser *parser,
break; break;
case CPP_COMMA: case CPP_COMMA:
if (recovering && or_comma && !brace_depth && !paren_depth) if (recovering && or_comma && !brace_depth && !paren_depth
&& !square_depth)
return -1; return -1;
break; break;
@ -3283,6 +3302,20 @@ cp_parser_primary_expression (cp_parser *parser,
return expr; return expr;
} }
case CPP_OPEN_SQUARE:
if (c_dialect_objc ())
/* We have an Objective-C++ message. */
return cp_parser_objc_expression (parser);
maybe_warn_cpp0x ("lambda expressions");
return cp_parser_lambda_expression (parser);
case CPP_OBJC_STRING:
if (c_dialect_objc ())
/* We have an Objective-C++ string literal. */
return cp_parser_objc_expression (parser);
cp_parser_error (parser, "expected primary-expression");
return error_mark_node;
case CPP_KEYWORD: case CPP_KEYWORD:
switch (token->keyword) switch (token->keyword)
{ {
@ -3540,13 +3573,6 @@ cp_parser_primary_expression (cp_parser *parser,
/* Anything else is an error. */ /* Anything else is an error. */
default: default:
/* ...unless we have an Objective-C++ message or string literal,
that is. */
if (c_dialect_objc ()
&& (token->type == CPP_OPEN_SQUARE
|| token->type == CPP_OBJC_STRING))
return cp_parser_objc_expression (parser);
cp_parser_error (parser, "expected primary-expression"); cp_parser_error (parser, "expected primary-expression");
return error_mark_node; return error_mark_node;
} }
@ -6925,6 +6951,525 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
return finish_trait_expr (kind, type1, type2); return finish_trait_expr (kind, type1, type2);
} }
/* Lambdas that appear in variable initializer or default argument scope
get that in their mangling, so we need to record it. We might as well
use the count for function and namespace scopes as well. */
static tree lambda_scope;
static int lambda_count;
typedef struct GTY(()) tree_int
{
tree t;
int i;
} tree_int;
DEF_VEC_O(tree_int);
DEF_VEC_ALLOC_O(tree_int,gc);
static GTY(()) VEC(tree_int,gc) *lambda_scope_stack;
static void
start_lambda_scope (tree decl)
{
tree_int ti;
gcc_assert (decl);
/* Once we're inside a function, we ignore other scopes and just push
the function again so that popping works properly. */
if (current_function_decl && TREE_CODE (decl) != FUNCTION_DECL)
decl = current_function_decl;
ti.t = lambda_scope;
ti.i = lambda_count;
VEC_safe_push (tree_int, gc, lambda_scope_stack, &ti);
if (lambda_scope != decl)
{
/* Don't reset the count if we're still in the same function. */
lambda_scope = decl;
lambda_count = 0;
}
}
static void
record_lambda_scope (tree lambda)
{
LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope;
LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++;
}
static void
finish_lambda_scope (void)
{
tree_int *p = VEC_last (tree_int, lambda_scope_stack);
if (lambda_scope != p->t)
{
lambda_scope = p->t;
lambda_count = p->i;
}
VEC_pop (tree_int, lambda_scope_stack);
}
/* We want to determine the linkage of a lambda type at pushtag time,
before CLASSTYPE_LAMBDA_EXPR has been set. So this callback allows us
to find out whether the current lambda mangling scope will give us
linkage or not. */
bool
no_linkage_lambda_type_p (tree type)
{
tree lambda, scope;
if (!LAMBDA_TYPE_P (type))
return false;
lambda = CLASSTYPE_LAMBDA_EXPR (type);
if (lambda)
scope = LAMBDA_EXPR_EXTRA_SCOPE (lambda);
else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type))
/* We can't use lambda_scope, and CLASSTYPE_TEMPLATE_INFO won't be set
yet either, so guess it's public for now. */
return false;
else
scope = lambda_scope;
return (scope == NULL_TREE);
}
/* Parse a lambda expression.
lambda-expression:
lambda-introducer lambda-declarator [opt] compound-statement
Returns a representation of the expression. */
static tree
cp_parser_lambda_expression (cp_parser* parser)
{
tree lambda_expr = build_lambda_expr ();
tree type;
LAMBDA_EXPR_LOCATION (lambda_expr)
= cp_lexer_peek_token (parser->lexer)->location;
/* We may be in the middle of deferred access check. Disable
it now. */
push_deferring_access_checks (dk_no_deferred);
type = begin_lambda_type (lambda_expr);
record_lambda_scope (lambda_expr);
{
/* Inside the class, surrounding template-parameter-lists do not apply. */
unsigned int saved_num_template_parameter_lists
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
cp_parser_lambda_introducer (parser, lambda_expr);
/* By virtue of defining a local class, a lambda expression has access to
the private variables of enclosing classes. */
cp_parser_lambda_declarator_opt (parser, lambda_expr);
cp_parser_lambda_body (parser, lambda_expr);
/* The capture list was built up in reverse order; fix that now. */
{
tree newlist = NULL_TREE;
tree elt, next;
for (elt = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr);
elt; elt = next)
{
/* Also add __ to the beginning of the field name so that code
outside the lambda body can't see the captured name. We could
just remove the name entirely, but this is more useful for
debugging. */
tree field = TREE_PURPOSE (elt);
char *buf
= (char *) alloca (IDENTIFIER_LENGTH (DECL_NAME (field)) + 3);
buf[1] = buf[0] = '_';
memcpy (buf + 2, IDENTIFIER_POINTER (DECL_NAME (field)),
IDENTIFIER_LENGTH (DECL_NAME (field)) + 1);
DECL_NAME (field) = get_identifier (buf);
next = TREE_CHAIN (elt);
TREE_CHAIN (elt) = newlist;
newlist = elt;
}
LAMBDA_EXPR_CAPTURE_LIST (lambda_expr) = newlist;
}
type = finish_struct (type, /*attributes=*/NULL_TREE);
parser->num_template_parameter_lists = saved_num_template_parameter_lists;
}
pop_deferring_access_checks ();
return build_lambda_object (lambda_expr);
}
/* Parse the beginning of a lambda expression.
lambda-introducer:
[ lambda-capture [opt] ]
LAMBDA_EXPR is the current representation of the lambda expression. */
static void
cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
{
/* Need commas after the first capture. */
bool first = true;
/* Eat the leading `['. */
cp_parser_require (parser, CPP_OPEN_SQUARE, "%<[%>");
/* Record default capture mode. "[&" "[=" "[&," "[=," */
if (cp_lexer_next_token_is (parser->lexer, CPP_AND)
&& cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_NAME)
LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) = CPLD_REFERENCE;
else if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) = CPLD_COPY;
if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) != CPLD_NONE)
{
cp_lexer_consume_token (parser->lexer);
first = false;
}
while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE))
{
cp_token* capture_token;
tree capture_id;
tree capture_init_expr;
cp_id_kind idk = CP_ID_KIND_NONE;
enum capture_kind_type
{
BY_COPY,
BY_REFERENCE
};
enum capture_kind_type capture_kind = BY_COPY;
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
{
error ("expected end of capture-list");
return;
}
if (first)
first = false;
else
cp_parser_require (parser, CPP_COMMA, "%<,%>");
/* Possibly capture `this'. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_THIS))
{
cp_lexer_consume_token (parser->lexer);
add_capture (lambda_expr,
/*id=*/get_identifier ("__this"),
/*initializer=*/finish_this_expr(),
/*by_reference_p=*/false);
continue;
}
/* Remember whether we want to capture as a reference or not. */
if (cp_lexer_next_token_is (parser->lexer, CPP_AND))
{
capture_kind = BY_REFERENCE;
cp_lexer_consume_token (parser->lexer);
}
/* Get the identifier. */
capture_token = cp_lexer_peek_token (parser->lexer);
capture_id = cp_parser_identifier (parser);
if (capture_id == error_mark_node)
/* Would be nice to have a cp_parser_skip_to_closing_x for general
delimiters, but I modified this to stop on unnested ']' as well. It
was already changed to stop on unnested '}', so the
"closing_parenthesis" name is no more misleading with my change. */
{
cp_parser_skip_to_closing_parenthesis (parser,
/*recovering=*/true,
/*or_comma=*/true,
/*consume_paren=*/true);
continue;
}
/* Find the initializer for this capture. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
{
/* An explicit expression exists. */
cp_lexer_consume_token (parser->lexer);
pedwarn (input_location, OPT_pedantic,
"ISO C++ does not allow initializers "
"in lambda expression capture lists");
capture_init_expr = cp_parser_assignment_expression (parser,
/*cast_p=*/true,
&idk);
}
else
{
const char* error_msg;
/* Turn the identifier into an id-expression. */
capture_init_expr
= cp_parser_lookup_name
(parser,
capture_id,
none_type,
/*is_template=*/false,
/*is_namespace=*/false,
/*check_dependency=*/true,
/*ambiguous_decls=*/NULL,
capture_token->location);
capture_init_expr
= finish_id_expression
(capture_id,
capture_init_expr,
parser->scope,
&idk,
/*integral_constant_expression_p=*/false,
/*allow_non_integral_constant_expression_p=*/false,
/*non_integral_constant_expression_p=*/NULL,
/*template_p=*/false,
/*done=*/true,
/*address_p=*/false,
/*template_arg_p=*/false,
&error_msg,
capture_token->location);
}
if (TREE_CODE (capture_init_expr) == IDENTIFIER_NODE)
capture_init_expr
= unqualified_name_lookup_error (capture_init_expr);
add_capture (lambda_expr,
capture_id,
capture_init_expr,
/*by_reference_p=*/capture_kind == BY_REFERENCE);
}
cp_parser_require (parser, CPP_CLOSE_SQUARE, "%<]%>");
}
/* Parse the (optional) middle of a lambda expression.
lambda-declarator:
( parameter-declaration-clause [opt] )
attribute-specifier [opt]
mutable [opt]
exception-specification [opt]
lambda-return-type-clause [opt]
LAMBDA_EXPR is the current representation of the lambda expression. */
static void
cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
{
/* 5.1.1.4 of the standard says:
If a lambda-expression does not include a lambda-declarator, it is as if
the lambda-declarator were ().
This means an empty parameter list, no attributes, and no exception
specification. */
tree param_list = void_list_node;
tree attributes = NULL_TREE;
tree exception_spec = NULL_TREE;
tree t;
/* The lambda-declarator is optional, but must begin with an opening
parenthesis if present. */
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
cp_lexer_consume_token (parser->lexer);
begin_scope (sk_function_parms, /*entity=*/NULL_TREE);
/* Parse parameters. */
param_list = cp_parser_parameter_declaration_clause (parser);
/* Default arguments shall not be specified in the
parameter-declaration-clause of a lambda-declarator. */
for (t = param_list; t; t = TREE_CHAIN (t))
if (TREE_PURPOSE (t))
pedwarn (DECL_SOURCE_LOCATION (TREE_VALUE (t)), OPT_pedantic,
"default argument specified for lambda parameter");
cp_parser_require (parser, CPP_CLOSE_PAREN, "%<)%>");
attributes = cp_parser_attributes_opt (parser);
/* Parse optional `mutable' keyword. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_MUTABLE))
{
cp_lexer_consume_token (parser->lexer);
LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1;
}
/* Parse optional exception specification. */
exception_spec = cp_parser_exception_specification_opt (parser);
/* Parse optional trailing return type. */
if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
{
cp_lexer_consume_token (parser->lexer);
LAMBDA_EXPR_RETURN_TYPE (lambda_expr) = cp_parser_type_id (parser);
}
/* The function parameters must be in scope all the way until after the
trailing-return-type in case of decltype. */
for (t = current_binding_level->names; t; t = TREE_CHAIN (t))
pop_binding (DECL_NAME (t), t);
leave_scope ();
}
/* Create the function call operator.
Messing with declarators like this is no uglier than building up the
FUNCTION_DECL by hand, and this is less likely to get out of sync with
other code. */
{
cp_decl_specifier_seq return_type_specs;
cp_declarator* declarator;
tree fco;
int quals;
void *p;
clear_decl_specs (&return_type_specs);
if (LAMBDA_EXPR_RETURN_TYPE (lambda_expr))
return_type_specs.type = LAMBDA_EXPR_RETURN_TYPE (lambda_expr);
else
/* Maybe we will deduce the return type later, but we can use void
as a placeholder return type anyways. */
return_type_specs.type = void_type_node;
p = obstack_alloc (&declarator_obstack, 0);
declarator = make_id_declarator (NULL_TREE, ansi_opname (CALL_EXPR),
sfk_none);
quals = (LAMBDA_EXPR_MUTABLE_P (lambda_expr)
? TYPE_UNQUALIFIED : TYPE_QUAL_CONST);
declarator = make_call_declarator (declarator, param_list, quals,
exception_spec,
/*late_return_type=*/NULL_TREE);
fco = grokmethod (&return_type_specs,
declarator,
attributes);
DECL_INITIALIZED_IN_CLASS_P (fco) = 1;
DECL_ARTIFICIAL (fco) = 1;
finish_member_declaration (fco);
obstack_free (&declarator_obstack, p);
}
}
/* Parse the body of a lambda expression, which is simply
compound-statement
but which requires special handling.
LAMBDA_EXPR is the current representation of the lambda expression. */
static void
cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
{
bool nested = (current_function_decl != NULL_TREE);
if (nested)
push_function_context ();
/* Finish the function call operator
- class_specifier
+ late_parsing_for_member
+ function_definition_after_declarator
+ ctor_initializer_opt_and_function_body */
{
tree fco = lambda_function (lambda_expr);
tree body;
bool done = false;
/* Let the front end know that we are going to be defining this
function. */
start_preparsed_function (fco,
NULL_TREE,
SF_PRE_PARSED | SF_INCLASS_INLINE);
start_lambda_scope (fco);
body = begin_function_body ();
/* 5.1.1.4 of the standard says:
If a lambda-expression does not include a trailing-return-type, it
is as if the trailing-return-type denotes the following type:
if the compound-statement is of the form
{ return attribute-specifier [opt] expression ; }
the type of the returned expression after lvalue-to-rvalue
conversion (_conv.lval_ 4.1), array-to-pointer conversion
(_conv.array_ 4.2), and function-to-pointer conversion
(_conv.func_ 4.3);
otherwise, void. */
/* In a lambda that has neither a lambda-return-type-clause
nor a deducible form, errors should be reported for return statements
in the body. Since we used void as the placeholder return type, parsing
the body as usual will give such desired behavior. */
if (!LAMBDA_EXPR_RETURN_TYPE (lambda_expr)
&& cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)
&& cp_lexer_peek_nth_token (parser->lexer, 2)->keyword == RID_RETURN
&& cp_lexer_peek_nth_token (parser->lexer, 3)->type != CPP_SEMICOLON)
{
tree compound_stmt;
tree expr = NULL_TREE;
cp_id_kind idk = CP_ID_KIND_NONE;
/* Parse tentatively in case there's more after the initial return
statement. */
cp_parser_parse_tentatively (parser);
cp_parser_require (parser, CPP_OPEN_BRACE, "%<{%>");
cp_parser_require_keyword (parser, RID_RETURN, "%<return%>");
expr = cp_parser_expression (parser, /*cast_p=*/false, &idk);
cp_parser_require (parser, CPP_SEMICOLON, "%<;%>");
cp_parser_require (parser, CPP_CLOSE_BRACE, "%<}%>");
if (cp_parser_parse_definitely (parser))
{
apply_lambda_return_type (lambda_expr, lambda_return_type (expr));
compound_stmt = begin_compound_stmt (0);
/* Will get error here if type not deduced yet. */
finish_return_stmt (expr);
finish_compound_stmt (compound_stmt);
done = true;
}
}
if (!done)
{
if (!LAMBDA_EXPR_RETURN_TYPE (lambda_expr))
LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda_expr) = true;
/* TODO: does begin_compound_stmt want BCS_FN_BODY?
cp_parser_compound_stmt does not pass it. */
cp_parser_function_body (parser);
LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda_expr) = false;
}
finish_function_body (body);
finish_lambda_scope ();
/* Finish the function and generate code for it if necessary. */
expand_or_defer_fn (finish_function (/*inline*/2));
}
if (nested)
pop_function_context();
}
/* Statements [gram.stmt.stmt] */ /* Statements [gram.stmt.stmt] */
/* Parse a statement. /* Parse a statement.
@ -13033,9 +13578,21 @@ cp_parser_init_declarator (cp_parser* parser,
} }
} }
else else
initializer = cp_parser_initializer (parser, {
&is_direct_init, /* We want to record the extra mangling scope for in-class
&is_non_constant_init); initializers of class members and initializers of static data
member templates. The former is a C++0x feature which isn't
implemented yet, and I expect it will involve deferring
parsing of the initializer until end of class as with default
arguments. So right here we only handle the latter. */
if (!member_p && processing_template_decl)
start_lambda_scope (decl);
initializer = cp_parser_initializer (parser,
&is_direct_init,
&is_non_constant_init);
if (!member_p && processing_template_decl)
finish_lambda_scope ();
}
} }
/* The old parser allows attributes to appear after a parenthesized /* The old parser allows attributes to appear after a parenthesized
@ -14453,7 +15010,8 @@ cp_parser_parameter_declaration (cp_parser *parser,
/* If we are defining a class, then the tokens that make up the /* If we are defining a class, then the tokens that make up the
default argument must be saved and processed later. */ default argument must be saved and processed later. */
if (!template_parm_p && at_class_scope_p () if (!template_parm_p && at_class_scope_p ()
&& TYPE_BEING_DEFINED (current_class_type)) && TYPE_BEING_DEFINED (current_class_type)
&& !LAMBDA_TYPE_P (current_class_type))
{ {
unsigned depth = 0; unsigned depth = 0;
int maybe_template_id = 0; int maybe_template_id = 0;
@ -17841,7 +18399,7 @@ cp_parser_function_definition_from_specifiers_and_declarator
/* Parse the part of a function-definition that follows the /* Parse the part of a function-definition that follows the
declarator. INLINE_P is TRUE iff this function is an inline declarator. INLINE_P is TRUE iff this function is an inline
function defined with a class-specifier. function defined within a class-specifier.
Returns the function defined. */ Returns the function defined. */
@ -17893,6 +18451,9 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
saved_num_template_parameter_lists saved_num_template_parameter_lists
= parser->num_template_parameter_lists; = parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0; parser->num_template_parameter_lists = 0;
start_lambda_scope (current_function_decl);
/* If the next token is `try', then we are looking at a /* If the next token is `try', then we are looking at a
function-try-block. */ function-try-block. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY)) if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
@ -17903,6 +18464,8 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
ctor_initializer_p ctor_initializer_p
= cp_parser_ctor_initializer_opt_and_function_body (parser); = cp_parser_ctor_initializer_opt_and_function_body (parser);
finish_lambda_scope ();
/* Finish the function. */ /* Finish the function. */
fn = finish_function ((ctor_initializer_p ? 1 : 0) | fn = finish_function ((ctor_initializer_p ? 1 : 0) |
(inline_p ? 2 : 0)); (inline_p ? 2 : 0));
@ -18530,7 +19093,7 @@ static void
cp_parser_late_parsing_default_args (cp_parser *parser, tree fn) cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
{ {
bool saved_local_variables_forbidden_p; bool saved_local_variables_forbidden_p;
tree parm; tree parm, parmdecl;
/* While we're parsing the default args, we might (due to the /* While we're parsing the default args, we might (due to the
statement expression extension) encounter more classes. We want statement expression extension) encounter more classes. We want
@ -18544,9 +19107,11 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
saved_local_variables_forbidden_p = parser->local_variables_forbidden_p; saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
parser->local_variables_forbidden_p = true; parser->local_variables_forbidden_p = true;
for (parm = TYPE_ARG_TYPES (TREE_TYPE (fn)); for (parm = TYPE_ARG_TYPES (TREE_TYPE (fn)),
parm; parmdecl = DECL_ARGUMENTS (fn);
parm = TREE_CHAIN (parm)) parm && parm != void_list_node;
parm = TREE_CHAIN (parm),
parmdecl = TREE_CHAIN (parmdecl))
{ {
cp_token_cache *tokens; cp_token_cache *tokens;
tree default_arg = TREE_PURPOSE (parm); tree default_arg = TREE_PURPOSE (parm);
@ -18568,6 +19133,8 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
tokens = DEFARG_TOKENS (default_arg); tokens = DEFARG_TOKENS (default_arg);
cp_parser_push_lexer_for_tokens (parser, tokens); cp_parser_push_lexer_for_tokens (parser, tokens);
start_lambda_scope (parmdecl);
/* Parse the assignment-expression. */ /* Parse the assignment-expression. */
parsed_arg = cp_parser_assignment_expression (parser, /*cast_p=*/false, NULL); parsed_arg = cp_parser_assignment_expression (parser, /*cast_p=*/false, NULL);
if (parsed_arg == error_mark_node) if (parsed_arg == error_mark_node)
@ -18586,6 +19153,8 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
VEC_iterate (tree, insts, ix, copy); ix++) VEC_iterate (tree, insts, ix, copy); ix++)
TREE_PURPOSE (copy) = parsed_arg; TREE_PURPOSE (copy) = parsed_arg;
finish_lambda_scope ();
/* If the token stream has not been completely used up, then /* If the token stream has not been completely used up, then
there was extra junk after the end of the default there was extra junk after the end of the default
argument. */ argument. */

View File

@ -300,7 +300,7 @@ get_template_info (const_tree t)
if (DECL_P (t) && DECL_LANG_SPECIFIC (t)) if (DECL_P (t) && DECL_LANG_SPECIFIC (t))
tinfo = DECL_TEMPLATE_INFO (t); tinfo = DECL_TEMPLATE_INFO (t);
if (!tinfo && TREE_CODE (t) == TYPE_DECL) if (!tinfo && DECL_IMPLICIT_TYPEDEF_P (t))
t = TREE_TYPE (t); t = TREE_TYPE (t);
if (TAGGED_TYPE_P (t)) if (TAGGED_TYPE_P (t))
@ -6230,6 +6230,7 @@ lookup_template_class (tree d1,
if (!is_partial_instantiation if (!is_partial_instantiation
&& !PRIMARY_TEMPLATE_P (gen_tmpl) && !PRIMARY_TEMPLATE_P (gen_tmpl)
&& !LAMBDA_TYPE_P (TREE_TYPE (gen_tmpl))
&& TREE_CODE (CP_DECL_CONTEXT (gen_tmpl)) == NAMESPACE_DECL) && TREE_CODE (CP_DECL_CONTEXT (gen_tmpl)) == NAMESPACE_DECL)
{ {
found = xref_tag_from_type (TREE_TYPE (gen_tmpl), found = xref_tag_from_type (TREE_TYPE (gen_tmpl),
@ -9162,6 +9163,22 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE); DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE);
SET_DECL_IMPLICIT_INSTANTIATION (r); SET_DECL_IMPLICIT_INSTANTIATION (r);
} }
else if (cp_unevaluated_operand)
{
/* We're substituting this var in a decltype outside of its
scope, such as for a lambda return type. Don't add it to
local_specializations, do perform auto deduction. */
tree auto_node = type_uses_auto (type);
tree init
= tsubst_expr (DECL_INITIAL (t), args, complain, in_decl,
/*constant_expression_p=*/false);
if (auto_node && init && describable_type (init))
{
type = do_auto_deduction (type, init, auto_node);
TREE_TYPE (r) = type;
}
}
else else
register_local_specialization (r, t); register_local_specialization (r, t);
@ -10153,9 +10170,13 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
--cp_unevaluated_operand; --cp_unevaluated_operand;
--c_inhibit_evaluation_warnings; --c_inhibit_evaluation_warnings;
type = if (DECLTYPE_FOR_LAMBDA_CAPTURE (t))
finish_decltype_type (type, type = lambda_capture_field_type (type);
DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t)); else if (DECLTYPE_FOR_LAMBDA_RETURN (t))
type = lambda_return_type (type);
else
type = finish_decltype_type
(type, DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t));
return cp_build_qualified_type_real (type, return cp_build_qualified_type_real (type,
cp_type_quals (t) cp_type_quals (t)
| cp_type_quals (type), | cp_type_quals (type),
@ -12359,6 +12380,39 @@ tsubst_copy_and_build (tree t,
} }
return t; return t;
case LAMBDA_EXPR:
{
tree r = build_lambda_expr ();
tree type = tsubst (TREE_TYPE (t), args, complain, NULL_TREE);
TREE_TYPE (r) = type;
CLASSTYPE_LAMBDA_EXPR (type) = r;
LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)
= LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);
LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);
LAMBDA_EXPR_DISCRIMINATOR (r)
= (LAMBDA_EXPR_DISCRIMINATOR (t));
LAMBDA_EXPR_CAPTURE_LIST (r)
= RECUR (LAMBDA_EXPR_CAPTURE_LIST (t));
LAMBDA_EXPR_THIS_CAPTURE (r)
= RECUR (LAMBDA_EXPR_THIS_CAPTURE (t));
LAMBDA_EXPR_EXTRA_SCOPE (r)
= RECUR (LAMBDA_EXPR_EXTRA_SCOPE (t));
/* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */
determine_visibility (TYPE_NAME (type));
/* Now that we know visibility, instantiate the type so we have a
declaration of the op() for later calls to lambda_function. */
complete_type (type);
type = tsubst (LAMBDA_EXPR_RETURN_TYPE (t), args, complain, in_decl);
if (type)
apply_lambda_return_type (r, type);
return build_lambda_object (r);
}
default: default:
/* Handle Objective-C++ constructs, if appropriate. */ /* Handle Objective-C++ constructs, if appropriate. */
{ {
@ -15959,10 +16013,11 @@ instantiate_decl (tree d, int defer_ok,
SET_DECL_IMPLICIT_INSTANTIATION (d); SET_DECL_IMPLICIT_INSTANTIATION (d);
} }
if (!defer_ok) /* Recheck the substitutions to obtain any warning messages
about ignoring cv qualifiers. Don't do this for artificial decls,
as it breaks the context-sensitive substitution for lambda op(). */
if (!defer_ok && !DECL_ARTIFICIAL (d))
{ {
/* Recheck the substitutions to obtain any warning messages
about ignoring cv qualifiers. */
tree gen = DECL_TEMPLATE_RESULT (gen_tmpl); tree gen = DECL_TEMPLATE_RESULT (gen_tmpl);
tree type = TREE_TYPE (gen); tree type = TREE_TYPE (gen);

View File

@ -1380,6 +1380,8 @@ lookup_fnfields_1 (tree type, tree name)
lazily_declare_fn (sfk_constructor, type); lazily_declare_fn (sfk_constructor, type);
if (CLASSTYPE_LAZY_COPY_CTOR (type)) if (CLASSTYPE_LAZY_COPY_CTOR (type))
lazily_declare_fn (sfk_copy_constructor, type); lazily_declare_fn (sfk_copy_constructor, type);
if (CLASSTYPE_LAZY_MOVE_CTOR (type))
lazily_declare_fn (sfk_move_constructor, type);
} }
else if (name == ansi_assopname(NOP_EXPR) else if (name == ansi_assopname(NOP_EXPR)
&& CLASSTYPE_LAZY_ASSIGNMENT_OP (type)) && CLASSTYPE_LAZY_ASSIGNMENT_OP (type))

View File

@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. If not see
static tree maybe_convert_cond (tree); static tree maybe_convert_cond (tree);
static tree finalize_nrv_r (tree *, int *, void *); static tree finalize_nrv_r (tree *, int *, void *);
static tree capture_decltype (tree);
/* Deferred Access Checking Overview /* Deferred Access Checking Overview
@ -1445,6 +1446,21 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
return error_mark_node; return error_mark_node;
} }
/* If decl is a field, object has a lambda type, and decl is not a member
of that type, then we have a reference to a member of 'this' from a
lambda inside a non-static member function, and we must get to decl
through the 'this' capture. If decl is not a member of that object,
either, then its access will still fail later. */
if (LAMBDA_TYPE_P (TREE_TYPE (object))
&& !same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (decl),
TREE_TYPE (object)))
object = cp_build_indirect_ref (lambda_expr_this_capture
(CLASSTYPE_LAMBDA_EXPR
(TREE_TYPE (object))),
/*errorstring=*/"",
/*complain=*/tf_warning_or_error);
if (current_class_ptr) if (current_class_ptr)
TREE_USED (current_class_ptr) = 1; TREE_USED (current_class_ptr) = 1;
if (processing_template_decl && !qualifying_scope) if (processing_template_decl && !qualifying_scope)
@ -2049,7 +2065,14 @@ finish_this_expr (void)
if (current_class_ptr) if (current_class_ptr)
{ {
result = current_class_ptr; tree type = TREE_TYPE (current_class_ref);
/* In a lambda expression, 'this' refers to the captured 'this'. */
if (LAMBDA_TYPE_P (type))
result = lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (type));
else
result = current_class_ptr;
} }
else if (current_function_decl else if (current_function_decl
&& DECL_STATIC_FUNCTION_P (current_function_decl)) && DECL_STATIC_FUNCTION_P (current_function_decl))
@ -2613,6 +2636,18 @@ baselink_for_fns (tree fns)
return build_baselink (cl, cl, fns, /*optype=*/NULL_TREE); return build_baselink (cl, cl, fns, /*optype=*/NULL_TREE);
} }
/* Returns true iff DECL is an automatic variable from a function outside
the current one. */
static bool
outer_automatic_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);
}
/* ID_EXPRESSION is a representation of parsed, but unprocessed, /* ID_EXPRESSION is a representation of parsed, but unprocessed,
id-expression. (See cp_parser_id_expression for details.) SCOPE, id-expression. (See cp_parser_id_expression for details.) SCOPE,
if non-NULL, is the type or namespace used to explicitly qualify if non-NULL, is the type or namespace used to explicitly qualify
@ -2714,12 +2749,61 @@ finish_id_expression (tree id_expression,
if (!scope && decl != error_mark_node) if (!scope && decl != error_mark_node)
maybe_note_name_used_in_class (id_expression, decl); maybe_note_name_used_in_class (id_expression, decl);
/* Disallow uses of local variables from containing functions. */ /* Disallow uses of local variables from containing functions, except
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) within lambda-expressions. */
if (outer_automatic_var_p (decl)
/* It's not a use (3.2) if we're in an unevaluated context. */
&& !cp_unevaluated_operand)
{ {
tree context = decl_function_context (decl); tree context = DECL_CONTEXT (decl);
if (context != NULL_TREE && context != current_function_decl tree containing_function = current_function_decl;
&& ! TREE_STATIC (decl)) tree lambda_stack = NULL_TREE;
tree lambda_expr = NULL_TREE;
/* Core issue 696: "[At the July 2009 meeting] the CWG expressed
support for an approach in which a reference to a local
[constant] automatic variable in a nested class or lambda body
would enter the expression as an rvalue, which would reduce
the complexity of the problem"
FIXME update for final resolution of core issue 696. */
if (DECL_INTEGRAL_CONSTANT_VAR_P (decl))
return integral_constant_value (decl);
/* If we are in a lambda function, we can move out until we hit
1. the context,
2. a non-lambda function, or
3. a non-default capturing lambda function. */
while (context != containing_function
&& LAMBDA_FUNCTION_P (containing_function))
{
lambda_expr = CLASSTYPE_LAMBDA_EXPR
(DECL_CONTEXT (containing_function));
if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr)
== CPLD_NONE)
break;
lambda_stack = tree_cons (NULL_TREE,
lambda_expr,
lambda_stack);
containing_function
= decl_function_context (containing_function);
}
if (context == containing_function)
{
decl = add_default_capture (lambda_stack,
/*id=*/DECL_NAME (decl),
/*initializer=*/decl);
}
else if (lambda_expr)
{
error ("%qD is not captured", decl);
return error_mark_node;
}
else
{ {
error (TREE_CODE (decl) == VAR_DECL error (TREE_CODE (decl) == VAR_DECL
? "use of %<auto%> variable from containing function" ? "use of %<auto%> variable from containing function"
@ -4788,6 +4872,18 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p)
if (real_lvalue_p (expr)) if (real_lvalue_p (expr))
type = build_reference_type (type); type = build_reference_type (type);
} }
/* Within a lambda-expression:
Every occurrence of decltype((x)) where x is a possibly
parenthesized id-expression that names an entity of
automatic storage duration is treated as if x were
transformed into an access to a corresponding data member
of the closure type that would have been declared if x
were a use of the denoted entity. */
else if (outer_automatic_var_p (expr)
&& current_function_decl
&& LAMBDA_FUNCTION_P (current_function_decl))
type = capture_decltype (expr);
else else
{ {
/* Otherwise, where T is the type of e, if e is an lvalue, /* Otherwise, where T is the type of e, if e is an lvalue,
@ -4842,6 +4938,8 @@ classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
it now. */ it now. */
if (CLASSTYPE_LAZY_COPY_CTOR (type)) if (CLASSTYPE_LAZY_COPY_CTOR (type))
lazily_declare_fn (sfk_copy_constructor, type); lazily_declare_fn (sfk_copy_constructor, type);
if (CLASSTYPE_LAZY_MOVE_CTOR (type))
lazily_declare_fn (sfk_move_constructor, type);
fns = CLASSTYPE_CONSTRUCTORS (type); fns = CLASSTYPE_CONSTRUCTORS (type);
} }
else else
@ -5105,4 +5203,416 @@ float_const_decimal64_p (void)
return 0; return 0;
} }
/* Constructor for a lambda expression. */
tree
build_lambda_expr (void)
{
tree lambda = make_node (LAMBDA_EXPR);
LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) = CPLD_NONE;
LAMBDA_EXPR_CAPTURE_LIST (lambda) = NULL_TREE;
LAMBDA_EXPR_THIS_CAPTURE (lambda) = NULL_TREE;
LAMBDA_EXPR_RETURN_TYPE (lambda) = NULL_TREE;
LAMBDA_EXPR_MUTABLE_P (lambda) = false;
return lambda;
}
/* Create the closure object for a LAMBDA_EXPR. */
tree
build_lambda_object (tree lambda_expr)
{
/* Build aggregate constructor call.
- cp_parser_braced_list
- cp_parser_functional_cast */
VEC(constructor_elt,gc) *elts = NULL;
tree node, expr, type;
location_t saved_loc;
if (processing_template_decl)
return lambda_expr;
/* Make sure any error messages refer to the lambda-introducer. */
saved_loc = input_location;
input_location = LAMBDA_EXPR_LOCATION (lambda_expr);
for (node = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr);
node;
node = TREE_CHAIN (node))
{
tree field = TREE_PURPOSE (node);
tree val = TREE_VALUE (node);
/* Mere mortals can't copy arrays with aggregate initialization, so
do some magic to make it work here. */
if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
val = build_array_copy (val);
CONSTRUCTOR_APPEND_ELT (elts, DECL_NAME (field), val);
}
expr = build_constructor (init_list_type_node, elts);
CONSTRUCTOR_IS_DIRECT_INIT (expr) = 1;
/* 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);
CLASSTYPE_NON_AGGREGATE (type) = 0;
expr = finish_compound_literal (type, expr);
CLASSTYPE_NON_AGGREGATE (type) = 1;
input_location = saved_loc;
return expr;
}
/* Return an initialized RECORD_TYPE for LAMBDA.
LAMBDA must have its explicit captures already. */
tree
begin_lambda_type (tree lambda)
{
tree type;
{
/* Unique name. This is just like an unnamed class, but we cannot use
make_anon_name because of certain checks against TYPE_ANONYMOUS_P. */
tree name;
name = make_lambda_name ();
/* Create the new RECORD_TYPE for this lambda. */
type = xref_tag (/*tag_code=*/record_type,
name,
/*scope=*/ts_within_enclosing_non_class,
/*template_header_p=*/false);
}
/* Designate it as a struct so that we can use aggregate initialization. */
CLASSTYPE_DECLARED_CLASS (type) = false;
/* Clear base types. */
xref_basetypes (type, /*bases=*/NULL_TREE);
/* Start the class. */
type = begin_class_definition (type, /*attributes=*/NULL_TREE);
/* Cross-reference the expression and the type. */
TREE_TYPE (lambda) = type;
CLASSTYPE_LAMBDA_EXPR (type) = lambda;
return type;
}
/* Returns the type to use for the return type of the operator() of a
closure class. */
tree
lambda_return_type (tree expr)
{
tree type;
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);
}
else
type = type_decays_to (unlowered_expr_type (expr));
return type;
}
/* Given a LAMBDA_EXPR or closure type LAMBDA, return the op() of the
closure type. */
tree
lambda_function (tree lambda)
{
tree type;
if (TREE_CODE (lambda) == LAMBDA_EXPR)
type = TREE_TYPE (lambda);
else
type = lambda;
gcc_assert (LAMBDA_TYPE_P (type));
/* Don't let debug_tree cause instantiation. */
if (CLASSTYPE_TEMPLATE_INSTANTIATION (type) && !COMPLETE_TYPE_P (type))
return NULL_TREE;
lambda = lookup_member (type, ansi_opname (CALL_EXPR),
/*protect=*/0, /*want_type=*/false);
if (lambda)
lambda = BASELINK_FUNCTIONS (lambda);
return lambda;
}
/* Returns the type to use for the FIELD_DECL corresponding to the
capture of EXPR.
The caller should add REFERENCE_TYPE for capture by reference. */
tree
lambda_capture_field_type (tree expr)
{
tree type;
if (type_dependent_expression_p (expr))
{
type = cxx_make_type (DECLTYPE_TYPE);
DECLTYPE_TYPE_EXPR (type) = expr;
DECLTYPE_FOR_LAMBDA_CAPTURE (type) = true;
SET_TYPE_STRUCTURAL_EQUALITY (type);
}
else
type = non_reference (unlowered_expr_type (expr));
return type;
}
/* Recompute the return type for LAMBDA with body of the form:
{ return EXPR ; } */
void
apply_lambda_return_type (tree lambda, tree return_type)
{
tree fco = lambda_function (lambda);
tree result;
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;
/* TREE_TYPE (FUNCTION_DECL) == METHOD_TYPE
TREE_TYPE (METHOD_TYPE) == return-type */
TREE_TYPE (TREE_TYPE (fco)) = return_type;
result = DECL_RESULT (fco);
if (result == NULL_TREE)
return;
/* 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. */
result = build_decl (input_location, RESULT_DECL, NULL_TREE,
TYPE_MAIN_VARIANT (return_type));
DECL_ARTIFICIAL (result) = 1;
DECL_IGNORED_P (result) = 1;
cp_apply_type_quals_to_decl (cp_type_quals (return_type),
result);
DECL_RESULT (fco) = result;
if (!processing_template_decl && aggregate_value_p (result, fco))
{
#ifdef PCC_STATIC_STRUCT_RETURN
cfun->returns_pcc_struct = 1;
#endif
cfun->returns_struct = 1;
}
}
/* DECL is a local variable or parameter from the surrounding scope of a
lambda-expression. Returns the decltype for a use of the capture field
for DECL even if it hasn't been captured yet. */
static tree
capture_decltype (tree decl)
{
tree lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl));
/* FIXME do lookup instead of list walk? */
tree cap = value_member (decl, LAMBDA_EXPR_CAPTURE_LIST (lam));
tree type;
if (cap)
type = TREE_TYPE (TREE_PURPOSE (cap));
else
switch (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam))
{
case CPLD_NONE:
error ("%qD is not captured", decl);
return error_mark_node;
case CPLD_COPY:
type = TREE_TYPE (decl);
if (TREE_CODE (type) == REFERENCE_TYPE
&& TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)
type = TREE_TYPE (type);
break;
case CPLD_REFERENCE:
type = TREE_TYPE (decl);
if (TREE_CODE (type) != REFERENCE_TYPE)
type = build_reference_type (TREE_TYPE (decl));
break;
default:
gcc_unreachable ();
}
if (TREE_CODE (type) != REFERENCE_TYPE)
{
if (!LAMBDA_EXPR_MUTABLE_P (lam))
type = cp_build_qualified_type (type, (TYPE_QUALS (type)
|TYPE_QUAL_CONST));
type = build_reference_type (type);
}
return type;
}
/* From an ID and INITIALIZER, create a capture (by reference if
BY_REFERENCE_P is true), add it to the capture-list for LAMBDA,
and return it. */
tree
add_capture (tree lambda, tree id, tree initializer, bool by_reference_p)
{
tree type;
tree member;
type = lambda_capture_field_type (initializer);
if (by_reference_p)
{
type = build_reference_type (type);
if (!real_lvalue_p (initializer))
error ("cannot capture %qE by reference", initializer);
}
/* Make member variable. */
member = build_lang_decl (FIELD_DECL, id, type);
/* Add it to the appropriate closure class. */
finish_member_declaration (member);
LAMBDA_EXPR_CAPTURE_LIST (lambda)
= tree_cons (member, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
if (id == get_identifier ("__this"))
{
if (LAMBDA_EXPR_CAPTURES_THIS_P (lambda))
error ("already captured %<this%> in lambda expression");
LAMBDA_EXPR_THIS_CAPTURE (lambda) = member;
}
return member;
}
/* Similar to add_capture, except this works on a stack of nested lambdas.
BY_REFERENCE_P in this case is derived from the default capture mode.
Returns the capture for the lambda at the bottom of the stack. */
tree
add_default_capture (tree lambda_stack, tree id, tree initializer)
{
bool this_capture_p = (id == get_identifier ("__this"));
tree member = NULL_TREE;
tree saved_class_type = current_class_type;
tree node;
for (node = lambda_stack;
node;
node = TREE_CHAIN (node))
{
tree lambda = TREE_VALUE (node);
current_class_type = TREE_TYPE (lambda);
member = add_capture (lambda,
id,
initializer,
/*by_reference_p=*/
(!this_capture_p
&& (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda)
== CPLD_REFERENCE)));
{
/* Have to get the old value of current_class_ref. */
tree object = cp_build_indirect_ref (DECL_ARGUMENTS
(lambda_function (lambda)),
/*errorstring=*/"",
/*complain=*/tf_warning_or_error);
initializer = finish_non_static_data_member
(member, object, /*qualifying_scope=*/NULL_TREE);
}
}
current_class_type = saved_class_type;
return member;
}
/* Return the capture pertaining to a use of 'this' in LAMBDA, in the form of an
INDIRECT_REF, possibly adding it through default capturing. */
tree
lambda_expr_this_capture (tree lambda)
{
tree result;
tree this_capture = LAMBDA_EXPR_THIS_CAPTURE (lambda);
/* Try to default capture 'this' if we can. */
if (!this_capture
&& LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE)
{
tree containing_function = TYPE_CONTEXT (TREE_TYPE (lambda));
tree lambda_stack = tree_cons (NULL_TREE, lambda, NULL_TREE);
/* If we are in a lambda function, we can move out until we hit:
1. a non-lambda function,
2. a lambda function capturing 'this', or
3. a non-default capturing lambda function. */
while (LAMBDA_FUNCTION_P (containing_function))
{
tree lambda
= CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (containing_function));
if (LAMBDA_EXPR_THIS_CAPTURE (lambda)
|| LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) == CPLD_NONE)
break;
lambda_stack = tree_cons (NULL_TREE,
lambda,
lambda_stack);
containing_function = decl_function_context (containing_function);
}
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (containing_function))
{
this_capture = add_default_capture (lambda_stack,
/*id=*/get_identifier ("__this"),
/* First parameter is 'this'. */
/*initializer=*/DECL_ARGUMENTS
(containing_function));
}
}
if (!this_capture)
{
error ("%<this%> was not captured for this lambda function");
result = error_mark_node;
}
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));
result = finish_non_static_data_member (this_capture,
current_class_ref,
/*qualifying_scope=*/NULL_TREE);
/* If 'this' is captured, each use of 'this' is transformed into an
access to the corresponding unnamed data member of the closure
type cast (_expr.cast_ 5.4) to the type of 'this'. [ The cast
ensures that the transformed expression is an rvalue. ] */
result = rvalue (result);
}
return result;
}
#include "gt-cp-semantics.h" #include "gt-cp-semantics.h"

View File

@ -456,6 +456,22 @@ build_cplus_new (tree type, tree init)
return rval; return rval;
} }
/* Return a TARGET_EXPR which expresses the direct-initialization of one
array from another. */
tree
build_array_copy (tree init)
{
tree type = TREE_TYPE (init);
tree slot = build_local_temp (type);
init = build2 (VEC_INIT_EXPR, type, slot, init);
SET_EXPR_LOCATION (init, input_location);
init = build_target_expr (slot, init);
TARGET_EXPR_IMPLICIT_P (init) = 1;
return init;
}
/* Build a TARGET_EXPR using INIT to initialize a new temporary of the /* Build a TARGET_EXPR using INIT to initialize a new temporary of the
indicated TYPE. */ indicated TYPE. */
@ -726,6 +742,17 @@ cp_build_reference_type (tree to_type, bool rval)
} }
/* Returns EXPR cast to rvalue reference type, like std::move. */
tree
move (tree expr)
{
tree type = TREE_TYPE (expr);
gcc_assert (TREE_CODE (type) != REFERENCE_TYPE);
type = cp_build_reference_type (type, /*rval*/true);
return build_static_cast (type, expr, tf_warning_or_error);
}
/* Used by the C++ front end to build qualified array types. However, /* Used by the C++ front end to build qualified array types. However,
the C version of this function does not properly maintain canonical the C version of this function does not properly maintain canonical
types (which are not used in C). */ types (which are not used in C). */
@ -1558,6 +1585,8 @@ no_linkage_check (tree t, bool relaxed_p)
namespace scope. This doesn't have a core issue number yet. */ namespace scope. This doesn't have a core issue number yet. */
if (TYPE_ANONYMOUS_P (t) && TYPE_NAMESPACE_SCOPE_P (t)) if (TYPE_ANONYMOUS_P (t) && TYPE_NAMESPACE_SCOPE_P (t))
return t; return t;
if (no_linkage_lambda_type_p (t))
return t;
r = CP_TYPE_CONTEXT (t); r = CP_TYPE_CONTEXT (t);
if (TYPE_P (r)) if (TYPE_P (r))
@ -2759,6 +2788,8 @@ special_function_p (const_tree decl)
DECL_LANG_SPECIFIC. */ DECL_LANG_SPECIFIC. */
if (DECL_COPY_CONSTRUCTOR_P (decl)) if (DECL_COPY_CONSTRUCTOR_P (decl))
return sfk_copy_constructor; return sfk_copy_constructor;
if (DECL_MOVE_CONSTRUCTOR_P (decl))
return sfk_move_constructor;
if (DECL_CONSTRUCTOR_P (decl)) if (DECL_CONSTRUCTOR_P (decl))
return sfk_constructor; return sfk_constructor;
if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR) if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)

View File

@ -1161,6 +1161,10 @@ structural_comptypes (tree t1, tree t2, int strict)
case DECLTYPE_TYPE: case DECLTYPE_TYPE:
if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1) if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
!= DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2) != DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2)
|| (DECLTYPE_FOR_LAMBDA_CAPTURE (t1)
!= DECLTYPE_FOR_LAMBDA_CAPTURE (t2))
|| (DECLTYPE_FOR_LAMBDA_RETURN (t1)
!= DECLTYPE_FOR_LAMBDA_RETURN (t2))
|| !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1),
DECLTYPE_TYPE_EXPR (t2))) DECLTYPE_TYPE_EXPR (t2)))
return false; return false;
@ -7001,6 +7005,31 @@ check_return_expr (tree retval, bool *no_warning)
return NULL_TREE; return NULL_TREE;
} }
/* As an extension, deduce lambda return type from a return statement
anywhere in the body. */
if (retval && LAMBDA_FUNCTION_P (current_function_decl))
{
tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type);
if (LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda))
{
tree type = lambda_return_type (retval);
tree oldtype = LAMBDA_EXPR_RETURN_TYPE (lambda);
if (VOID_TYPE_P (type))
{ /* Nothing. */ }
else if (oldtype == NULL_TREE)
{
pedwarn (input_location, OPT_pedantic, "lambda return type "
"can only be deduced when the return statement is "
"the only statement in the function body");
apply_lambda_return_type (lambda, type);
}
else if (!same_type_p (type, oldtype))
error ("inconsistent types %qT and %qT deduced for "
"lambda return type", type, oldtype);
}
}
if (processing_template_decl) if (processing_template_decl)
{ {
current_function_returns_value = 1; current_function_returns_value = 1;

View File

@ -838,6 +838,12 @@ digest_init_r (tree type, tree init, bool nested, int flags)
if (TREE_CODE (type) == ARRAY_TYPE if (TREE_CODE (type) == ARRAY_TYPE
&& TREE_CODE (init) != CONSTRUCTOR) && TREE_CODE (init) != CONSTRUCTOR)
{ {
/* Allow the result of build_array_copy. */
if (TREE_CODE (init) == TARGET_EXPR
&& (same_type_ignoring_top_level_qualifiers_p
(type, TREE_TYPE (init))))
return init;
error ("array must be initialized with a brace-enclosed" error ("array must be initialized with a brace-enclosed"
" initializer"); " initializer");
return error_mark_node; return error_mark_node;

View File

@ -1,3 +1,46 @@
2009-09-29 John Freeman <jfreeman08@gmail.com>
Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/lambda/lambda-array.C: New.
* g++.dg/cpp0x/lambda/lambda-capture-const-ref.C: New.
* g++.dg/cpp0x/lambda/lambda-capture-const-ref-neg.C: New.
* g++.dg/cpp0x/lambda/lambda-const.C: New.
* g++.dg/cpp0x/lambda/lambda-copy-default-neg.C: New.
* g++.dg/cpp0x/lambda/lambda-copy-default.C: New.
* g++.dg/cpp0x/lambda/lambda-copy-neg.C: New.
* g++.dg/cpp0x/lambda/lambda-copy.C: New.
* g++.dg/cpp0x/lambda/lambda-ctor-neg.C: New.
* g++.dg/cpp0x/lambda/lambda-ctors.C: New.
* g++.dg/cpp0x/lambda/lambda-deduce-ext-neg.C: New.
* g++.dg/cpp0x/lambda/lambda-deduce-ext-neg2.C: New.
* g++.dg/cpp0x/lambda/lambda-deduce-ext.C: New.
* g++.dg/cpp0x/lambda/lambda-deduce-neg.C: New.
* g++.dg/cpp0x/lambda/lambda-deduce.C: New.
* g++.dg/cpp0x/lambda/lambda-defarg.C: New.
* g++.dg/cpp0x/lambda/lambda-eh.C: New.
* g++.dg/cpp0x/lambda/lambda-errloc.C: New.
* g++.dg/cpp0x/lambda/lambda-field-names.C: New.
* g++.dg/cpp0x/lambda/lambda-in-class-neg.C: New.
* g++.dg/cpp0x/lambda/lambda-in-class.C: New.
* g++.dg/cpp0x/lambda/lambda-lookup-neg.C: New.
* g++.dg/cpp0x/lambda/lambda-mangle.C: New.
* g++.dg/cpp0x/lambda/lambda-mixed.C: New.
* g++.dg/cpp0x/lambda/lambda-mutable.C: New.
* g++.dg/cpp0x/lambda/lambda-nested.C: New.
* g++.dg/cpp0x/lambda/lambda-non-const.C: New.
* g++.dg/cpp0x/lambda/lambda-nop.C: New.
* g++.dg/cpp0x/lambda/lambda-ns-scope.C: New.
* g++.dg/cpp0x/lambda/lambda-pass.C: New.
* g++.dg/cpp0x/lambda/lambda-recursive.C: New.
* g++.dg/cpp0x/lambda/lambda-ref-default.C: New.
* g++.dg/cpp0x/lambda/lambda-ref.C: New.
* g++.dg/cpp0x/lambda/lambda-std-function.C: New.
* g++.dg/cpp0x/lambda/lambda-template.C: New.
* g++.dg/cpp0x/lambda/lambda-this.C: New.
* g++.dg/cpp0x/lambda/lambda-type.C: New.
* g++.dg/cpp0x/lambda/lambda-use.C: New.
* lib/prune.exp: Accept "In lambda function".
2009-09-29 Harsha Jagasia <harsha.jagasia@amd.com> 2009-09-29 Harsha Jagasia <harsha.jagasia@amd.com>
* gcc.target/i386/fma4-check.h * gcc.target/i386/fma4-check.h

View File

@ -0,0 +1,20 @@
// Test that array capture by copy works.
// { dg-options -std=c++0x }
// { dg-do run }
struct A
{
int i;
A(int i): i(i) {}
A(const A& a): i(a.i+1) {}
};
int main()
{
A ar[4][3] = { { 10, 20, 30 },
{ 40, 50, 60 },
{ 70, 80, 90 },
{ 100, 110, 120 } };
int i = [ar] { return ar[1][1]; }().i;
return (i!= 52);
}

View File

@ -0,0 +1,14 @@
// { dg-options "-std=c++0x" }
#include <cassert>
int main() {
int i = 1, j = 2;
const int& ci = i;
[&ci, &j] () -> void { j = ci; } ();
assert(i == 1);
assert(j == 1);
[&ci] () -> void { ci = 0; } (); // { dg-error "" "cannot assign to const int&" }
return 0;
}

View File

@ -0,0 +1,15 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
#include <cassert>
int main() {
int i = 1, j = 2;
const int& ci = i;
[&ci, &j] () -> void { j = ci; } ();
assert(i == 1);
assert(j == 1);
//[&ci] () -> void { ci = 0; } (); { dg-error: cannot assign to const int& }
return 0;
}

View File

@ -0,0 +1,19 @@
// { dg-options "-std=c++0x" }
#include <cassert>
template<typename F>
void call(const F& f) { f(); } // { dg-error "discards qualifiers" }
int main() {
call([] () -> void {});
call([] () mutable -> void {}); // { dg-message "" "`f' does not have const `operator()'" }
int i = -1;
call([&i] () -> void { i = 0; });
assert(i == 0);
call([i] () -> void { i = 0; }); // { dg-error "" "assignment to non-reference capture in const lambda" }
return 0;
}

View File

@ -0,0 +1,20 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
#include <cassert>
template<typename F>
void call(const F& f) { f(); }
int main() {
call([] () -> void {});
//call([] () mutable -> void {}); // { dg-error: "`f' does not have const `operator()'" }
int i = -1;
call([&i] () -> void { i = 0; });
assert(i == 0);
//call([i] () -> void { i = 0; }); // { dg-error: "assignment to non-reference capture in const lambda" }
return 0;
}

View File

@ -0,0 +1,13 @@
// { dg-options "-std=c++0x" }
int main() {
int i;
const char* s;
[=] () -> void { i; s; i; s; } ();
[] () -> void { i; } (); // { dg-error "" "`i' is not captured" }
[1] () -> void {} (); // { dg-error "expected identifier" }
return 0;
}

View File

@ -0,0 +1,14 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
int main() {
int i;
const char* s;
[=] () -> void { i; s; i; s; } ();
//[] () -> void { i; } (); // { dg-error: "`i' is not in scope" }
//[1] () -> void {} (); // { dg-error: "expected identifier" }
return 0;
}

View File

@ -0,0 +1,13 @@
// { dg-options "-std=c++0x" }
int main() {
int i;
const char* s;
[i, s] () -> void { i; s; } ();
[] () -> void { i; } (); // { dg-error "" "`i' is not captured" }
[1] () -> void {} (); // { dg-error "expected identifier" }
return 0;
}

View File

@ -0,0 +1,14 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
int main() {
int i;
const char* s;
[i, s] () -> void { i; s; } ();
//[] () -> void { i; } (); // { dg-error: "`i' is not in scope" }
//[1] () -> void {} (); // { dg-error: "expected identifier" }
return 0;
}

View File

@ -0,0 +1,25 @@
// { dg-options -std=c++0x }
void f()
{
int i;
auto lam = [i]{}; // { dg-message "note" }
decltype(lam) lam2 = { 1 }; // { dg-error "" "not an aggregate" }
decltype(lam) lam3; // { dg-error "" "deleted default ctor" }
lam3 = lam; // { dg-error "" "deleted assignment op" }
}
template <class T>
void g(T i)
{
auto lam = [i]{}; // { dg-message "note" }
decltype(lam) lam2 = { 1 }; // { dg-error "" "not an aggregate" }
decltype(lam) lam3; // { dg-error "" "deleted default ctor" }
lam3 = lam; // { dg-error "" "deleted assignment op" }
}
int main()
{
f();
g(1);
}

View File

@ -0,0 +1,18 @@
// { dg-options -std=c++0x }
// { dg-do run }
struct A
{
A() { }
A(A&) { }
A(A&&) { }
};
int main()
{
A a;
auto lam4 = [a]{}; // OK, implicit move ctor
lam4();
auto lam5 = lam4; // OK, implicit copy ctor
lam5();
}

View File

@ -0,0 +1,24 @@
// Testcase for an extension to allow return type deduction when the lambda
// contains more than just a single return-statement.
// { dg-options -std=c++0x }
bool b;
template <class T>
T f (T t)
{
return [=]
{
auto i = t+1;
if (b)
return i+1;
else
return i+2; // { dg-error "lambda return type" }
}();
}
int main()
{
if (f(1) != 3)
return 1;
}

View File

@ -0,0 +1,22 @@
// Test that in pedantic mode, we warn about the extension to allow return
// type deduction when the lambda contains more than just a single
// return-statement.
// { dg-options "-std=c++0x -pedantic" }
bool b;
template <class T>
T f (T t)
{
[=] { return t+1; }; // OK
return [=] {
auto i = t+1;
return i+1; // { dg-warning "only statement" }
}();
}
int main()
{
if (f(1) != 3)
return 1;
}

View File

@ -0,0 +1,27 @@
// Testcase for an extension to allow return type deduction when the lambda
// contains more than just a single return-statement.
// { dg-options -std=c++0x }
// { dg-do run }
bool b;
template <class T>
T f (T t)
{
return [=] {
auto i = t+1;
if (b)
return i+1;
else
return i+1;
}();
}
int main()
{
// Pointless, but well-formed.
[] { return 1; return 2; }();
if (f(1) != 3)
return 1;
}

View File

@ -0,0 +1,10 @@
// { dg-options "-std=c++0x" }
#include <cassert>
int main() {
int i = 0;
int& r = [&] () { return i; } (); // { dg-error "" "invalid initialization of non-const reference of type int& from a temporary of type int" }
return 0;
}

View File

@ -0,0 +1,29 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
#include <cassert>
int main() {
[] {};
[] {} ();
[] () {};
[] () {} ();
[] () { return "lambda"; };
int i = 1, j = 2;
[&i, j] () { i = j; } ();
assert(i == 2);
assert(j == 2);
i = [] () { return 3; } ();
assert(i == 3);
int k = [&] () { return i; } ();
[]{ return; };
int array[] = { 1, 2, 3 };
int* p = [&] () { return array; } ();
return 0;
}

View File

@ -0,0 +1,6 @@
// { dg-options "-std=c++0x -pedantic-errors" }
int main()
{
[](int a = 1) { return a; }(); // { dg-error "" }
}

View File

@ -0,0 +1,35 @@
// Test that we properly clean up if we get an exception in the middle of
// constructing the closure object.
// { dg-options -std=c++0x }
// This test fails because of PR 41449; it isn't a lambda issue.
// { dg-do run { xfail *-*-* } }
struct A
{
A() {}
A(const A&) { throw 1; }
};
int bs;
struct B
{
B() { ++bs; }
B(const B&) { ++bs; }
~B() { --bs; }
};
int main()
{
{
B b1, b2;
A a;
try
{
[b1, a, b2]{ };
}
catch(...) {}
}
return bs;
}

View File

@ -0,0 +1,18 @@
// Test that error messages about creating the closure object refer to
// the lambda-introducer.
// { dg-options -std=c++0x }
struct A
{
A();
A(const A& a) = delete; // { dg-error "deleted" }
};
int main()
{
A ar[4][3];
[ar] { }; // { dg-error "3:" }
A a;
[a] { }; // { dg-error "3:" }
}

View File

@ -0,0 +1,21 @@
// "For each entity captured by copy, an unnamed non-static data member is
// declared in the closure type" -- test that there isn't a member of the
// closure with the same name as the captured variable.
// { dg-options -std=c++0x }
template <class T>
struct A: public T
{
A(T t): T(t) { }
int f() { return this->i; } // { dg-error "" "no member named i" }
};
int main()
{
int i = 42;
auto lam = [i]{ };
lam.i = 24; // { dg-error "" "no member named i" }
A<decltype(lam)> a(lam);
return a.f();
}

View File

@ -0,0 +1,35 @@
// { dg-options "-std=c++0x" }
#include <cassert>
class C {
private:
int m_i;
public:
C() : m_i(-1) {
[] { this; } (); // { dg-error "not captured" }
[this] () -> void { m_i = 0; } ();
assert(m_i == 0);
[this] () -> void { this->m_i = 1; } ();
assert(m_i == 1);
[&] () -> void { m_i = 2; } ();
assert(m_i == 2);
[&] () -> void { this->m_i = 3; } ();
assert(m_i == 3);
[=] () -> void { m_i = 4; } (); // copies 'this' or --copies-m_i--?
assert(m_i == 4);
[=] () -> void { this->m_i = 5; } ();
assert(m_i == 5);
}
};
int main() {
C c;
[this] () -> void {} (); // { dg-error "use of 'this' in non-member function" }
return 0;
}

View File

@ -0,0 +1,36 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
#include <cassert>
class C {
private:
int m_i;
public:
C() : m_i(-1) {
//[] { this; } ();
[this] () -> void { m_i = 0; } ();
assert(m_i == 0);
[this] () -> void { this->m_i = 1; } ();
assert(m_i == 1);
[&] () -> void { m_i = 2; } ();
assert(m_i == 2);
[&] () -> void { this->m_i = 3; } ();
assert(m_i == 3);
[=] () -> void { m_i = 4; } (); // copies 'this' or --copies-m_i--?
assert(m_i == 4);
[=] () -> void { this->m_i = 5; } ();
assert(m_i == 5);
}
};
int main() {
C c;
//[this] () -> void {} (); // { dg-error: "cannot capture `this' outside of class method" }
return 0;
}

View File

@ -0,0 +1,7 @@
// Test that we don't crash on a failed lookup.
// { dg-options -std=c++0x }
int main()
{
[i]{}; // { dg-error "not declared" }
}

View File

@ -0,0 +1,102 @@
// Test lambda mangling
// { dg-options "-std=c++0x -fno-inline" }
template<typename F> int algo(F fn) { return fn(); }
inline void g(int n) {
int bef(int i = []{ return 1; }());
// Default arguments of block-extern function declarations
// remain in the context of the encloding function body.
// The closure type is encoded as Z1giEUlvE_.
// The call operator of that type is _ZZ1giENKUlvE_clEv.
// { dg-final { scan-assembler "_ZZ1giENKUlvE_clEv" } }
// { dg-final { scan-assembler "weak\[ \t\]*_?_ZZ1giENKUlvE_clEv" { target { ! { *-*-darwin* } } } } }
algo([=]{return n+bef();});
// The captured entities do not participate in <lambda-sig>
// and so this closure type has the same <lambda-sig> as
// the previous one. It encoding is therefore Z1giEUlvE0_
// and the call operator is _ZZ1giENKUlvE0_clEv. The
// instance of "algo" being called is then
// _Z4algoIZ1giEUlvE0_EiT_.
// { dg-final { scan-assembler "_Z4algoIZ1giEUlvE0_EiT_" } }
// { dg-final { scan-assembler "_ZZ1giENKUlvE0_clEv" } }
int i = []{return 1;}();
}
struct S {
void f(int =
// Type: ZN1S1fEiiEd0_UlvE_
// Operator: _ZZN1S1fEiiEd0_NKUlvE_clEv
// { dg-final { scan-assembler "_ZZN1S1fEiiEd0_NKUlvE_clEv" } }
// { dg-final { scan-assembler "weak\[ \t\]*_?_ZZN1S1fEiiEd0_NKUlvE_clEv" { target { ! { *-*-darwin* } } } } }
[]{return 1;}()
// Type: ZN1S1fEiiEd0_UlvE0_
// Operator: _ZZN1S1fEiiEd0_NKUlvE0_clEv
// { dg-final { scan-assembler "_ZZN1S1fEiiEd0_NKUlvE0_clEv" } }
+ []{return 2;}(),
int =
// Type: ZN1S1fEiiEd_UlvE_
// Operator: _ZZN1S1fEiiEd_NKUlvE_clEv
// { dg-final { scan-assembler "_ZZN1S1fEiiEd_NKUlvE_clEv" } }
[]{return 3;}());
};
template<typename T> struct R {
static int x;
};
template<typename T> int R<T>::x = []{return 1;}();
template int R<int>::x;
// Type of lambda in intializer of R<int>::x: N1RIiE1xMUlvE_E
// Corresponding operator(): _ZNK1RIiE1xMUlvE_clEv
// { dg-final { scan-assembler "_ZNK1RIiE1xMUlvE_clEv" } }
// { dg-final { scan-assembler "weak\[ \t\]*_?_ZNK1RIiE1xMUlvE_clEv" } }
void bar()
{
// lambdas in non-vague linkage functions have internal linkage.
// { dg-final { scan-assembler-not "weak\[^\n\r\]*bar\[^\n\r\]*Ul" } }
[]{}();
}
// lambdas used in non-template, non-class body initializers are internal.
// { dg-final { scan-assembler-not "weak\[^\n\r\]*_ZNKUlv" } }
// { dg-final { scan-assembler-not "weak\[^\n\r\]*variable" } }
int variable = []{return 1;}();
// And a template instantiated with such a lambda is also internal.
// { dg-final { scan-assembler-not "weak\[^\n\r\]*algoIUl" } }
int var2 = algo([]{return 1;});
// As are lambdas used in non-class-body default arguments.
// { dg-final { scan-assembler-not "weak\[^\n\r\]*function" } }
void function (int i = []{return 1;}()+[]{return 1;}());
struct Foo
{
static int Int;
void Bar(int);
};
int Foo::Int = []{return 1;}();
// Even default arguments for member functions that appear outside the
// class body are internal.
// { dg-final { scan-assembler-not "weak\[^\n\r\]*Foo" } }
void Foo::Bar(int i = []{return 1;}()) {}
// Even default arguments for function templates.
// { dg-final { scan-assembler-not "weak\[^\n\r\]*fn2\[^\n\r\]*Ulv" } }
template <class T>
void fn2 (T t = []{return 1;}()) {}
int main()
{
g(42);
S().f();
function();
Foo().Bar();
fn2<int>();
}

View File

@ -0,0 +1,13 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
#include <cassert>
int main() {
int i = 1, j = 2;
[&i, j] () mutable -> void { i = 0; j = 0; } ();
assert(i == 0);
assert(j == 2);
return 0;
}

View File

@ -0,0 +1,16 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
#include <cassert>
int main() {
int i = 1;
const char* s1 = "hello";
const char* s2 = s1;
[i, s2] () mutable -> void { i = 2; s2 = "world"; } ();
//[i, s2] () -> void { i = 2; s2 = "world"; } (); // { dg-error: "assignment of data-member in read-only structure" }
assert(i == 1);
assert(s1 == s2);
return 0;
}

View File

@ -0,0 +1,52 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
#include <cassert>
int main() {
int i = 1;
[] (int& i) -> void {
[&] () -> void {
i = 2;
} ();
} (i);
assert(i == 2);
[&] () -> void {
[&i] () -> void {
i = 3;
} ();
} ();
assert(i == 3);
[&] () -> void {
[&] () -> void {
i = 4;
} ();
} ();
assert(i == 4);
i = 4;
[&] () -> void {
[=] () mutable -> void {
i = 5;
} ();
} ();
assert(i == 4);
[=] () mutable -> void {
[&] () -> void {
i = 6;
} ();
} ();
assert(i == 4);
return 0;
}

View File

@ -0,0 +1,19 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
#include <cassert>
template<typename F>
void call(F f) { f(); }
int main() {
call([] () -> void {});
call([] () mutable -> void {});
int i = -1;
call([i] () mutable -> void { i = 0; });
assert(i == -1);
return 0;
}

View File

@ -0,0 +1,19 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
#include <cassert>
int main() {
int i = 1, j = 2;
[i, j] () -> void {} ();
assert(i == 1);
assert(j == 2);
[&i, &j] () -> void {} ();
assert(i == 1);
assert(j == 2);
[] (int x) -> void {} (1);
[] (int& x) -> void {} (i);
[] (int x, int y) -> void {} (i, j);
return 0;
}

View File

@ -0,0 +1,18 @@
// { dg-options -std=c++0x }
// { dg-do run }
auto f = [](int i) { return i+1; };
int g(int i = [] { return 237; }())
{
return i;
}
int main()
{
if (f(41) != 42)
return 1;
if (g() != 237)
return 2;
return 0;
}

View File

@ -0,0 +1,27 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
#include <cassert>
#include <algorithm>
template <typename F, typename A1>
void call(F f, const A1& arg1) {
f(arg1);
}
int main() {
int i = 1;
call(
[&i] (int j) -> void { i = j; },
2
);
assert(i == 2);
int A[] = {1, 2, 3, 4};
int sum = 0;
std::for_each(A, A+4, [&sum] (int n) -> void { sum += n; });
assert(sum == 10);
return 0;
}

View File

@ -0,0 +1,21 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
//#include <iostream>
#include <functional>
#include <cassert>
int main() {
std::function<int(int)> fib = [&fib] (int n) -> int {
//std::cerr << "fib(" << n << ")\n";
if (n <= 2) return 1;
else return fib(n-1) + fib(n-2);
};
assert(fib(5) == 5);
assert(fib(10) == 55);
return 0;
}

View File

@ -0,0 +1,15 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
#include <cassert>
int main() {
int i = 1;
float j = 2.0;
[&] () -> void { i = 3; j = 4.0; } ();
assert(i == 3);
assert(j == 4.0);
return 0;
}

View File

@ -0,0 +1,15 @@
// { dg-do "run" }
// { dg-options "-std=c++0x" }
#include <cassert>
int main() {
int i = 1;
float j = 2.0;
[&i, &j] () -> void { i = 3; j = 4.0; } ();
assert(i == 3);
assert(j == 4.0);
return 0;
}

View File

@ -0,0 +1,22 @@
// Test using std::function wrapper.
// { dg-do run }
// { dg-options -std=c++0x }
#include <functional>
typedef std::function<int()> FN;
template<typename T>
FN f(T fn)
{
return [fn]{return fn(2);};
}
int main()
{
auto fn = f([](int i){return i*21;});
if (fn() != 42)
return 1;
return 0;
}

View File

@ -0,0 +1,41 @@
// { dg-options -std=c++0x }
// { dg-do run }
extern "C" void abort();
template <class T>
auto apply (T t) -> decltype (t())
{
return t();
}
template <class T>
T f(T t)
{
T t2 = t;
if (t != [=]()->T { return t; }())
abort ();
if (t != [=] { return t; }())
abort ();
if (t != [=] { return t2; }())
abort ();
if (t != [&] { return t; }())
abort ();
if (t != apply([=]{return t;}))
abort ();
int i;
[&] (int a) { return a+i+t; } (0);
[&] (int a) -> decltype(a) { return a+i+t; } (0);
[&] (int a) -> decltype(i) { return a+i+t; } (0);
[&] (int a) -> decltype(t) { return a+i+t; } (0);
[&] (int a) -> decltype(a+i) { return a+i+t; } (0);
[&] (int a) -> decltype(a+t) { return a+i+t; } (0);
[&] (int a) -> decltype(i+t) { return a+i+t; } (0);
[&] (int a) -> decltype(a+i+t) { return a+i+t; } (0);
}
int main()
{
f(0xbeef);
}

View File

@ -0,0 +1,13 @@
// Test that implicit 'this' capture works, but that it's still an rvalue.
// { dg-options -std=c++0x }
struct A
{
int i;
void f()
{
[=] { i = 0; };
[&] { i = 0; };
[=] { this = 0; }; // { dg-error "lvalue" }
}
};

View File

@ -0,0 +1,74 @@
// Every id-expression that is a use (_basic.def.odr_ 3.2) of an entity
// captured by copy is transformed into an access to the corresponding
// unnamed data member of the closure type.
//...
// Every occurrence of decltype((x)) where x is a possibly parenthesized
// id-expression that names an entity of automatic storage duration is
// treated as if x were transformed into an access to a corresponding data
// member of the closure type that would have been declared if x were a use
// of the denoted entity.
// So, other appearances of 'x' within decltype do not refer to the closure
// member, because they are not "use"s in the sense of 3.2.
// { dg-options -std=c++0x }
template<class T, class U>
struct same_type;
template <class T>
struct same_type<T,T> { };
int main()
{
int i;
[=] {
same_type<decltype(i),int>();
same_type<decltype((i)),int const&>();
i+1;
same_type<decltype((i)),int const&>();
same_type<decltype(i),int>();
};
[=] {
same_type<decltype(i),int>();
same_type<decltype((i)),int const&>();
same_type<decltype(i),int>();
};
[=] () mutable {
same_type<decltype(i),int>();
same_type<decltype((i)),int &>();
same_type<decltype(i),int>();
};
[&] {
same_type<decltype(i),int>();
same_type<decltype((i)),int &>();
same_type<decltype(i),int>();
};
[i] {
same_type<decltype(i),int>();
same_type<decltype((i)),int const&>();
};
[&,i] {
same_type<decltype(i),int>();
same_type<decltype((i)),int const&>();
};
[i] () mutable {
same_type<decltype(i),int>();
same_type<decltype((i)),int &>();
};
[&,i] () mutable {
same_type<decltype(i),int>();
same_type<decltype((i)),int &>();
};
[&i] {
same_type<decltype(i),int>();
same_type<decltype((i)),int &>();
};
[=,&i] {
same_type<decltype(i),int>();
same_type<decltype((i)),int &>();
};
[] {
same_type<decltype(i),int>();
same_type<decltype((i)),int const&>(); // { dg-error "" "not captured" }
};
}

View File

@ -0,0 +1,12 @@
// { dg-options -std=c++0x }
int main(int argc, char** argv)
{
int i;
int &ir = i;
const int ci = 0;
const int &cir = ci;
[] { sizeof (argc); sizeof (i); sizeof (ir); sizeof (ci); sizeof (cir); };
[] { int ia[ci]; };
}

View File

@ -20,7 +20,7 @@
proc prune_gcc_output { text } { proc prune_gcc_output { text } {
#send_user "Before:$text\n" #send_user "Before:$text\n"
regsub -all "(^|\n)(\[^\n\]*: )?In ((static member )?function|member|method|(copy )?constructor|destructor|instantiation|program|subroutine|block-data) \[^\n\]*" $text "" text regsub -all "(^|\n)(\[^\n\]*: )?In ((static member |lambda )?function|member|method|(copy )?constructor|destructor|instantiation|program|subroutine|block-data)\[^\n\]*" $text "" text
regsub -all "(^|\n)\[^\n\]*(: )?At (top level|global scope):\[^\n\]*" $text "" text regsub -all "(^|\n)\[^\n\]*(: )?At (top level|global scope):\[^\n\]*" $text "" text
regsub -all "(^|\n)\[^\n\]*: instantiated from \[^\n\]*" $text "" text regsub -all "(^|\n)\[^\n\]*: instantiated from \[^\n\]*" $text "" text
regsub -all "(^|\n) inlined from \[^\n\]*" $text "" text regsub -all "(^|\n) inlined from \[^\n\]*" $text "" text

6
include/ChangeLog.lambda Normal file
View File

@ -0,0 +1,6 @@
2009-09-29 Jason Merrill <jason@redhat.com>
* demangle.h (enum demangle_component_type): Add
DEMANGLE_COMPONENT_LAMBDA, DEMANGLE_COMPONENT_DEFAULT_ARG,
DEMANGLE_COMPONENT_UNNAMED_TYPE.
(struct demangle_component): Add s_unary_num.

View File

@ -381,6 +381,12 @@ enum demangle_component_type
DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS, DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS,
/* Global destructors keyed to name. */ /* Global destructors keyed to name. */
DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS, DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS,
/* A lambda closure type. */
DEMANGLE_COMPONENT_LAMBDA,
/* A default argument scope. */
DEMANGLE_COMPONENT_DEFAULT_ARG,
/* An unnamed type. */
DEMANGLE_COMPONENT_UNNAMED_TYPE,
/* A pack expansion. */ /* A pack expansion. */
DEMANGLE_COMPONENT_PACK_EXPANSION DEMANGLE_COMPONENT_PACK_EXPANSION
}; };
@ -494,6 +500,14 @@ struct demangle_component
struct demangle_component *right; struct demangle_component *right;
} s_binary; } s_binary;
struct
{
/* subtree, same place as d_left. */
struct demangle_component *sub;
/* integer. */
int num;
} s_unary_num;
} u; } u;
}; };

View File

@ -1,3 +1,14 @@
2009-09-29 Jason Merrill <jason@redhat.com>
* Makefile.in: Enable demangle target.
* cp-demangle.c (d_lambda, d_unnamed_type, d_make_default_arg): New.
(d_name, d_prefix, d_unqualified_name, d_local_name): Handle lambdas.
(d_parmlist): Factor out from d_bare_function_type.
(d_compact_number): Factor out from d_template_param and d_expression.
(d_append_num): Factor out from d_print_comp.
(d_print_comp, d_print_mod_list): Handle lambdas.
* testsuite/demangle-expected: Add lambda tests.
2009-09-23 Matthew Gingell <gingell@adacore.com> 2009-09-23 Matthew Gingell <gingell@adacore.com>
* cplus-dem.c (ada_demangle): Ensure demangled is freed. * cplus-dem.c (ada_demangle): Ensure demangled is freed.

View File

@ -371,10 +371,12 @@ TAGS: $(CFILES)
etags `for i in $(CFILES); do echo $(srcdir)/$$i ; done` etags `for i in $(CFILES); do echo $(srcdir)/$$i ; done`
# The standalone demangler (c++filt) has been moved to binutils. # The standalone demangler (c++filt) has been moved to binutils.
demangle: # But make this target work anyway for demangler hacking.
demangle: $(ALL) $(srcdir)/cp-demangle.c
@echo "The standalone demangler, now named c++filt, is now" @echo "The standalone demangler, now named c++filt, is now"
@echo "a part of binutils." @echo "a part of binutils."
@false $(CC) @DEFS@ $(CFLAGS) $(CPPFLAGS) -I. -I$(INCDIR) $(HDEFINES) \
$(srcdir)/cp-demangle.c -DSTANDALONE_DEMANGLER $(TARGETLIB) -o $@
ls: ls:
@echo Makefile $(CFILES) @echo Makefile $(CFILES)

View File

@ -408,6 +408,10 @@ static struct demangle_component *d_local_name (struct d_info *);
static int d_discriminator (struct d_info *); static int d_discriminator (struct d_info *);
static struct demangle_component *d_lambda (struct d_info *);
static struct demangle_component *d_unnamed_type (struct d_info *);
static int static int
d_add_substitution (struct d_info *, struct demangle_component *); d_add_substitution (struct d_info *, struct demangle_component *);
@ -922,6 +926,20 @@ d_make_extended_operator (struct d_info *di, int args,
return p; return p;
} }
static struct demangle_component *
d_make_default_arg (struct d_info *di, int num,
struct demangle_component *sub)
{
struct demangle_component *p = d_make_empty (di);
if (p)
{
p->type = DEMANGLE_COMPONENT_DEFAULT_ARG;
p->u.s_unary_num.num = num;
p->u.s_unary_num.sub = sub;
}
return p;
}
/* Add a new constructor component. */ /* Add a new constructor component. */
static struct demangle_component * static struct demangle_component *
@ -1153,8 +1171,9 @@ d_name (struct d_info *di)
return d_local_name (di); return d_local_name (di);
case 'L': case 'L':
case 'U':
return d_unqualified_name (di); return d_unqualified_name (di);
case 'S': case 'S':
{ {
int subst; int subst;
@ -1276,6 +1295,7 @@ d_prefix (struct d_info *di)
|| IS_LOWER (peek) || IS_LOWER (peek)
|| peek == 'C' || peek == 'C'
|| peek == 'D' || peek == 'D'
|| peek == 'U'
|| peek == 'L') || peek == 'L')
dc = d_unqualified_name (di); dc = d_unqualified_name (di);
else if (peek == 'S') else if (peek == 'S')
@ -1291,6 +1311,16 @@ d_prefix (struct d_info *di)
dc = d_template_param (di); dc = d_template_param (di);
else if (peek == 'E') else if (peek == 'E')
return ret; return ret;
else if (peek == 'M')
{
/* Initializer scope for a lambda. We don't need to represent
this; the normal code will just treat the variable as a type
scope, which gives appropriate output. */
if (ret == NULL)
return NULL;
d_advance (di, 1);
continue;
}
else else
return NULL; return NULL;
@ -1347,6 +1377,18 @@ d_unqualified_name (struct d_info *di)
return NULL; return NULL;
return ret; return ret;
} }
else if (peek == 'U')
{
switch (d_peek_next_char (di))
{
case 'l':
return d_lambda (di);
case 't':
return d_unnamed_type (di);
default:
return NULL;
}
}
else else
return NULL; return NULL;
} }
@ -2242,50 +2284,30 @@ d_function_type (struct d_info *di)
return ret; return ret;
} }
/* <bare-function-type> ::= [J]<type>+ */ /* <type>+ */
static struct demangle_component * static struct demangle_component *
d_bare_function_type (struct d_info *di, int has_return_type) d_parmlist (struct d_info *di)
{ {
struct demangle_component *return_type;
struct demangle_component *tl; struct demangle_component *tl;
struct demangle_component **ptl; struct demangle_component **ptl;
char peek;
/* Detect special qualifier indicating that the first argument
is the return type. */
peek = d_peek_char (di);
if (peek == 'J')
{
d_advance (di, 1);
has_return_type = 1;
}
return_type = NULL;
tl = NULL; tl = NULL;
ptl = &tl; ptl = &tl;
while (1) while (1)
{ {
struct demangle_component *type; struct demangle_component *type;
peek = d_peek_char (di); char peek = d_peek_char (di);
if (peek == '\0' || peek == 'E') if (peek == '\0' || peek == 'E')
break; break;
type = cplus_demangle_type (di); type = cplus_demangle_type (di);
if (type == NULL) if (type == NULL)
return NULL; return NULL;
if (has_return_type) *ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL);
{ if (*ptl == NULL)
return_type = type; return NULL;
has_return_type = 0; ptl = &d_right (*ptl);
}
else
{
*ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL);
if (*ptl == NULL)
return NULL;
ptl = &d_right (*ptl);
}
} }
/* There should be at least one parameter type besides the optional /* There should be at least one parameter type besides the optional
@ -2300,10 +2322,45 @@ d_bare_function_type (struct d_info *di, int has_return_type)
&& d_left (tl)->u.s_builtin.type->print == D_PRINT_VOID) && d_left (tl)->u.s_builtin.type->print == D_PRINT_VOID)
{ {
di->expansion -= d_left (tl)->u.s_builtin.type->len; di->expansion -= d_left (tl)->u.s_builtin.type->len;
tl = NULL; d_left (tl) = NULL;
} }
return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE, return_type, tl); return tl;
}
/* <bare-function-type> ::= [J]<type>+ */
static struct demangle_component *
d_bare_function_type (struct d_info *di, int has_return_type)
{
struct demangle_component *return_type;
struct demangle_component *tl;
char peek;
/* Detect special qualifier indicating that the first argument
is the return type. */
peek = d_peek_char (di);
if (peek == 'J')
{
d_advance (di, 1);
has_return_type = 1;
}
if (has_return_type)
{
return_type = cplus_demangle_type (di);
if (return_type == NULL)
return NULL;
}
else
return_type = NULL;
tl = d_parmlist (di);
if (tl == NULL)
return NULL;
return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE,
return_type, tl);
} }
/* <class-enum-type> ::= <name> */ /* <class-enum-type> ::= <name> */
@ -2405,6 +2462,24 @@ d_pointer_to_member_type (struct d_info *di)
return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem); return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem);
} }
/* <non-negative number> _ */
static long
d_compact_number (struct d_info *di)
{
long num;
if (d_peek_char (di) == '_')
num = 0;
else if (d_peek_char (di) == 'n')
return -1;
else
num = d_number (di) + 1;
if (! d_check_char (di, '_'))
return -1;
return num;
}
/* <template-param> ::= T_ /* <template-param> ::= T_
::= T <(parameter-2 non-negative) number> _ ::= T <(parameter-2 non-negative) number> _
*/ */
@ -2417,17 +2492,8 @@ d_template_param (struct d_info *di)
if (! d_check_char (di, 'T')) if (! d_check_char (di, 'T'))
return NULL; return NULL;
if (d_peek_char (di) == '_') param = d_compact_number (di);
param = 0; if (param < 0)
else
{
param = d_number (di);
if (param < 0)
return NULL;
param += 1;
}
if (! d_check_char (di, '_'))
return NULL; return NULL;
++di->did_subs; ++di->did_subs;
@ -2599,17 +2665,8 @@ d_expression (struct d_info *di)
/* Function parameter used in a late-specified return type. */ /* Function parameter used in a late-specified return type. */
int index; int index;
d_advance (di, 2); d_advance (di, 2);
if (d_peek_char (di) == '_') index = d_compact_number (di);
index = 1; if (index < 0)
else
{
index = d_number (di);
if (index < 0)
return NULL;
index += 2;
}
if (! d_check_char (di, '_'))
return NULL; return NULL;
return d_make_function_param (di, index); return d_make_function_param (di, index);
@ -2802,10 +2859,31 @@ d_local_name (struct d_info *di)
else else
{ {
struct demangle_component *name; struct demangle_component *name;
int num = -1;
if (d_peek_char (di) == 'd')
{
/* Default argument scope: d <number> _. */
d_advance (di, 1);
num = d_compact_number (di);
if (num < 0)
return NULL;
}
name = d_name (di); name = d_name (di);
if (! d_discriminator (di)) if (name)
return NULL; switch (name->type)
{
/* Lambdas and unnamed types have internal discriminators. */
case DEMANGLE_COMPONENT_LAMBDA:
case DEMANGLE_COMPONENT_UNNAMED_TYPE:
break;
default:
if (! d_discriminator (di))
return NULL;
}
if (num >= 0)
name = d_make_default_arg (di, num, name);
return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name); return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name);
} }
} }
@ -2829,6 +2907,75 @@ d_discriminator (struct d_info *di)
return 1; return 1;
} }
/* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ */
static struct demangle_component *
d_lambda (struct d_info *di)
{
struct demangle_component *tl;
struct demangle_component *ret;
int num;
if (! d_check_char (di, 'U'))
return NULL;
if (! d_check_char (di, 'l'))
return NULL;
tl = d_parmlist (di);
if (tl == NULL)
return NULL;
if (! d_check_char (di, 'E'))
return NULL;
num = d_compact_number (di);
if (num < 0)
return NULL;
ret = d_make_empty (di);
if (ret)
{
ret->type = DEMANGLE_COMPONENT_LAMBDA;
ret->u.s_unary_num.sub = tl;
ret->u.s_unary_num.num = num;
}
if (! d_add_substitution (di, ret))
return NULL;
return ret;
}
/* <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ */
static struct demangle_component *
d_unnamed_type (struct d_info *di)
{
struct demangle_component *ret;
long num;
if (! d_check_char (di, 'U'))
return NULL;
if (! d_check_char (di, 't'))
return NULL;
num = d_compact_number (di);
if (num < 0)
return NULL;
ret = d_make_empty (di);
if (ret)
{
ret->type = DEMANGLE_COMPONENT_UNNAMED_TYPE;
ret->u.s_number.number = num;
}
if (! d_add_substitution (di, ret))
return NULL;
return ret;
}
/* Add a new substitution. */ /* Add a new substitution. */
static int static int
@ -3122,6 +3269,14 @@ d_append_string (struct d_print_info *dpi, const char *s)
d_append_buffer (dpi, s, strlen (s)); d_append_buffer (dpi, s, strlen (s));
} }
static inline void
d_append_num (struct d_print_info *dpi, long l)
{
char buf[25];
sprintf (buf,"%ld", l);
d_append_string (dpi, buf);
}
static inline char static inline char
d_last_char (struct d_print_info *dpi) d_last_char (struct d_print_info *dpi)
{ {
@ -3398,6 +3553,8 @@ d_print_comp (struct d_print_info *dpi,
struct demangle_component *local_name; struct demangle_component *local_name;
local_name = d_right (typed_name); local_name = d_right (typed_name);
if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
local_name = local_name->u.s_unary_num.sub;
while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS || local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|| local_name->type == DEMANGLE_COMPONENT_CONST_THIS) || local_name->type == DEMANGLE_COMPONENT_CONST_THIS)
@ -4048,13 +4205,10 @@ d_print_comp (struct d_print_info *dpi,
return; return;
case DEMANGLE_COMPONENT_FUNCTION_PARAM: case DEMANGLE_COMPONENT_FUNCTION_PARAM:
{ d_append_string (dpi, "{parm#");
char buf[25]; d_append_num (dpi, dc->u.s_number.number + 1);
d_append_string (dpi, "parm#"); d_append_char (dpi, '}');
sprintf(buf,"%ld", dc->u.s_number.number); return;
d_append_string (dpi, buf);
return;
}
case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
d_append_string (dpi, "global constructors keyed to "); d_append_string (dpi, "global constructors keyed to ");
@ -4066,6 +4220,20 @@ d_print_comp (struct d_print_info *dpi,
d_print_comp (dpi, dc->u.s_binary.left); d_print_comp (dpi, dc->u.s_binary.left);
return; return;
case DEMANGLE_COMPONENT_LAMBDA:
d_append_string (dpi, "{lambda(");
d_print_comp (dpi, dc->u.s_unary_num.sub);
d_append_string (dpi, ")#");
d_append_num (dpi, dc->u.s_unary_num.num + 1);
d_append_char (dpi, '}');
return;
case DEMANGLE_COMPONENT_UNNAMED_TYPE:
d_append_string (dpi, "{unnamed type#");
d_append_num (dpi, dc->u.s_number.number + 1);
d_append_char (dpi, '}');
return;
default: default:
d_print_error (dpi); d_print_error (dpi);
return; return;
@ -4184,6 +4352,15 @@ d_print_mod_list (struct d_print_info *dpi,
d_append_char (dpi, '.'); d_append_char (dpi, '.');
dc = d_right (mods->mod); dc = d_right (mods->mod);
if (dc->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
{
d_append_string (dpi, "{default arg#");
d_append_num (dpi, dc->u.s_unary_num.num + 1);
d_append_string (dpi, "}::");
dc = dc->u.s_unary_num.sub;
}
while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|| dc->type == DEMANGLE_COMPONENT_CONST_THIS) || dc->type == DEMANGLE_COMPONENT_CONST_THIS)

View File

@ -3885,11 +3885,11 @@ java resource java/util/iso4217.properties
# decltype/param placeholder test # decltype/param placeholder test
--format=gnu-v3 --format=gnu-v3
_Z3addIidEDTplfp_fp0_ET_T0_ _Z3addIidEDTplfp_fp0_ET_T0_
decltype (parm#1+parm#2) add<int, double>(int, double) decltype ({parm#1}+{parm#2}) add<int, double>(int, double)
# decltype/fn call test # decltype/fn call test
--format=gnu-v3 --format=gnu-v3
_Z4add3IidEDTclL_Z1gEfp_fp0_EET_T0_ _Z4add3IidEDTclL_Z1gEfp_fp0_EET_T0_
decltype (g(parm#1, parm#2)) add3<int, double>(int, double) decltype (g({parm#1}, {parm#2})) add3<int, double>(int, double)
# new (2008) built in types test # new (2008) built in types test
--format=gnu-v3 --format=gnu-v3
_Z1fDfDdDeDhDsDi _Z1fDfDdDeDhDsDi
@ -3901,12 +3901,28 @@ void f<int*, float*, double*>(int*, float*, double*)
# '.' test # '.' test
--format=gnu-v3 --format=gnu-v3
_Z1hI1AIiEdEDTcldtfp_1gIT0_EEET_S2_ _Z1hI1AIiEdEDTcldtfp_1gIT0_EEET_S2_
decltype ((parm#1.(g<double>))()) h<A<int>, double>(A<int>, double) decltype (({parm#1}.(g<double>))()) h<A<int>, double>(A<int>, double)
# test for typed function in decltype # test for typed function in decltype
--format=gnu-v3 --format=gnu-v3
_ZN1AIiE1jIiEEDTplfp_clL_Z1xvEEET_ _ZN1AIiE1jIiEEDTplfp_clL_Z1xvEEET_
decltype (parm#1+((x())())) A<int>::j<int>(int) decltype ({parm#1}+((x())())) A<int>::j<int>(int)
# test for expansion of function parameter pack # test for expansion of function parameter pack
--format=gnu-v3 --format=gnu-v3
_Z1gIIidEEDTclL_Z1fEspplfp_Li1EEEDpT_ _Z1gIIidEEDTclL_Z1fEspplfp_Li1EEEDpT_
decltype (f((parm#1+(1))...)) g<int, double>(int, double) decltype (f(({parm#1}+(1))...)) g<int, double>(int, double)
# lambda tests
--format=gnu-v3
_ZZ1giENKUlvE_clEv
g(int)::{lambda()#1}::operator()() const
--format=gnu-v3
_Z4algoIZ1giEUlvE0_EiT_
int algo<g(int)::{lambda()#2}>(g(int)::{lambda()#2})
--format=gnu-v3
_ZZN1S1fEiiEd0_NKUlvE0_clEv
S::f(int, int)::{default arg#2}::{lambda()#2}::operator()() const
--format=gnu-v3
_ZNK1SIiE1xMUlvE1_clEv
S<int>::x::{lambda()#3}::operator()() const
--format=gnu-v3
_Z1fN1SUt_E
f(S::{unnamed type#1})