The failure in this testcase was happening because we were trying to
evaluate the capture decltype again when instantiating the lambda
operator(), but it only works when we're still in the enclosing function
context. Fixed by basically waiting to copy the type over at
instantiation time rather than copy the dependent type at template
definition time.
Tested x86_64-pc-linux-gnu, applied to trunk.
commit 7493431b3a7c540254aa92cd0e8ea873eace94f8
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Jun 29 11:55:58 2011 -0400
PR c++/49554
* semantics.c (lambda_proxy_type): New.
(build_capture_proxy): Use it.
* cp-tree.h (DECLTYPE_FOR_LAMBDA_PROXY): New.
* pt.c (tsubst) [DECLTYPE_TYPE]: Use them.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7244cc8..55c88e3 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3418,11 +3418,13 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
/* These flags indicate that we want different semantics from normal
decltype: lambda capture just drops references, lambda return also does
- type decay. */
+ type decay, lambda proxies look through implicit dereference. */
#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))
+#define DECLTYPE_FOR_LAMBDA_PROXY(NODE) \
+ TREE_LANG_FLAG_2 (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
@@ -5455,6 +5457,7 @@ 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_proxy_type (tree);
extern tree lambda_function (tree);
extern void apply_lambda_return_type (tree, tree);
extern tree add_capture (tree, tree, tree, bool, bool);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b3dd85f..d1d8336 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11108,6 +11108,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
type = lambda_capture_field_type (type);
else if (DECLTYPE_FOR_LAMBDA_RETURN (t))
type = lambda_return_type (type);
+ else if (DECLTYPE_FOR_LAMBDA_PROXY (t))
+ type = lambda_proxy_type (type);
else
type = finish_decltype_type
(type, DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t), complain);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 4581729..fb984d4 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -8489,6 +8489,27 @@ insert_pending_capture_proxies (void)
LAMBDA_EXPR_PENDING_PROXIES (lam) = NULL;
}
+/* Given REF, a COMPONENT_REF designating a field in the lambda closure,
+ return the type we want the proxy to have: the type of the field itself,
+ with added const-qualification if the lambda isn't mutable and the
+ capture is by value. */
+
+tree
+lambda_proxy_type (tree ref)
+{
+ tree type;
+ if (REFERENCE_REF_P (ref))
+ ref = TREE_OPERAND (ref, 0);
+ type = TREE_TYPE (ref);
+ if (!dependent_type_p (type))
+ return type;
+ type = cxx_make_type (DECLTYPE_TYPE);
+ DECLTYPE_TYPE_EXPR (type) = ref;
+ DECLTYPE_FOR_LAMBDA_PROXY (type) = true;
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
+ return type;
+}
+
/* MEMBER is a capture field in a lambda closure class. Now that we're
inside the operator(), build a placeholder var for future lookups and
debugging. */
@@ -8496,7 +8517,7 @@ insert_pending_capture_proxies (void)
tree
build_capture_proxy (tree member)
{
- tree var, object, fn, closure, name, lam;
+ tree var, object, fn, closure, name, lam, type;
closure = DECL_CONTEXT (member);
fn = lambda_function (closure);
@@ -8511,7 +8532,8 @@ build_capture_proxy (tree member)
/* Remove the __ inserted by add_capture. */
name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
- var = build_decl (input_location, VAR_DECL, name, TREE_TYPE (object));
+ type = lambda_proxy_type (object);
+ var = build_decl (input_location, VAR_DECL, name, type);
SET_DECL_VALUE_EXPR (var, object);
DECL_HAS_VALUE_EXPR_P (var) = 1;
DECL_ARTIFICIAL (var) = 1;
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template3.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template3.C
new file mode 100644
index 0000000..fd6f1d3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template3.C
@@ -0,0 +1,33 @@
+// PR c++/49554
+// { dg-options -std=c++0x }
+
+template<typename T>
+ struct base
+ {
+ struct iterator { };
+
+ iterator begin();
+ };
+
+template<typename T>
+class flist : public base<T>
+{
+ typedef base<T> Base;
+
+ typedef typename Base::iterator Base_iterator;
+public:
+
+ void
+ resize()
+ {
+ Base_iterator b = Base::begin();
+
+ [b](int i) { return i; };
+ }
+};
+
+void test01()
+{
+ flist<int> fl;
+ fl.resize();
+}