mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-27 05:44:15 +08:00
merge in cxx0x-lambdas-branch@152308
From-SVN: r152318
This commit is contained in:
parent
300ea2831b
commit
d5f4edddeb
@ -328,6 +328,7 @@ Chris Fairles cfairles@gcc.gnu.org
|
||||
Li Feng nemokingdom@gmail.com
|
||||
Thomas Fitzsimmons fitzsim@redhat.com
|
||||
Brian Ford ford@vss.fsi.com
|
||||
John Freeman jfreeman08@gmail.com
|
||||
Nathan Froyd froydnj@codesourcery.com
|
||||
Chao-ying Fu fu@mips.com
|
||||
Gary Funck gary@intrepid.com
|
||||
|
@ -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>
|
||||
|
||||
* mangle.c (write_builtin_type): Support decimal float types.
|
||||
|
@ -2677,6 +2677,10 @@ add_implicitly_declared_members (tree t,
|
||||
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
|
||||
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
|
||||
@ -4449,6 +4453,20 @@ check_bases_and_members (tree t)
|
||||
cant_have_const_ctor,
|
||||
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
|
||||
and destructors. */
|
||||
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 (!(innermost_scope_kind() == sk_class
|
||||
&& TYPE_BEING_DEFINED (current_class_type)))
|
||||
&& TYPE_BEING_DEFINED (current_class_type)
|
||||
&& !LAMBDA_TYPE_P (current_class_type)))
|
||||
return;
|
||||
|
||||
/* If there's already a binding for this NAME, then we don't have
|
||||
|
@ -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
|
||||
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);
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
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:
|
||||
/* FIXME communicate throw type to back end, probably by moving
|
||||
THROW_EXPR into ../tree.def. */
|
||||
|
@ -138,6 +138,8 @@ cp_tree_size (enum tree_code code)
|
||||
case TRAIT_EXPR:
|
||||
return sizeof (struct tree_trait_expr);
|
||||
|
||||
case LAMBDA_EXPR: return sizeof (struct tree_lambda_expr);
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
@ -81,6 +81,11 @@ DEFTREECODE (TYPE_EXPR, "type_expr", tcc_expression, 1)
|
||||
the remaining operands are the arguments to the initialization function. */
|
||||
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,
|
||||
else it is NULL_TREE. */
|
||||
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. */
|
||||
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.
|
||||
DECLTYPE_TYPE_EXPR is the expression whose type we are computing.
|
||||
DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P states whether the
|
||||
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)
|
||||
|
||||
/*
|
||||
|
136
gcc/cp/cp-tree.h
136
gcc/cp/cp-tree.h
@ -77,6 +77,8 @@ framework extensions, you must include this file before toplev.h, not after.
|
||||
TYPE_REF_IS_RVALUE (in REFERENCE_TYPE)
|
||||
ATTR_IS_DEPENDENT (in the TREE_LIST for an attribute)
|
||||
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)
|
||||
TI_PENDING_TEMPLATE_FLAG.
|
||||
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)
|
||||
STMT_IS_FULL_EXPR_P (in _STMT)
|
||||
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)
|
||||
ICS_THIS_FLAG (in _CONV)
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
|
||||
STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST)
|
||||
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).
|
||||
ICS_BAD_FLAG (in _CONV)
|
||||
FN_TRY_BLOCK_P (in TRY_BLOCK)
|
||||
@ -517,6 +522,81 @@ struct GTY (()) tree_trait_expr {
|
||||
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 {
|
||||
TS_CP_GENERIC,
|
||||
TS_CP_IDENTIFIER,
|
||||
@ -530,6 +610,7 @@ enum cp_tree_node_structure_enum {
|
||||
TS_CP_STATIC_ASSERT,
|
||||
TS_CP_ARGUMENT_PACK_SELECT,
|
||||
TS_CP_TRAIT_EXPR,
|
||||
TS_CP_LAMBDA_EXPR,
|
||||
LAST_TS_CP_ENUM
|
||||
};
|
||||
|
||||
@ -550,6 +631,8 @@ union GTY((desc ("cp_tree_node_structure (&%h)"),
|
||||
argument_pack_select;
|
||||
struct tree_trait_expr GTY ((tag ("TS_CP_TRAIT_EXPR")))
|
||||
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_list_ctor : 1;
|
||||
unsigned non_std_layout : 1;
|
||||
unsigned lazy_move_ctor : 1;
|
||||
|
||||
/* When adding a flag here, consider whether or not it ought to
|
||||
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
|
||||
of this by updating the size of this bitfield whenever you add or
|
||||
remove a flag. */
|
||||
unsigned dummy : 9;
|
||||
unsigned dummy : 8;
|
||||
|
||||
tree primary_base;
|
||||
VEC(tree_pair_s,gc) *vcall_indices;
|
||||
@ -1159,6 +1243,8 @@ struct GTY(()) lang_type_class {
|
||||
to resort it if pointers get rearranged. */
|
||||
struct sorted_fields_type * GTY ((reorder ("resort_sorted_fields")))
|
||||
sorted_fields;
|
||||
/* FIXME reuse another field? */
|
||||
tree lambda_expr;
|
||||
};
|
||||
|
||||
struct GTY(()) lang_type_ptrmem {
|
||||
@ -1221,6 +1307,11 @@ struct GTY(()) lang_type {
|
||||
#define CLASSTYPE_LAZY_COPY_CTOR(NODE) \
|
||||
(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
|
||||
-- but that it has not yet been declared. */
|
||||
#define CLASSTYPE_LAZY_ASSIGNMENT_OP(NODE) \
|
||||
@ -1426,6 +1517,13 @@ struct GTY(()) lang_type {
|
||||
#define CLASSTYPE_BEFRIENDING_CLASSES(NODE) \
|
||||
(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". */
|
||||
#define CLASSTYPE_DECLARED_CLASS(NODE) \
|
||||
(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); \
|
||||
(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
|
||||
TEMPLATE_DECL. This macro determines whether or not a given class
|
||||
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) \
|
||||
(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
|
||||
specified in its declaration. This can also be set for an
|
||||
erroneously declared PARM_DECL. */
|
||||
@ -3570,6 +3680,7 @@ typedef enum special_function_kind {
|
||||
special_function_p. */
|
||||
sfk_constructor, /* A constructor. */
|
||||
sfk_copy_constructor, /* A copy constructor. */
|
||||
sfk_move_constructor, /* A move constructor. */
|
||||
sfk_assignment_operator, /* An assignment operator. */
|
||||
sfk_destructor, /* A destructor. */
|
||||
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_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)
|
||||
|
||||
#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 push_switch (tree);
|
||||
extern void pop_switch (void);
|
||||
extern tree make_lambda_name (void);
|
||||
extern int decls_match (tree, tree);
|
||||
extern tree duplicate_decls (tree, tree, bool);
|
||||
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 finish_decltype_type (tree, bool);
|
||||
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 */
|
||||
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 build_cplus_array_type (tree, tree);
|
||||
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_chain (tree, tree);
|
||||
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 cp_build_type_attribute_variant (tree, tree);
|
||||
extern tree cp_build_reference_type (tree, bool);
|
||||
extern tree move (tree);
|
||||
extern tree cp_build_qualified_type_real (tree, int, tsubst_flags_t);
|
||||
#define cp_build_qualified_type(TYPE, QUALS) \
|
||||
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 bool cxx_omp_privatize_by_reference (const_tree);
|
||||
|
||||
/* in parser.c */
|
||||
extern bool no_linkage_lambda_type_p (tree);
|
||||
|
||||
/* -- end of C++ */
|
||||
|
||||
#endif /* ! GCC_CP_TREE_H */
|
||||
|
@ -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
|
||||
valid aggregate initialization. */
|
||||
&& !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++;
|
||||
return init;
|
||||
@ -6622,6 +6623,7 @@ grokfndecl (tree ctype,
|
||||
{
|
||||
case sfk_constructor:
|
||||
case sfk_copy_constructor:
|
||||
case sfk_move_constructor:
|
||||
DECL_CONSTRUCTOR_P (decl) = 1;
|
||||
break;
|
||||
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 ARGUMENT_PACK_SELECT: return TS_CP_ARGUMENT_PACK_SELECT;
|
||||
case TRAIT_EXPR: return TS_CP_TRAIT_EXPR;
|
||||
case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR;
|
||||
default: return TS_CP_GENERIC;
|
||||
}
|
||||
}
|
||||
|
@ -597,6 +597,15 @@ dump_aggr_type (tree t, int flags)
|
||||
else
|
||||
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
|
||||
pp_cxx_tree_identifier (cxx_pp, name);
|
||||
if (tmplate)
|
||||
@ -1224,6 +1233,14 @@ dump_function_decl (tree t, int flags)
|
||||
tree exceptions;
|
||||
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;
|
||||
if (TREE_CODE (t) == TEMPLATE_DECL)
|
||||
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. */
|
||||
if (DECL_CONSTRUCTOR_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))
|
||||
{
|
||||
@ -2676,6 +2698,8 @@ function_category (tree fn)
|
||||
return _("In constructor %qs");
|
||||
else if (DECL_DESTRUCTOR_P (fn))
|
||||
return _("In destructor %qs");
|
||||
else if (LAMBDA_FUNCTION_P (fn))
|
||||
return _("In lambda function");
|
||||
else
|
||||
return _("In member function %qs");
|
||||
}
|
||||
|
157
gcc/cp/mangle.c
157
gcc/cp/mangle.c
@ -182,10 +182,13 @@ static void write_template_prefix (const tree);
|
||||
static void write_unqualified_name (const tree);
|
||||
static void write_conversion_operator_name (const 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 *,
|
||||
const unsigned int);
|
||||
static void write_number (unsigned HOST_WIDE_INT, const int,
|
||||
const unsigned int);
|
||||
static void write_compact_number (int num);
|
||||
static void write_integer_cst (const tree);
|
||||
static void write_real_cst (const tree);
|
||||
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_string_literal (tree, tree);
|
||||
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 tree mangle_decl_string (const tree);
|
||||
|
||||
@ -744,6 +747,22 @@ needs_fake_anon (const_tree 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>
|
||||
::= <unscoped-template-name> <template-args>
|
||||
::= <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
|
||||
TYPE_DECL for the main variant. */
|
||||
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);
|
||||
|
||||
@ -822,7 +840,8 @@ write_name (tree decl, const int ignore_local_scope)
|
||||
if (TYPE_P (context))
|
||||
context = TYPE_NAME (context);
|
||||
/* 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>
|
||||
production for the innermost function scope. */
|
||||
@ -831,7 +850,7 @@ write_name (tree decl, const int ignore_local_scope)
|
||||
}
|
||||
/* Up one scope level. */
|
||||
local_entity = context;
|
||||
context = CP_DECL_CONTEXT (context);
|
||||
context = decl_mangling_context (context);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
tree template_info = NULL;
|
||||
|
||||
MANGLE_TRACE_TREE ("prefix", node);
|
||||
|
||||
if (node == NULL
|
||||
|| node == global_namespace)
|
||||
return;
|
||||
|
||||
MANGLE_TRACE_TREE ("prefix", node);
|
||||
|
||||
if (find_substitution (node))
|
||||
return;
|
||||
|
||||
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
|
||||
case, we're under the <local-name> production, which encodes
|
||||
the enclosing function scope elsewhere. So don't continue
|
||||
here. */
|
||||
if (TREE_CODE (node) == FUNCTION_DECL)
|
||||
if (TREE_CODE (node) == FUNCTION_DECL
|
||||
|| TREE_CODE (node) == PARM_DECL)
|
||||
return;
|
||||
|
||||
decl = node;
|
||||
@ -1016,8 +1036,15 @@ write_prefix (const tree node)
|
||||
else
|
||||
/* Not templated. */
|
||||
{
|
||||
write_prefix (CP_DECL_CONTEXT (decl));
|
||||
write_prefix (decl_mangling_context (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);
|
||||
@ -1107,6 +1134,7 @@ write_template_prefix (const tree node)
|
||||
<unqualified-name> ::= <operator-name>
|
||||
::= <special-name>
|
||||
::= <source-name>
|
||||
::= <unnamed-type-name>
|
||||
::= <local-source-name>
|
||||
|
||||
<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. */
|
||||
}
|
||||
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. */
|
||||
@ -1202,6 +1242,44 @@ write_source_name (tree 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
|
||||
MIN_DIGITS characters. BUFFER points to the _end_ of the buffer
|
||||
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. */
|
||||
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++)
|
||||
{
|
||||
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
|
||||
FUNCTION_DECL for the enclosing function. ENTITY is the decl for
|
||||
the entity itself. LOCAL_ENTITY is the entity that's directly
|
||||
scoped in FUNCTION_DECL, either ENTITY itself or an enclosing scope
|
||||
of ENTITY.
|
||||
FUNCTION_DECL for the enclosing function, or a PARM_DECL for lambdas in
|
||||
default argument scope. ENTITY is the decl for the entity itself.
|
||||
LOCAL_ENTITY is the entity that's directly scoped in FUNCTION_DECL,
|
||||
either ENTITY itself or an enclosing scope of ENTITY.
|
||||
|
||||
<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
|
||||
write_local_name (const tree function, const tree local_entity,
|
||||
write_local_name (tree function, const tree local_entity,
|
||||
const tree entity)
|
||||
{
|
||||
tree parm = NULL_TREE;
|
||||
|
||||
MANGLE_TRACE_TREE ("local-name", entity);
|
||||
|
||||
if (TREE_CODE (function) == PARM_DECL)
|
||||
{
|
||||
parm = function;
|
||||
function = DECL_CONTEXT (parm);
|
||||
}
|
||||
|
||||
write_char ('Z');
|
||||
write_encoding (function);
|
||||
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)
|
||||
{
|
||||
write_char ('s');
|
||||
@ -1718,6 +1827,10 @@ write_type (tree type)
|
||||
break;
|
||||
|
||||
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');
|
||||
if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type))
|
||||
write_char ('t');
|
||||
@ -2236,9 +2349,7 @@ write_expression (tree expr)
|
||||
int index = DECL_PARM_INDEX (expr);
|
||||
gcc_assert (index >= 1);
|
||||
write_string ("fp");
|
||||
if (index > 1)
|
||||
write_unsigned_number (index - 2);
|
||||
write_char ('_');
|
||||
write_compact_number (index - 1);
|
||||
}
|
||||
else if (DECL_P (expr))
|
||||
{
|
||||
@ -2701,9 +2812,7 @@ write_template_param (const tree parm)
|
||||
write_char ('T');
|
||||
/* NUMBER as it appears in the mangling is (-1)-indexed, with the
|
||||
earliest template param denoted by `_'. */
|
||||
if (parm_index > 0)
|
||||
write_unsigned_number (parm_index - 1);
|
||||
write_char ('_');
|
||||
write_compact_number (parm_index);
|
||||
}
|
||||
|
||||
/* <template-template-param>
|
||||
|
@ -530,12 +530,13 @@ use_thunk (tree thunk_fndecl, bool emit_p)
|
||||
|
||||
/* 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
|
||||
do_build_copy_constructor (tree fndecl)
|
||||
{
|
||||
tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
|
||||
bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl);
|
||||
|
||||
parm = convert_from_reference (parm);
|
||||
|
||||
@ -555,6 +556,7 @@ do_build_copy_constructor (tree fndecl)
|
||||
int cvquals = cp_type_quals (TREE_TYPE (parm));
|
||||
int i;
|
||||
tree binfo, base_binfo;
|
||||
tree init;
|
||||
VEC(tree,gc) *vbases;
|
||||
|
||||
/* 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;
|
||||
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
|
||||
= tree_cons (binfo,
|
||||
build_tree_list (NULL_TREE,
|
||||
build_base_path (PLUS_EXPR, parm,
|
||||
binfo, 1)),
|
||||
build_tree_list (NULL_TREE, init),
|
||||
member_init_list);
|
||||
}
|
||||
|
||||
@ -579,17 +582,17 @@ do_build_copy_constructor (tree fndecl)
|
||||
if (BINFO_VIRTUAL_P (base_binfo))
|
||||
continue;
|
||||
|
||||
init = build_base_path (PLUS_EXPR, parm, base_binfo, 1);
|
||||
if (move_p)
|
||||
init = move (init);
|
||||
member_init_list
|
||||
= tree_cons (base_binfo,
|
||||
build_tree_list (NULL_TREE,
|
||||
build_base_path (PLUS_EXPR, parm,
|
||||
base_binfo, 1)),
|
||||
build_tree_list (NULL_TREE, init),
|
||||
member_init_list);
|
||||
}
|
||||
|
||||
for (; fields; fields = TREE_CHAIN (fields))
|
||||
{
|
||||
tree init = parm;
|
||||
tree field = fields;
|
||||
tree expr_type;
|
||||
|
||||
@ -622,7 +625,9 @@ do_build_copy_constructor (tree fndecl)
|
||||
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);
|
||||
|
||||
member_init_list = tree_cons (field, init, member_init_list);
|
||||
@ -936,6 +941,8 @@ locate_copy (tree type, void *client_)
|
||||
it now. */
|
||||
if (CLASSTYPE_LAZY_COPY_CTOR (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);
|
||||
}
|
||||
else
|
||||
@ -1036,6 +1043,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
|
||||
|
||||
case sfk_copy_constructor:
|
||||
case sfk_assignment_operator:
|
||||
case sfk_move_constructor:
|
||||
{
|
||||
struct copy_data data;
|
||||
|
||||
@ -1057,7 +1065,9 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
|
||||
}
|
||||
else
|
||||
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);
|
||||
raises = synthesize_exception_spec (type, &locate_copy, &data);
|
||||
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 = build_lang_decl (FUNCTION_DECL, name, fn_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;
|
||||
else if (kind == sfk_destructor)
|
||||
DECL_DESTRUCTOR_P (fn) = 1;
|
||||
@ -1175,6 +1186,8 @@ lazily_declare_fn (special_function_kind sfk, tree type)
|
||||
CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0;
|
||||
else if (sfk == sfk_copy_constructor)
|
||||
CLASSTYPE_LAZY_COPY_CTOR (type) = 0;
|
||||
else if (sfk == sfk_move_constructor)
|
||||
CLASSTYPE_LAZY_MOVE_CTOR (type) = 0;
|
||||
else if (sfk == sfk_destructor)
|
||||
CLASSTYPE_LAZY_DESTRUCTOR (type) = 0;
|
||||
/* Create appropriate clones. */
|
||||
|
@ -1834,6 +1834,23 @@ make_anon_name (void)
|
||||
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. */
|
||||
|
||||
static inline cxx_binding *
|
||||
@ -2637,6 +2654,11 @@ pushdecl_class_level (tree x)
|
||||
tree name;
|
||||
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);
|
||||
/* Get the name of X. */
|
||||
if (TREE_CODE (x) == OVERLOAD)
|
||||
@ -3735,6 +3757,11 @@ qualify_lookup (tree val, int flags)
|
||||
return true;
|
||||
if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES))
|
||||
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;
|
||||
}
|
||||
|
||||
@ -5114,7 +5141,8 @@ pushtag (tree name, tree type, tag_scope scope)
|
||||
{
|
||||
tree cs = current_scope ();
|
||||
|
||||
if (scope == ts_current)
|
||||
if (scope == ts_current
|
||||
|| (cs && TREE_CODE (cs) == FUNCTION_DECL))
|
||||
context = cs;
|
||||
else if (cs != NULL_TREE && TYPE_P (cs))
|
||||
/* When declaring a friend class of a local class, we want
|
||||
|
603
gcc/cp/parser.c
603
gcc/cp/parser.c
@ -1626,6 +1626,14 @@ static tree cp_parser_constant_expression
|
||||
(cp_parser *, bool, bool *);
|
||||
static tree cp_parser_builtin_offsetof
|
||||
(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] */
|
||||
|
||||
@ -2452,6 +2460,7 @@ cp_parser_skip_to_closing_parenthesis (cp_parser *parser,
|
||||
{
|
||||
unsigned paren_depth = 0;
|
||||
unsigned brace_depth = 0;
|
||||
unsigned square_depth = 0;
|
||||
|
||||
if (recovering && !or_comma
|
||||
&& 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 `)'. */
|
||||
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:
|
||||
/* This matches the processing in skip_to_end_of_statement. */
|
||||
if (!brace_depth)
|
||||
@ -2483,7 +2501,8 @@ cp_parser_skip_to_closing_parenthesis (cp_parser *parser,
|
||||
break;
|
||||
|
||||
case CPP_COMMA:
|
||||
if (recovering && or_comma && !brace_depth && !paren_depth)
|
||||
if (recovering && or_comma && !brace_depth && !paren_depth
|
||||
&& !square_depth)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
@ -3283,6 +3302,20 @@ cp_parser_primary_expression (cp_parser *parser,
|
||||
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:
|
||||
switch (token->keyword)
|
||||
{
|
||||
@ -3540,13 +3573,6 @@ cp_parser_primary_expression (cp_parser *parser,
|
||||
|
||||
/* Anything else is an error. */
|
||||
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");
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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] */
|
||||
|
||||
/* Parse a statement.
|
||||
@ -13033,9 +13578,21 @@ cp_parser_init_declarator (cp_parser* parser,
|
||||
}
|
||||
}
|
||||
else
|
||||
initializer = cp_parser_initializer (parser,
|
||||
&is_direct_init,
|
||||
&is_non_constant_init);
|
||||
{
|
||||
/* We want to record the extra mangling scope for in-class
|
||||
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
|
||||
@ -14453,7 +15010,8 @@ cp_parser_parameter_declaration (cp_parser *parser,
|
||||
/* If we are defining a class, then the tokens that make up the
|
||||
default argument must be saved and processed later. */
|
||||
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;
|
||||
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
|
||||
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. */
|
||||
|
||||
@ -17893,6 +18451,9 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
|
||||
saved_num_template_parameter_lists
|
||||
= parser->num_template_parameter_lists;
|
||||
parser->num_template_parameter_lists = 0;
|
||||
|
||||
start_lambda_scope (current_function_decl);
|
||||
|
||||
/* If the next token is `try', then we are looking at a
|
||||
function-try-block. */
|
||||
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
|
||||
= cp_parser_ctor_initializer_opt_and_function_body (parser);
|
||||
|
||||
finish_lambda_scope ();
|
||||
|
||||
/* Finish the function. */
|
||||
fn = finish_function ((ctor_initializer_p ? 1 : 0) |
|
||||
(inline_p ? 2 : 0));
|
||||
@ -18530,7 +19093,7 @@ static void
|
||||
cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
|
||||
{
|
||||
bool saved_local_variables_forbidden_p;
|
||||
tree parm;
|
||||
tree parm, parmdecl;
|
||||
|
||||
/* While we're parsing the default args, we might (due to the
|
||||
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;
|
||||
parser->local_variables_forbidden_p = true;
|
||||
|
||||
for (parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
|
||||
parm;
|
||||
parm = TREE_CHAIN (parm))
|
||||
for (parm = TYPE_ARG_TYPES (TREE_TYPE (fn)),
|
||||
parmdecl = DECL_ARGUMENTS (fn);
|
||||
parm && parm != void_list_node;
|
||||
parm = TREE_CHAIN (parm),
|
||||
parmdecl = TREE_CHAIN (parmdecl))
|
||||
{
|
||||
cp_token_cache *tokens;
|
||||
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);
|
||||
cp_parser_push_lexer_for_tokens (parser, tokens);
|
||||
|
||||
start_lambda_scope (parmdecl);
|
||||
|
||||
/* Parse the assignment-expression. */
|
||||
parsed_arg = cp_parser_assignment_expression (parser, /*cast_p=*/false, NULL);
|
||||
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++)
|
||||
TREE_PURPOSE (copy) = parsed_arg;
|
||||
|
||||
finish_lambda_scope ();
|
||||
|
||||
/* If the token stream has not been completely used up, then
|
||||
there was extra junk after the end of the default
|
||||
argument. */
|
||||
|
69
gcc/cp/pt.c
69
gcc/cp/pt.c
@ -300,7 +300,7 @@ get_template_info (const_tree t)
|
||||
if (DECL_P (t) && DECL_LANG_SPECIFIC (t))
|
||||
tinfo = DECL_TEMPLATE_INFO (t);
|
||||
|
||||
if (!tinfo && TREE_CODE (t) == TYPE_DECL)
|
||||
if (!tinfo && DECL_IMPLICIT_TYPEDEF_P (t))
|
||||
t = TREE_TYPE (t);
|
||||
|
||||
if (TAGGED_TYPE_P (t))
|
||||
@ -6230,6 +6230,7 @@ lookup_template_class (tree d1,
|
||||
|
||||
if (!is_partial_instantiation
|
||||
&& !PRIMARY_TEMPLATE_P (gen_tmpl)
|
||||
&& !LAMBDA_TYPE_P (TREE_TYPE (gen_tmpl))
|
||||
&& TREE_CODE (CP_DECL_CONTEXT (gen_tmpl)) == NAMESPACE_DECL)
|
||||
{
|
||||
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);
|
||||
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
|
||||
register_local_specialization (r, t);
|
||||
|
||||
@ -10153,9 +10170,13 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
--cp_unevaluated_operand;
|
||||
--c_inhibit_evaluation_warnings;
|
||||
|
||||
type =
|
||||
finish_decltype_type (type,
|
||||
DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t));
|
||||
if (DECLTYPE_FOR_LAMBDA_CAPTURE (t))
|
||||
type = lambda_capture_field_type (type);
|
||||
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,
|
||||
cp_type_quals (t)
|
||||
| cp_type_quals (type),
|
||||
@ -12359,6 +12380,39 @@ tsubst_copy_and_build (tree 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:
|
||||
/* Handle Objective-C++ constructs, if appropriate. */
|
||||
{
|
||||
@ -15959,10 +16013,11 @@ instantiate_decl (tree d, int defer_ok,
|
||||
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 type = TREE_TYPE (gen);
|
||||
|
||||
|
@ -1380,6 +1380,8 @@ lookup_fnfields_1 (tree type, tree name)
|
||||
lazily_declare_fn (sfk_constructor, type);
|
||||
if (CLASSTYPE_LAZY_COPY_CTOR (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)
|
||||
&& CLASSTYPE_LAZY_ASSIGNMENT_OP (type))
|
||||
|
@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
|
||||
static tree maybe_convert_cond (tree);
|
||||
static tree finalize_nrv_r (tree *, int *, void *);
|
||||
static tree capture_decltype (tree);
|
||||
|
||||
|
||||
/* Deferred Access Checking Overview
|
||||
@ -1445,6 +1446,21 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
|
||||
|
||||
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)
|
||||
TREE_USED (current_class_ptr) = 1;
|
||||
if (processing_template_decl && !qualifying_scope)
|
||||
@ -2049,7 +2065,14 @@ finish_this_expr (void)
|
||||
|
||||
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
|
||||
&& 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);
|
||||
}
|
||||
|
||||
/* 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. (See cp_parser_id_expression for details.) SCOPE,
|
||||
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)
|
||||
maybe_note_name_used_in_class (id_expression, decl);
|
||||
|
||||
/* Disallow uses of local variables from containing functions. */
|
||||
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
|
||||
/* Disallow uses of local variables from containing functions, except
|
||||
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);
|
||||
if (context != NULL_TREE && context != current_function_decl
|
||||
&& ! TREE_STATIC (decl))
|
||||
tree context = DECL_CONTEXT (decl);
|
||||
tree containing_function = current_function_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
|
||||
? "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))
|
||||
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
|
||||
{
|
||||
/* 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. */
|
||||
if (CLASSTYPE_LAZY_COPY_CTOR (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);
|
||||
}
|
||||
else
|
||||
@ -5105,4 +5203,416 @@ float_const_decimal64_p (void)
|
||||
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"
|
||||
|
@ -456,6 +456,22 @@ build_cplus_new (tree type, tree init)
|
||||
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
|
||||
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,
|
||||
the C version of this function does not properly maintain canonical
|
||||
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. */
|
||||
if (TYPE_ANONYMOUS_P (t) && TYPE_NAMESPACE_SCOPE_P (t))
|
||||
return t;
|
||||
if (no_linkage_lambda_type_p (t))
|
||||
return t;
|
||||
|
||||
r = CP_TYPE_CONTEXT (t);
|
||||
if (TYPE_P (r))
|
||||
@ -2759,6 +2788,8 @@ special_function_p (const_tree decl)
|
||||
DECL_LANG_SPECIFIC. */
|
||||
if (DECL_COPY_CONSTRUCTOR_P (decl))
|
||||
return sfk_copy_constructor;
|
||||
if (DECL_MOVE_CONSTRUCTOR_P (decl))
|
||||
return sfk_move_constructor;
|
||||
if (DECL_CONSTRUCTOR_P (decl))
|
||||
return sfk_constructor;
|
||||
if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)
|
||||
|
@ -1161,6 +1161,10 @@ structural_comptypes (tree t1, tree t2, int strict)
|
||||
case DECLTYPE_TYPE:
|
||||
if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
|
||||
!= 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),
|
||||
DECLTYPE_TYPE_EXPR (t2)))
|
||||
return false;
|
||||
@ -7001,6 +7005,31 @@ check_return_expr (tree retval, bool *no_warning)
|
||||
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)
|
||||
{
|
||||
current_function_returns_value = 1;
|
||||
|
@ -838,6 +838,12 @@ digest_init_r (tree type, tree init, bool nested, int flags)
|
||||
if (TREE_CODE (type) == ARRAY_TYPE
|
||||
&& 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"
|
||||
" initializer");
|
||||
return error_mark_node;
|
||||
|
@ -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>
|
||||
|
||||
* gcc.target/i386/fma4-check.h
|
||||
|
20
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-array.C
Normal file
20
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-array.C
Normal 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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
15
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const-ref.C
Normal file
15
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const-ref.C
Normal 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;
|
||||
}
|
||||
|
19
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-neg.C
Normal file
19
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-neg.C
Normal 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;
|
||||
}
|
||||
|
20
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const.C
Normal file
20
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const.C
Normal 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;
|
||||
}
|
||||
|
13
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-default-neg.C
Normal file
13
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-default-neg.C
Normal 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;
|
||||
}
|
||||
|
14
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-default.C
Normal file
14
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-default.C
Normal 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;
|
||||
}
|
||||
|
13
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-neg.C
Normal file
13
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-neg.C
Normal 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;
|
||||
}
|
||||
|
14
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy.C
Normal file
14
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy.C
Normal 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;
|
||||
}
|
||||
|
25
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ctor-neg.C
Normal file
25
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ctor-neg.C
Normal 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);
|
||||
}
|
18
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ctors.C
Normal file
18
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ctors.C
Normal 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();
|
||||
}
|
24
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg.C
Normal file
24
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg.C
Normal 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;
|
||||
}
|
22
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg2.C
Normal file
22
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg2.C
Normal 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;
|
||||
}
|
27
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext.C
Normal file
27
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext.C
Normal 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;
|
||||
}
|
10
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-neg.C
Normal file
10
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-neg.C
Normal 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;
|
||||
}
|
||||
|
29
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce.C
Normal file
29
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce.C
Normal 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;
|
||||
}
|
||||
|
6
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg.C
Normal file
6
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg.C
Normal file
@ -0,0 +1,6 @@
|
||||
// { dg-options "-std=c++0x -pedantic-errors" }
|
||||
|
||||
int main()
|
||||
{
|
||||
[](int a = 1) { return a; }(); // { dg-error "" }
|
||||
}
|
35
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-eh.C
Normal file
35
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-eh.C
Normal 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;
|
||||
}
|
18
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-errloc.C
Normal file
18
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-errloc.C
Normal 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:" }
|
||||
}
|
21
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-field-names.C
Normal file
21
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-field-names.C
Normal 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();
|
||||
}
|
35
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-in-class-neg.C
Normal file
35
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-in-class-neg.C
Normal 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;
|
||||
}
|
||||
|
36
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-in-class.C
Normal file
36
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-in-class.C
Normal 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;
|
||||
}
|
||||
|
7
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-lookup-neg.C
Normal file
7
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-lookup-neg.C
Normal 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" }
|
||||
}
|
102
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C
Normal file
102
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C
Normal 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>();
|
||||
}
|
13
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mixed.C
Normal file
13
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mixed.C
Normal 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;
|
||||
}
|
||||
|
16
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mutable.C
Normal file
16
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mutable.C
Normal 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;
|
||||
}
|
||||
|
52
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested.C
Normal file
52
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested.C
Normal 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;
|
||||
}
|
||||
|
19
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-non-const.C
Normal file
19
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-non-const.C
Normal 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;
|
||||
}
|
||||
|
19
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nop.C
Normal file
19
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nop.C
Normal 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;
|
||||
}
|
||||
|
18
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ns-scope.C
Normal file
18
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ns-scope.C
Normal 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;
|
||||
}
|
27
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-pass.C
Normal file
27
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-pass.C
Normal 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;
|
||||
}
|
||||
|
21
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-recursive.C
Normal file
21
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-recursive.C
Normal 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;
|
||||
}
|
||||
|
15
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ref-default.C
Normal file
15
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ref-default.C
Normal 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;
|
||||
}
|
||||
|
15
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ref.C
Normal file
15
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ref.C
Normal 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;
|
||||
}
|
||||
|
22
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-std-function.C
Normal file
22
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-std-function.C
Normal 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;
|
||||
}
|
41
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template.C
Normal file
41
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template.C
Normal 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);
|
||||
}
|
13
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this.C
Normal file
13
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this.C
Normal 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" }
|
||||
}
|
||||
};
|
74
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-type.C
Normal file
74
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-type.C
Normal 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" }
|
||||
};
|
||||
}
|
12
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-use.C
Normal file
12
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-use.C
Normal 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]; };
|
||||
}
|
@ -20,7 +20,7 @@
|
||||
proc prune_gcc_output { text } {
|
||||
#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\]*: instantiated from \[^\n\]*" $text "" text
|
||||
regsub -all "(^|\n) inlined from \[^\n\]*" $text "" text
|
||||
|
6
include/ChangeLog.lambda
Normal file
6
include/ChangeLog.lambda
Normal 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.
|
@ -381,6 +381,12 @@ enum demangle_component_type
|
||||
DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS,
|
||||
/* Global destructors keyed to name. */
|
||||
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. */
|
||||
DEMANGLE_COMPONENT_PACK_EXPANSION
|
||||
};
|
||||
@ -494,6 +500,14 @@ struct demangle_component
|
||||
struct demangle_component *right;
|
||||
} s_binary;
|
||||
|
||||
struct
|
||||
{
|
||||
/* subtree, same place as d_left. */
|
||||
struct demangle_component *sub;
|
||||
/* integer. */
|
||||
int num;
|
||||
} s_unary_num;
|
||||
|
||||
} u;
|
||||
};
|
||||
|
||||
|
@ -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>
|
||||
|
||||
* cplus-dem.c (ada_demangle): Ensure demangled is freed.
|
||||
|
@ -371,10 +371,12 @@ TAGS: $(CFILES)
|
||||
etags `for i in $(CFILES); do echo $(srcdir)/$$i ; done`
|
||||
|
||||
# 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 "a part of binutils."
|
||||
@false
|
||||
$(CC) @DEFS@ $(CFLAGS) $(CPPFLAGS) -I. -I$(INCDIR) $(HDEFINES) \
|
||||
$(srcdir)/cp-demangle.c -DSTANDALONE_DEMANGLER $(TARGETLIB) -o $@
|
||||
|
||||
ls:
|
||||
@echo Makefile $(CFILES)
|
||||
|
@ -408,6 +408,10 @@ static struct demangle_component *d_local_name (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
|
||||
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;
|
||||
}
|
||||
|
||||
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. */
|
||||
|
||||
static struct demangle_component *
|
||||
@ -1153,8 +1171,9 @@ d_name (struct d_info *di)
|
||||
return d_local_name (di);
|
||||
|
||||
case 'L':
|
||||
case 'U':
|
||||
return d_unqualified_name (di);
|
||||
|
||||
|
||||
case 'S':
|
||||
{
|
||||
int subst;
|
||||
@ -1276,6 +1295,7 @@ d_prefix (struct d_info *di)
|
||||
|| IS_LOWER (peek)
|
||||
|| peek == 'C'
|
||||
|| peek == 'D'
|
||||
|| peek == 'U'
|
||||
|| peek == 'L')
|
||||
dc = d_unqualified_name (di);
|
||||
else if (peek == 'S')
|
||||
@ -1291,6 +1311,16 @@ d_prefix (struct d_info *di)
|
||||
dc = d_template_param (di);
|
||||
else if (peek == 'E')
|
||||
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
|
||||
return NULL;
|
||||
|
||||
@ -1347,6 +1377,18 @@ d_unqualified_name (struct d_info *di)
|
||||
return NULL;
|
||||
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
|
||||
return NULL;
|
||||
}
|
||||
@ -2242,50 +2284,30 @@ d_function_type (struct d_info *di)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* <bare-function-type> ::= [J]<type>+ */
|
||||
/* <type>+ */
|
||||
|
||||
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 **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;
|
||||
ptl = &tl;
|
||||
while (1)
|
||||
{
|
||||
struct demangle_component *type;
|
||||
|
||||
peek = d_peek_char (di);
|
||||
char peek = d_peek_char (di);
|
||||
if (peek == '\0' || peek == 'E')
|
||||
break;
|
||||
type = cplus_demangle_type (di);
|
||||
if (type == NULL)
|
||||
return NULL;
|
||||
if (has_return_type)
|
||||
{
|
||||
return_type = type;
|
||||
has_return_type = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL);
|
||||
if (*ptl == NULL)
|
||||
return NULL;
|
||||
ptl = &d_right (*ptl);
|
||||
}
|
||||
*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
|
||||
@ -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)
|
||||
{
|
||||
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> */
|
||||
@ -2405,6 +2462,24 @@ d_pointer_to_member_type (struct d_info *di)
|
||||
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_
|
||||
::= T <(parameter-2 non-negative) number> _
|
||||
*/
|
||||
@ -2417,17 +2492,8 @@ d_template_param (struct d_info *di)
|
||||
if (! d_check_char (di, 'T'))
|
||||
return NULL;
|
||||
|
||||
if (d_peek_char (di) == '_')
|
||||
param = 0;
|
||||
else
|
||||
{
|
||||
param = d_number (di);
|
||||
if (param < 0)
|
||||
return NULL;
|
||||
param += 1;
|
||||
}
|
||||
|
||||
if (! d_check_char (di, '_'))
|
||||
param = d_compact_number (di);
|
||||
if (param < 0)
|
||||
return NULL;
|
||||
|
||||
++di->did_subs;
|
||||
@ -2599,17 +2665,8 @@ d_expression (struct d_info *di)
|
||||
/* Function parameter used in a late-specified return type. */
|
||||
int index;
|
||||
d_advance (di, 2);
|
||||
if (d_peek_char (di) == '_')
|
||||
index = 1;
|
||||
else
|
||||
{
|
||||
index = d_number (di);
|
||||
if (index < 0)
|
||||
return NULL;
|
||||
index += 2;
|
||||
}
|
||||
|
||||
if (! d_check_char (di, '_'))
|
||||
index = d_compact_number (di);
|
||||
if (index < 0)
|
||||
return NULL;
|
||||
|
||||
return d_make_function_param (di, index);
|
||||
@ -2802,10 +2859,31 @@ d_local_name (struct d_info *di)
|
||||
else
|
||||
{
|
||||
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);
|
||||
if (! d_discriminator (di))
|
||||
return NULL;
|
||||
if (name)
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -2829,6 +2907,75 @@ d_discriminator (struct d_info *di)
|
||||
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. */
|
||||
|
||||
static int
|
||||
@ -3122,6 +3269,14 @@ d_append_string (struct d_print_info *dpi, const char *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
|
||||
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;
|
||||
|
||||
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
|
||||
|| local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| local_name->type == DEMANGLE_COMPONENT_CONST_THIS)
|
||||
@ -4048,13 +4205,10 @@ d_print_comp (struct d_print_info *dpi,
|
||||
return;
|
||||
|
||||
case DEMANGLE_COMPONENT_FUNCTION_PARAM:
|
||||
{
|
||||
char buf[25];
|
||||
d_append_string (dpi, "parm#");
|
||||
sprintf(buf,"%ld", dc->u.s_number.number);
|
||||
d_append_string (dpi, buf);
|
||||
return;
|
||||
}
|
||||
d_append_string (dpi, "{parm#");
|
||||
d_append_num (dpi, dc->u.s_number.number + 1);
|
||||
d_append_char (dpi, '}');
|
||||
return;
|
||||
|
||||
case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
|
||||
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);
|
||||
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:
|
||||
d_print_error (dpi);
|
||||
return;
|
||||
@ -4184,6 +4352,15 @@ d_print_mod_list (struct d_print_info *dpi,
|
||||
d_append_char (dpi, '.');
|
||||
|
||||
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
|
||||
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_CONST_THIS)
|
||||
|
@ -3885,11 +3885,11 @@ java resource java/util/iso4217.properties
|
||||
# decltype/param placeholder test
|
||||
--format=gnu-v3
|
||||
_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
|
||||
--format=gnu-v3
|
||||
_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
|
||||
--format=gnu-v3
|
||||
_Z1fDfDdDeDhDsDi
|
||||
@ -3901,12 +3901,28 @@ void f<int*, float*, double*>(int*, float*, double*)
|
||||
# '.' test
|
||||
--format=gnu-v3
|
||||
_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
|
||||
--format=gnu-v3
|
||||
_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
|
||||
--format=gnu-v3
|
||||
_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})
|
||||
|
Loading…
Reference in New Issue
Block a user