diff options
author | Jason Merrill <jason@redhat.com> | 2009-10-27 17:58:09 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2009-10-27 17:58:09 -0400 |
commit | b77068f27bbad156e88352bb1a3382a96b66acbf (patch) | |
tree | 000402686698d1995b0a51ccb183ff709533ba84 /gcc | |
parent | 73d28034382a7ba65ec46d6a1cebd828f32b16c9 (diff) | |
download | gcc-b77068f27bbad156e88352bb1a3382a96b66acbf.zip gcc-b77068f27bbad156e88352bb1a3382a96b66acbf.tar.gz gcc-b77068f27bbad156e88352bb1a3382a96b66acbf.tar.bz2 |
Allow no-capture lambdas to convert to function pointer.
* semantics.c (maybe_add_lambda_conv_op): New.
* parser.c (cp_parser_lambda_expression): Call it.
(cp_parser_lambda_declarator_opt): Make op() static if
no captures.
* mangle.c (write_closure_type_name): Adjust.
* semantics.c (finish_this_expr): Adjust.
* decl.c (grok_op_properties): Allow it.
* call.c (build_user_type_conversion_1): Handle static conversion op.
(build_op_call): And op().
From-SVN: r153617
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/cp/call.c | 25 | ||||
-rw-r--r-- | gcc/cp/class.c | 3 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/decl.c | 9 | ||||
-rw-r--r-- | gcc/cp/mangle.c | 2 | ||||
-rw-r--r-- | gcc/cp/parser.c | 20 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 69 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-neg.C | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv.C | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C | 18 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/lambda/lambda-non-const.C | 1 |
13 files changed, 142 insertions, 36 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e722958..ba4caf8 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2009-10-27 Jason Merrill <jason@redhat.com> + + Allow no-capture lambdas to convert to function pointer. + * semantics.c (maybe_add_lambda_conv_op): New. + * parser.c (cp_parser_lambda_expression): Call it. + (cp_parser_lambda_declarator_opt): Make op() static if + no captures. + * mangle.c (write_closure_type_name): Adjust. + * semantics.c (finish_this_expr): Adjust. + * decl.c (grok_op_properties): Allow it. + * call.c (build_user_type_conversion_1): Handle static conversion op. + (build_op_call): And op(). + 2009-10-26 Jakub Jelinek <jakub@redhat.com> PR debug/41828 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4542804..d4bdcba 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -2953,11 +2953,16 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags) for (fns = TREE_VALUE (conv_fns); fns; fns = OVL_NEXT (fns)) { tree fn = OVL_CURRENT (fns); + tree first = first_arg; if (DECL_NONCONVERTING_P (fn) && (flags & LOOKUP_ONLYCONVERTING)) continue; + /* Lambdas have a static conversion op. */ + if (DECL_STATIC_FUNCTION_P (fn)) + first = NULL_TREE; + /* [over.match.funcs] For conversion functions, the function is considered to be a member of the class of the implicit object argument for the purpose of defining the type of @@ -2968,14 +2973,14 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags) if (TREE_CODE (fn) == TEMPLATE_DECL) cand = add_template_candidate (&candidates, fn, fromtype, NULL_TREE, - first_arg, NULL, totype, + first, NULL, totype, TYPE_BINFO (fromtype), conversion_path, flags, DEDUCE_CONV); else cand = add_function_candidate (&candidates, fn, fromtype, - first_arg, NULL, + first, NULL, TYPE_BINFO (fromtype), conversion_path, flags); @@ -3382,20 +3387,30 @@ build_op_call (tree obj, VEC(tree,gc) **args, tsubst_flags_t complain) for (fns = BASELINK_FUNCTIONS (fns); fns; fns = OVL_NEXT (fns)) { tree fn = OVL_CURRENT (fns); + + tree lfirst = first_mem_arg; + if (DECL_STATIC_FUNCTION_P (fn)) + lfirst = NULL_TREE; + if (TREE_CODE (fn) == TEMPLATE_DECL) add_template_candidate (&candidates, fn, base, NULL_TREE, - first_mem_arg, *args, NULL_TREE, + lfirst, *args, NULL_TREE, TYPE_BINFO (type), TYPE_BINFO (type), LOOKUP_NORMAL, DEDUCE_CALL); else add_function_candidate - (&candidates, fn, base, first_mem_arg, *args, TYPE_BINFO (type), + (&candidates, fn, base, lfirst, *args, TYPE_BINFO (type), TYPE_BINFO (type), LOOKUP_NORMAL); } } - convs = lookup_conversions (type); + /* Rather than mess with handling static conversion ops here, just don't + look at conversions in lambdas. */ + if (LAMBDA_TYPE_P (type)) + convs = NULL_TREE; + else + convs = lookup_conversions (type); for (; convs; convs = TREE_CHAIN (convs)) { diff --git a/gcc/cp/class.c b/gcc/cp/class.c index d737bdf..dc4c6b3 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2677,7 +2677,8 @@ add_implicitly_declared_members (tree t, CLASSTYPE_LAZY_COPY_CTOR (t) = 1; } - /* Currently only lambdas get a lazy move ctor. */ + /* Currently only lambdas get a lazy move ctor, but N2987 adds them for + other classes. */ if (LAMBDA_TYPE_P (t)) CLASSTYPE_LAZY_MOVE_CTOR (t) = 1; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ea28e9f..5c51a6f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5073,6 +5073,7 @@ extern void apply_lambda_return_type (tree, tree); extern tree add_capture (tree, tree, tree, bool, bool); extern tree add_default_capture (tree, tree, tree); extern tree lambda_expr_this_capture (tree); +extern void maybe_add_lambda_conv_op (tree); /* in tree.c */ void cp_free_lang_data (tree t); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index ead3f33..33023a7 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10209,8 +10209,13 @@ grok_op_properties (tree decl, bool complain) || operator_code == ARRAY_REF || operator_code == NOP_EXPR) { - error ("%qD must be a nonstatic member function", decl); - return false; + if (class_type && LAMBDA_TYPE_P (class_type)) + /* Lambdas can have static op() and conv ops. */; + else + { + error ("%qD must be a nonstatic member function", decl); + return false; + } } else { diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index d4bcbac..874df74 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1309,7 +1309,7 @@ write_closure_type_name (const tree type) MANGLE_TRACE_TREE ("closure-type-name", type); write_string ("Ul"); - write_method_parms (parms, /*method_p=*/1, fn); + write_method_parms (parms, DECL_NONSTATIC_MEMBER_FUNCTION_P (fn), fn); write_char ('E'); write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda)); } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 7fd995f..2a0cc37 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7090,6 +7090,8 @@ cp_parser_lambda_expression (cp_parser* parser) LAMBDA_EXPR_CAPTURE_LIST (lambda_expr) = newlist; } + maybe_add_lambda_conv_op (type); + type = finish_struct (type, /*attributes=*/NULL_TREE); parser->num_template_parameter_lists = saved_num_template_parameter_lists; @@ -7347,15 +7349,25 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) declarator = make_id_declarator (NULL_TREE, ansi_opname (CALL_EXPR), sfk_none); - quals = (LAMBDA_EXPR_MUTABLE_P (lambda_expr) - ? TYPE_UNQUALIFIED : TYPE_QUAL_CONST); + quals = TYPE_UNQUALIFIED; + if (LAMBDA_EXPR_CAPTURE_LIST (lambda_expr) == NULL_TREE + && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) == CPLD_NONE) + { + /* A lambda with no captures has a static op() and a conversion op + to function type. */ + if (LAMBDA_EXPR_MUTABLE_P (lambda_expr)) + error ("lambda expression with no captures declared mutable"); + return_type_specs.storage_class = sc_static; + } + else if (!LAMBDA_EXPR_MUTABLE_P (lambda_expr)) + quals = 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); + declarator, + attributes); DECL_INITIALIZED_IN_CLASS_P (fco) = 1; DECL_ARTIFICIAL (fco) = 1; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 417c15f..e270a73 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2063,17 +2063,13 @@ finish_this_expr (void) { tree result; - if (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; - - } + /* In a lambda expression, 'this' refers to the captured 'this'. */ + if (current_function_decl + && LAMBDA_FUNCTION_P (current_function_decl)) + result = (lambda_expr_this_capture + (CLASSTYPE_LAMBDA_EXPR (current_class_type))); + else if (current_class_ptr) + result = current_class_ptr; else if (current_function_decl && DECL_STATIC_FUNCTION_P (current_function_decl)) { @@ -5759,4 +5755,55 @@ lambda_expr_this_capture (tree lambda) return result; } +/* If the closure TYPE has a static op(), also add a conversion to function + pointer. */ + +void +maybe_add_lambda_conv_op (tree type) +{ + bool nested = (current_function_decl != NULL_TREE); + tree callop = lambda_function (type); + tree rettype, name, fntype, fn, body, compound_stmt; + + if (!DECL_STATIC_FUNCTION_P (callop)) + return; + + rettype = build_pointer_type (TREE_TYPE (callop)); + name = mangle_conv_op_name_for_type (rettype); + fntype = build_function_type (rettype, void_list_node); + fn = build_lang_decl (FUNCTION_DECL, name, fntype); + DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); + + if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn + && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT) + DECL_ALIGN (fn) = 2 * BITS_PER_UNIT; + + SET_OVERLOADED_OPERATOR_CODE (fn, TYPE_EXPR); + grokclassfn (type, fn, NO_SPECIAL); + set_linkage_according_to_type (type, fn); + rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof); + DECL_IN_AGGR_P (fn) = 1; + DECL_ARTIFICIAL (fn) = 1; + DECL_NOT_REALLY_EXTERN (fn) = 1; + DECL_DECLARED_INLINE_P (fn) = 1; + DECL_STATIC_FUNCTION_P (fn) = 1; + + add_method (type, fn, NULL_TREE); + + if (nested) + push_function_context (); + start_preparsed_function (fn, NULL_TREE, + SF_PRE_PARSED | SF_INCLASS_INLINE); + body = begin_function_body (); + compound_stmt = begin_compound_stmt (0); + + finish_return_stmt (decay_conversion (callop)); + + finish_compound_stmt (compound_stmt); + finish_function_body (body); + + expand_or_defer_fn (finish_function (2)); + if (nested) + pop_function_context (); +} #include "gt-cp-semantics.h" diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7c29cdf..6b1d818 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2009-10-27 Jason Merrill <jason@redhat.com> + + * g++.dg/cpp0x/lambda/lambda-conv.C: New. + * g++.dg/cpp0x/lambda/lambda-const-neg.C: Adjust. + * g++.dg/cpp0x/lambda/lambda-mangle.C: Adjust. + * g++.dg/cpp0x/lambda/lambda-non-const.C: Adjust. + 2009-10-27 Eric Botcazou <ebotcazou@adacore.com> * gnat.dg/null_pointer_deref1.adb: Accept Constraint_Error. diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-neg.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-neg.C index f48c6c2..0e329e5 100644 --- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-neg.C +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-neg.C @@ -3,11 +3,11 @@ #include <cassert> template<typename F> -void call(const F& f) { f(); } // { dg-error "discards qualifiers" } +void call(const F& f) { f(); } int main() { call([] () -> void {}); - call([] () mutable -> void {}); // { dg-message "" "`f' does not have const `operator()'" } + call([] () mutable -> void {}); // { dg-message "" "declared mutable" } int i = -1; call([&i] () -> void { i = 0; }); diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv.C new file mode 100644 index 0000000..e308248 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv.C @@ -0,0 +1,6 @@ +// { dg-options -std=c++0x } + +int main() +{ + void (*pfn)() = []{}; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C index 9f7d5f3..aa7462b 100644 --- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C @@ -9,8 +9,8 @@ inline void g(int n) { // 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* *-*-mingw* *-*-cygwin } } } } } +// { dg-final { scan-assembler "_ZZ1giENUlvE_clEv" } } +// { dg-final { scan-assembler "weak\[ \t\]*_?_ZZ1giENUlvE_clEv" { target { ! { *-*-darwin* *-*-mingw* *-*-cygwin } } } } } algo([=]{return n+bef();}); // The captured entities do not participate in <lambda-sig> @@ -31,17 +31,17 @@ 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* *-*-mingw* *-*-cygwin } } } } } +// { dg-final { scan-assembler "_ZZN1S1fEiiEd0_NUlvE_clEv" } } +// { dg-final { scan-assembler "weak\[ \t\]*_?_ZZN1S1fEiiEd0_NUlvE_clEv" { target { ! { *-*-darwin* *-*-mingw* *-*-cygwin } } } } } []{return 1;}() // Type: ZN1S1fEiiEd0_UlvE0_ // Operator: _ZZN1S1fEiiEd0_NKUlvE0_clEv -// { dg-final { scan-assembler "_ZZN1S1fEiiEd0_NKUlvE0_clEv" } } +// { dg-final { scan-assembler "_ZZN1S1fEiiEd0_NUlvE0_clEv" } } + []{return 2;}(), int = // Type: ZN1S1fEiiEd_UlvE_ // Operator: _ZZN1S1fEiiEd_NKUlvE_clEv -// { dg-final { scan-assembler "_ZZN1S1fEiiEd_NKUlvE_clEv" } } +// { dg-final { scan-assembler "_ZZN1S1fEiiEd_NUlvE_clEv" } } []{return 3;}()); }; @@ -52,8 +52,8 @@ 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" { target { ! { *-*-mingw* *-*-cygwin } } } } } +// { dg-final { scan-assembler "_ZN1RIiE1xMUlvE_clEv" } } +// { dg-final { scan-assembler "weak\[ \t\]*_?_ZN1RIiE1xMUlvE_clEv" { target { ! { *-*-mingw* *-*-cygwin } } } } } void bar() { @@ -63,7 +63,7 @@ void bar() } // 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\]*_ZNUlv" } } // { dg-final { scan-assembler-not "weak\[^\n\r\]*variable" } } int variable = []{return 1;}(); diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-non-const.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-non-const.C index 9c2b119..9ff8c02 100644 --- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-non-const.C +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-non-const.C @@ -8,7 +8,6 @@ void call(F f) { f(); } int main() { call([] () -> void {}); - call([] () mutable -> void {}); int i = -1; call([i] () mutable -> void { i = 0; }); |