From a684685337dc14afc172c7e2172b40d65dd4fa7b Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 27 Apr 2010 17:26:25 -0400 Subject: re PR c++/43856 ([C++0x] gcc-4.5.0 fails to transform id-expression into class member access in lambda compound-statement) PR c++/43856 * name-lookup.c (qualify_lookup): Disqualify lambda op(). * class.c (current_nonlambda_class_type): New fn. * semantics.c (nonlambda_method_basetype): New. * cp-tree.h: Declare them. * tree.c (maybe_dummy_object): Handle implicit 'this' capture. From-SVN: r158807 --- gcc/cp/ChangeLog | 7 ++++++ gcc/cp/class.c | 28 ++++++++++++++++++++++++ gcc/cp/cp-tree.h | 2 ++ gcc/cp/name-lookup.c | 4 ++++ gcc/cp/semantics.c | 26 ++++++++++++++++++++++ gcc/cp/tree.c | 15 +++++++++---- gcc/testsuite/ChangeLog | 3 +++ gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this2.C | 16 ++++++++++++++ 8 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this2.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d0a112c..4dd3df4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,12 @@ 2010-04-27 Jason Merrill + PR c++/43856 + * name-lookup.c (qualify_lookup): Disqualify lambda op(). + * class.c (current_nonlambda_class_type): New fn. + * semantics.c (nonlambda_method_basetype): New. + * cp-tree.h: Declare them. + * tree.c (maybe_dummy_object): Handle implicit 'this' capture. + * semantics.c (baselink_for_fns): Correct BASELINK_BINFO. PR c++/43875 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 07dfb1c..c640af4 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5971,6 +5971,34 @@ currently_open_derived_class (tree t) return NULL_TREE; } +/* Returns the innermost class type which is not a lambda closure type. */ + +tree +current_nonlambda_class_type (void) +{ + int i; + + /* We start looking from 1 because entry 0 is from global scope, + and has no type. */ + for (i = current_class_depth; i > 0; --i) + { + tree c; + if (i == current_class_depth) + c = current_class_type; + else + { + if (current_class_stack[i].hidden) + break; + c = current_class_stack[i].type; + } + if (!c) + continue; + if (!LAMBDA_TYPE_P (c)) + return c; + } + return NULL_TREE; +} + /* When entering a class scope, all enclosing class scopes' names with static meaning (static variables, static functions, types and enumerators) have to be visible. This recursive function calls diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index dd89171..62e92cc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4580,6 +4580,7 @@ extern void resort_type_method_vec (void *, void *, extern bool add_method (tree, tree, tree); extern bool currently_open_class (tree); extern tree currently_open_derived_class (tree); +extern tree current_nonlambda_class_type (void); extern tree finish_struct (tree, tree); extern void finish_struct_1 (tree); extern int resolves_to_fixed_type_p (tree, int *); @@ -5212,6 +5213,7 @@ extern tree add_capture (tree, tree, tree, bool, bool); extern tree add_default_capture (tree, tree, tree); extern void register_capture_members (tree); extern tree lambda_expr_this_capture (tree); +extern tree nonlambda_method_basetype (void); extern void maybe_add_lambda_conv_op (tree); /* in tree.c */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index b4ac49f..5586bf7 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3807,6 +3807,10 @@ qualify_lookup (tree val, int flags) if (cp_unevaluated_operand && TREE_CODE (val) == FIELD_DECL && DECL_NORMAL_CAPTURE_P (val)) return false; + /* None of the lookups that use qualify_lookup want the op() from the + lambda; they want the one from the enclosing class. */ + if (TREE_CODE (val) == FUNCTION_DECL && LAMBDA_FUNCTION_P (val)) + return false; return true; } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 6bf33c7..7c03959 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5869,6 +5869,32 @@ lambda_expr_this_capture (tree lambda) return result; } +/* Returns the method basetype of the innermost non-lambda function, or + NULL_TREE if none. */ + +tree +nonlambda_method_basetype (void) +{ + tree fn, type; + if (!current_class_ref) + return NULL_TREE; + + type = current_class_type; + if (!LAMBDA_TYPE_P (type)) + return type; + + /* Find the nearest enclosing non-lambda function. */ + fn = TYPE_NAME (type); + do + fn = decl_function_context (fn); + while (fn && LAMBDA_FUNCTION_P (fn)); + + if (!fn || !DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + return NULL_TREE; + + return TYPE_METHOD_BASETYPE (TREE_TYPE (fn)); +} + /* If the closure TYPE has a static op(), also add a conversion to function pointer. */ diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 0abc12c..f8b2c40 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2293,11 +2293,11 @@ maybe_dummy_object (tree type, tree* binfop) { tree decl, context; tree binfo; + tree current = current_nonlambda_class_type (); - if (current_class_type - && (binfo = lookup_base (current_class_type, type, - ba_unique | ba_quiet, NULL))) - context = current_class_type; + if (current + && (binfo = lookup_base (current, type, ba_any, NULL))) + context = current; else { /* Reference from a nested class member function. */ @@ -2315,6 +2315,13 @@ maybe_dummy_object (tree type, tree* binfop) && same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)), current_class_type)) decl = current_class_ref; + else if (current != current_class_type + && context == nonlambda_method_basetype ()) + /* In a lambda, need to go through 'this' capture. */ + decl = (cp_build_indirect_ref + ((lambda_expr_this_capture + (CLASSTYPE_LAMBDA_EXPR (current_class_type))), + RO_NULL, tf_warning_or_error)); else decl = build_dummy_object (context); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0746e59..37f201a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2010-04-27 Jason Merrill + PR c++/43856 + * g++.dg/cpp0x/lambda/lambda-this2.C: New. + PR c++/43875 * g++.dg/cpp0x/lambda/lambda-deduce2.C: New. diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this2.C new file mode 100644 index 0000000..ce4bda4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this2.C @@ -0,0 +1,16 @@ +// PR c++/43856 +// Test for implicit 'this' capture via rewriting. +// { dg-options "-std=c++0x" } + +struct S1 { + int operator()(int); + int i; + void g(); + void f() { + [=]() { + i; + g(); + operator()(42); + }; + } +}; -- cgit v1.1