Patchwork C++ PATCH for c++/49554 (bogus error with lambda in template)

login
register
mail settings
Submitter Jason Merrill
Date June 29, 2011, 5:24 p.m.
Message ID <4E0B5FD9.7090002@redhat.com>
Download mbox | patch
Permalink /patch/102644/
State New
Headers show

Comments

Jason Merrill - June 29, 2011, 5:24 p.m.
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.

Patch

commit 7493431b3a7c540254aa92cd0e8ea873eace94f8
Author: Jason Merrill <jason@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();
+}