finish_this_expr needs to be prepared for lambda_expr_this_capture to
return NULL_TREE.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit c631290819f1ab3754041c46d351745953fb8319
Author: Jason Merrill <ja...@redhat.com>
Date: Mon Oct 20 09:56:35 2014 -0400
PR c++/63601
* lambda.c (current_nonlambda_function): New.
* semantics.c (finish_this_expr): Use it.
* cp-tree.h: Declare it.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b6afc31..0923d9f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5961,6 +5961,7 @@ extern bool is_normal_capture_proxy (tree);
extern void register_capture_members (tree);
extern tree lambda_expr_this_capture (tree, bool);
extern tree maybe_resolve_dummy (tree, bool);
+extern tree current_nonlambda_function (void);
extern tree nonlambda_method_basetype (void);
extern void maybe_add_lambda_conv_op (tree);
extern bool is_lambda_ignored_entity (tree);
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 17fd037..d4030e3 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -777,6 +777,17 @@ maybe_resolve_dummy (tree object, bool add_capture_p)
return object;
}
+/* Returns the innermost non-lambda function. */
+
+tree
+current_nonlambda_function (void)
+{
+ tree fn = current_function_decl;
+ while (fn && LAMBDA_FUNCTION_P (fn))
+ fn = decl_function_context (fn);
+ return fn;
+}
+
/* Returns the method basetype of the innermost non-lambda function, or
NULL_TREE if none. */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 0e675a3..26e66f5 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2438,7 +2438,7 @@ finish_increment_expr (tree expr, enum tree_code code)
tree
finish_this_expr (void)
{
- tree result;
+ tree result = NULL_TREE;
if (current_class_ptr)
{
@@ -2450,25 +2450,19 @@ finish_this_expr (void)
else
result = current_class_ptr;
}
- else if (current_function_decl
- && DECL_STATIC_FUNCTION_P (current_function_decl))
- {
- error ("%<this%> is unavailable for static member functions");
- result = error_mark_node;
- }
+
+ if (result)
+ /* The keyword 'this' is a prvalue expression. */
+ return rvalue (result);
+
+ tree fn = current_nonlambda_function ();
+ if (fn && DECL_STATIC_FUNCTION_P (fn))
+ error ("%<this%> is unavailable for static member functions");
+ else if (fn)
+ error ("invalid use of %<this%> in non-member function");
else
- {
- if (current_function_decl)
- error ("invalid use of %<this%> in non-member function");
- else
- error ("invalid use of %<this%> at top level");
- result = error_mark_node;
- }
-
- /* The keyword 'this' is a prvalue expression. */
- result = rvalue (result);
-
- return result;
+ error ("invalid use of %<this%> at top level");
+ return error_mark_node;
}
/* Finish a pseudo-destructor expression. If SCOPE is NULL, the
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this20.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this20.C
new file mode 100644
index 0000000..0d27320
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this20.C
@@ -0,0 +1,4 @@
+// PR c++/63601
+// { dg-do compile { target c++11 } }
+
+auto f = []{ sizeof(this); }; // { dg-error "this" }