public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++14/lambda] Experimental polymorphic lambda patches
@ 2013-07-01 23:27 Adam Butcher
  2013-07-01 23:27 ` [PATCH 4/4] [lambda] [polymorphic] [HACK] Avoid crash on symbol table writing when generic lambda declared with iostream (or potentially other code) included Adam Butcher
                   ` (6 more replies)
  0 siblings, 7 replies; 39+ messages in thread
From: Adam Butcher @ 2013-07-01 23:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill, Adam Butcher

Hi all,

I've finally reworked the generic lambda patches I made back in 2009
(http://gcc.1065356.n5.nabble.com/lambda-Latest-experimental-polymorphic-lambda-patches-tt713016.html)
to apply against GCC's mainline.

The syntaxes demonstrated by the following examples are supported (as
per the previous incarnation) implementing parts of N3559 and N3560.

  1.  [] (auto x, auto& y, auto const& z) { return x + y + z; } 
  2.  [] <typename X, typename Y, typename Z> (X x, Y& y, Z const& z) { return x + y + z; } 
  3.  [] <typename Y> (auto x, Y& y, auto const& z) { return x + y + z; } 

Missing features:

 - Conversion to function pointer of stateless generic lambdas is
   currently unsupported.  Currently a warning is generated for all
   such lambdas at their definition.

Other issues: (see XXX, FIXME, TODO)

  a)  Location of implementation.
  b)  What to do about name mangling?
  c)  Figure out why symtab contains nullptrs.  Maybe related to (b).
  d)  Not behind any -std option.  Should require -std=c++1y or
      -std=gnu++1y.
  e)  Should collect 'auto' parameters during parse and realloc
      template parameter list once at the end of the parameter list
      rather than incrementally.

Any comments appreciated.  Guidance on implementing the conversion
operator for stateless generic lambdas would be useful.  I've made a
few attempts which were lacking!

Cheers,
Adam

Patch summary: (4):
  [lambda] [polymorphic] Support template-parameter-list in
    lambda-declarator.
  [lambda] [polymorphic] Support generic lambdas in templates.
  [lambda] [polymorphic] Infer template parameter from auto used in
    function parameter list.
  [lambda] [polymorphic] [HACK] Avoid crash on symbol table writing when
    generic lambda declared with iostream (or potentially other code)
    included.

 gcc/cp/decl.c      |   1 +
 gcc/cp/mangle.c    |   2 +
 gcc/cp/parser.c    | 246 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 gcc/cp/pt.c        |  10 +++
 gcc/cp/semantics.c |  10 ++-
 gcc/symtab.c       |  18 ++++
 6 files changed, 279 insertions(+), 8 deletions(-)

-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 1/4] [lambda] [polymorphic] Support template-parameter-list in lambda-declarator.
  2013-07-01 23:27 [C++14/lambda] Experimental polymorphic lambda patches Adam Butcher
  2013-07-01 23:27 ` [PATCH 4/4] [lambda] [polymorphic] [HACK] Avoid crash on symbol table writing when generic lambda declared with iostream (or potentially other code) included Adam Butcher
@ 2013-07-01 23:27 ` Adam Butcher
  2013-07-01 23:27 ` [PATCH 2/4] [lambda] [polymorphic] Support generic lambdas in templates Adam Butcher
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 39+ messages in thread
From: Adam Butcher @ 2013-07-01 23:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill, Adam Butcher

---
 gcc/cp/mangle.c    |  2 ++
 gcc/cp/parser.c    | 43 +++++++++++++++++++++++++++++++++++++++++--
 gcc/cp/semantics.c | 10 +++++++++-
 3 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 8da62b5..4d4c0fd 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -1438,6 +1438,8 @@ write_closure_type_name (const tree type)
   MANGLE_TRACE_TREE ("closure-type-name", type);
 
   write_string ("Ul");
+  if (TREE_CODE (fn) == TEMPLATE_DECL) // XXX: should we bother mangling generic lambdas?
+    fn = DECL_TEMPLATE_RESULT (fn);
   write_method_parms (parms, /*method_p=*/1, fn);
   write_char ('E');
   write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda));
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 6e8293b..d0867c7 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8783,6 +8783,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
 /* Parse the (optional) middle of a lambda expression.
 
    lambda-declarator:
+     < template-parameter-list [opt] >
      ( parameter-declaration-clause [opt] )
        attribute-specifier [opt]
        mutable [opt]
@@ -8802,10 +8803,26 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
   tree param_list = void_list_node;
   tree attributes = NULL_TREE;
   tree exception_spec = NULL_TREE;
+  tree template_param_list = NULL_TREE;
   tree t;
 
-  /* The lambda-declarator is optional, but must begin with an opening
-     parenthesis if present.  */
+  /* The template-parameter-list is optional, but must begin with
+     an opening angle if present.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+    {
+      cp_lexer_consume_token (parser->lexer);
+
+      template_param_list = cp_parser_template_parameter_list (parser);
+
+      cp_parser_skip_to_end_of_template_parameter_list (parser);
+
+      /* We just processed one more parameter list.  */
+      ++parser->num_template_parameter_lists;
+    }
+
+  /* The parameter-declaration-clause is optional (unless
+     template-parameter-list was given), but must begin with an
+     opening parenthesis if present.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
     {
       cp_lexer_consume_token (parser->lexer);
@@ -8851,6 +8868,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 
       leave_scope ();
     }
+  else if (template_param_list != NULL_TREE) // generate diagnostic
+    cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
 
   /* Create the function call operator.
 
@@ -8894,6 +8913,23 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 	DECL_ARTIFICIAL (fco) = 1;
 	/* Give the object parameter a different name.  */
 	DECL_NAME (DECL_ARGUMENTS (fco)) = get_identifier ("__closure");
+	if (template_param_list != NULL_TREE)
+	  {
+	    tree saved_current_function_decl = current_function_decl;
+
+	    /* Clear current function decl to allow check_member_template
+	       to pass.  Currently it rejects templates inside functions.
+	       Couldn't figure out a clean way to test for lambda inside
+	       check_member_template.  */
+	    current_function_decl = NULL_TREE;
+	    fco = finish_member_template_decl (fco);
+	    current_function_decl = saved_current_function_decl;
+
+	    --parser->num_template_parameter_lists;
+
+	    finish_template_decl (template_param_list);
+
+	  }
       }
 
     finish_member_declaration (fco);
@@ -8937,6 +8973,9 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
     tree compound_stmt;
     tree cap;
 
+    if (TREE_CODE (fco) == TEMPLATE_DECL)
+      fco = DECL_TEMPLATE_RESULT (fco);
+
     /* Let the front end know that we are going to be defining this
        function.  */
     start_preparsed_function (fco,
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index f821754..792c385 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -9146,7 +9146,7 @@ lambda_function (tree lambda)
 			  /*protect=*/0, /*want_type=*/false,
 			  tf_warning_or_error);
   if (lambda)
-    lambda = BASELINK_FUNCTIONS (lambda);
+    lambda = OVL_CURRENT (BASELINK_FUNCTIONS (lambda));
   return lambda;
 }
 
@@ -9392,6 +9392,8 @@ build_capture_proxy (tree member)
 
   closure = DECL_CONTEXT (member);
   fn = lambda_function (closure);
+  if (TREE_CODE (fn) == TEMPLATE_DECL)
+    fn = DECL_TEMPLATE_RESULT (fn);
   lam = CLASSTYPE_LAMBDA_EXPR (closure);
 
   /* The proxy variable forwards to the capture field.  */
@@ -9808,6 +9810,12 @@ maybe_add_lambda_conv_op (tree type)
   if (processing_template_decl)
     return;
 
+  if (TREE_CODE (callop) == TEMPLATE_DECL)
+    {
+      warning (0, "Conversion of a generic lambda to a function pointer is not currently implemented.");
+      return;
+    }
+
   if (DECL_INITIAL (callop) == NULL_TREE)
     {
       /* If the op() wasn't instantiated due to errors, give up.  */
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 2/4] [lambda] [polymorphic] Support generic lambdas in templates.
  2013-07-01 23:27 [C++14/lambda] Experimental polymorphic lambda patches Adam Butcher
  2013-07-01 23:27 ` [PATCH 4/4] [lambda] [polymorphic] [HACK] Avoid crash on symbol table writing when generic lambda declared with iostream (or potentially other code) included Adam Butcher
  2013-07-01 23:27 ` [PATCH 1/4] [lambda] [polymorphic] Support template-parameter-list in lambda-declarator Adam Butcher
@ 2013-07-01 23:27 ` Adam Butcher
  2013-07-01 23:27 ` [PATCH 3/4] [lambda] [polymorphic] Infer template parameter from auto used in function parameter list Adam Butcher
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 39+ messages in thread
From: Adam Butcher @ 2013-07-01 23:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill, Adam Butcher

---
 gcc/cp/pt.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3847a1d..fbdd8ec6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -18847,6 +18847,9 @@ instantiate_decl (tree d, int defer_ok,
   tree fn_context;
   bool nested;
 
+  if (TREE_CODE (d) == TEMPLATE_DECL)
+    return d;
+
   /* This function should only be used to instantiate templates for
      functions and static member variables.  */
   gcc_assert (VAR_OR_FUNCTION_DECL_P (d));
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 3/4] [lambda] [polymorphic] Infer template parameter from auto used in function parameter list.
  2013-07-01 23:27 [C++14/lambda] Experimental polymorphic lambda patches Adam Butcher
                   ` (2 preceding siblings ...)
  2013-07-01 23:27 ` [PATCH 2/4] [lambda] [polymorphic] Support generic lambdas in templates Adam Butcher
@ 2013-07-01 23:27 ` Adam Butcher
  2013-07-02  0:01 ` [PATCH] [debug] Added DEBUG_FUNCTION void dump_backtrace Adam Butcher
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 39+ messages in thread
From: Adam Butcher @ 2013-07-01 23:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill, Adam Butcher

---
 gcc/cp/decl.c   |   1 +
 gcc/cp/parser.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 gcc/cp/pt.c     |   7 ++
 3 files changed, 206 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 047fd77..00bcc35 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10331,6 +10331,7 @@ grokdeclarator (const cp_declarator *declarator,
 	{
 	  error ("parameter declared %<auto%>");
 	  type = error_mark_node;
+	  dump_backtrace ();
 	}
 
       /* A parameter declared as an array of T is really a pointer to T.
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d0867c7..3bab09e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8780,6 +8780,178 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
   cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
 }
 
+/* The struct auto_parm_handler_t defines an interface for customizing
+   the behaviour when a C++11 `auto' type is found as the primary type
+   specifier of a function parameter declaration.
+   If auto_parm_handler is set whilst parsing a function parameter
+   list, the function auto_parm_handler->hook will be called for each
+   parameter having `auto' as its primary type; in each case the
+   result of the hook will be used to replace `auto' as the primary
+   type.  */
+typedef struct auto_parm_handler_t auto_parm_handler_t;
+typedef tree (*auto_parm_hook_t) (auto_parm_handler_t*);
+struct auto_parm_handler_t
+{
+   auto_parm_hook_t hook;
+};
+/* Set to a structure that provides the above interface to be called
+   if a type containing `auto' is found during
+   cp_parser_parameter_declaration_list.  */
+auto_parm_handler_t* auto_parm_handler = 0;
+
+/* Handler state for processing `auto' found in lambda function call
+   parameter list.  Supports implicit polymorphic lambdas.  */
+typedef struct lambda_auto_handler_t
+{
+  auto_parm_hook_t hook;
+  tree* template_param_list;
+  vec<deferred_access_check, va_gc> *checks;
+  cp_parser* parser;
+  int i;
+}
+lambda_auto_handler_t;
+
+/* FIXME: Much of this would appear to fit better in pt.c.  */
+
+/* FIXME: It would also mean the copied function
+          build_template_parm_index and rudely extern'd
+          x_canonical_type_parameter would be unnecessary.  */
+
+tree lambda_parameter_make_auto_type_name
+  (lambda_auto_handler_t*);
+tree lambda_auto_handler
+  (lambda_auto_handler_t*);
+
+tree
+lambda_parameter_make_auto_type_name (lambda_auto_handler_t* handler)
+{
+  char buf[32];
+  sprintf (buf, "__AutoT%d", ++handler->i);
+  return get_identifier (buf);
+}
+
+/* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL,
+   ORIG_LEVEL, DECL, and TYPE.
+   FIXME: Remove this copy from here; i.e. probably move rest into
+          pt.c.  */
+
+static tree
+build_template_parm_index (int index,
+			   int level,
+			   int orig_level,
+			   tree decl,
+			   tree type)
+{
+  tree t = make_node (TEMPLATE_PARM_INDEX);
+  TEMPLATE_PARM_IDX (t) = index;
+  TEMPLATE_PARM_LEVEL (t) = level;
+  TEMPLATE_PARM_ORIG_LEVEL (t) = orig_level;
+  TEMPLATE_PARM_DECL (t) = decl;
+  TREE_TYPE (t) = type;
+  TREE_CONSTANT (t) = TREE_CONSTANT (decl);
+  TREE_READONLY (t) = TREE_READONLY (decl);
+
+  return t;
+}
+
+tree
+lambda_auto_handler (lambda_auto_handler_t* handler)
+{
+  struct cp_binding_level* scope = current_binding_level;
+
+  /* FIXME: should use location of this 'auto' token. (maybe store on HANDLER?) */
+  location_t param_loc = cp_lexer_peek_token (handler->parser->lexer)->location;
+
+  /* First auto parameter may need to start a template parameter list.  */
+  bool become_template = *handler->template_param_list == NULL_TREE;
+
+  tree synth_id = lambda_parameter_make_auto_type_name (handler);
+  tree synth_tmpl_parm = finish_template_type_parm (class_type_node, synth_id);
+  synth_tmpl_parm = build_tree_list (NULL_TREE, synth_tmpl_parm);
+
+  if (become_template)
+    {
+      /* do something rude and pretend that the template parameter
+	 scope surrounds the function definition.  */
+      current_binding_level = current_binding_level->level_chain;
+
+      /*if (ENABLE_SCOPE_CHECKING)
+	--binding_depth;*/
+
+      push_deferring_access_checks (dk_deferred);
+      begin_template_parm_list ();
+    }
+
+  synth_tmpl_parm = process_template_parm (0,
+				       param_loc,
+				       synth_tmpl_parm,
+				       /*non_type=*/false,
+				       /*param_pack=*/false);
+
+  /* Re-index based on last existing parameter.  */
+  if (!become_template)
+    {
+      tree old = *handler->template_param_list;
+      size_t len = TREE_VEC_LENGTH (old);
+      size_t idx;
+      extern tree x_canonical_type_parameter (tree);
+
+      tree p = TREE_VALUE (TREE_VEC_ELT (old, --len));
+      if (TREE_CODE (p) == TYPE_DECL || TREE_CODE (p) == TEMPLATE_DECL)
+	idx = TEMPLATE_TYPE_IDX (TREE_TYPE (p));
+      else
+	idx = TEMPLATE_PARM_IDX (DECL_INITIAL (p));
+
+      ++idx;
+
+      TEMPLATE_TYPE_PARM_INDEX (TREE_TYPE (synth_id))
+	= build_template_parm_index (idx, processing_template_decl,
+				     processing_template_decl,
+				     TYPE_NAME (TREE_TYPE (synth_id)),
+				     TREE_TYPE (synth_id));
+      TYPE_CANONICAL (TREE_TYPE (synth_id)) = x_canonical_type_parameter (TREE_TYPE (synth_id));
+    }
+
+  if (become_template)
+    {
+      /* Initial template parameter, create new list.  */
+      *handler->template_param_list = end_template_parm_list (synth_tmpl_parm);
+      ++handler->parser->num_template_parameter_lists;
+      push_deferring_access_checks (dk_no_check);
+      push_binding_level (scope);
+    }
+  else /* Add to existing template parameter list.  */
+    {
+      tree old = *handler->template_param_list;
+      tree new_vec;
+      size_t len;
+
+      gcc_assert (TREE_CODE (old) == TREE_VEC);
+
+      len = TREE_VEC_LENGTH (old);
+
+      // FIXME: TODO: Store up 'auto' template parameters in HANDLER
+      // FIXME: TODO: and realloc actual template list once.  For now
+      // FIXME: TODO: just grow list by one each time.
+      new_vec = make_tree_vec (len+1);
+      {
+	size_t n;
+	for (n = 0; n != len; ++n)
+	  TREE_VEC_ELT (new_vec, n) = TREE_VEC_ELT (old, n);
+      }
+      TREE_VEC_ELT (new_vec, len) = synth_tmpl_parm;
+
+      ggc_free (old);
+
+      *handler->template_param_list = new_vec;
+
+      TREE_VALUE (current_template_parms) = new_vec;
+    }
+
+  /* Return synthesized type as a substitute for `auto'. */
+  return TREE_TYPE (synth_id);
+}
+
 /* Parse the (optional) middle of a lambda expression.
 
    lambda-declarator:
@@ -8829,6 +9001,15 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 
       begin_scope (sk_function_parms, /*entity=*/NULL_TREE);
 
+      /* Set up handler for auto being used in function parameter list.  */
+      lambda_auto_handler_t auto_handler;
+      auto_handler.hook = (auto_parm_hook_t) lambda_auto_handler;
+      auto_handler.template_param_list = &template_param_list;
+      auto_handler.checks = 0;
+      auto_handler.parser = parser;
+      auto_handler.i = 0;
+      auto_parm_handler = (auto_parm_handler_t*) &auto_handler;
+
       /* Parse parameters.  */
       param_list = cp_parser_parameter_declaration_clause (parser);
 
@@ -8839,6 +9020,9 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 	  pedwarn (DECL_SOURCE_LOCATION (TREE_VALUE (t)), OPT_Wpedantic,
 		   "default argument specified for lambda parameter");
 
+      /* TODO: copy auto_handler.checks out */
+      auto_parm_handler = 0;
+
       cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
 
       attributes = cp_parser_attributes_opt (parser);
@@ -17915,11 +18099,20 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
       deprecated_state = DEPRECATED_SUPPRESS;
 
       if (parameter)
-	decl = grokdeclarator (parameter->declarator,
-			       &parameter->decl_specifiers,
-			       PARM,
-			       parameter->default_argument != NULL_TREE,
-			       &parameter->decl_specifiers.attributes);
+	{
+	  /* If there is a custom `auto' handler and the primary type
+	     of this parameter is `auto', then invoke the hook and
+	     replace `auto' with the result. */
+	  if (auto_parm_handler && is_auto (parameter->decl_specifiers.type))
+	    {
+	      parameter->decl_specifiers.type = auto_parm_handler->hook (auto_parm_handler);
+	    }
+	  decl = grokdeclarator (parameter->declarator,
+				 &parameter->decl_specifiers,
+				 PARM,
+				 parameter->default_argument != NULL_TREE,
+				 &parameter->decl_specifiers.attributes);
+	}
 
       deprecated_state = DEPRECATED_NORMAL;
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index fbdd8ec6..8ed7aab 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3545,6 +3545,13 @@ canonical_type_parameter (tree type)
     }
 }
 
+/* FIXME: Cleanup this mess */
+tree x_canonical_type_parameter (tree type);
+tree x_canonical_type_parameter (tree type)
+{
+  return canonical_type_parameter (type);
+}
+
 /* Return a TEMPLATE_PARM_INDEX, similar to INDEX, but whose
    TEMPLATE_PARM_LEVEL has been decreased by LEVELS.  If such a
    TEMPLATE_PARM_INDEX already exists, it is returned; otherwise, a
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 4/4] [lambda] [polymorphic] [HACK] Avoid crash on symbol table writing when generic lambda declared with iostream (or potentially other code) included.
  2013-07-01 23:27 [C++14/lambda] Experimental polymorphic lambda patches Adam Butcher
@ 2013-07-01 23:27 ` Adam Butcher
  2013-07-01 23:27 ` [PATCH 1/4] [lambda] [polymorphic] Support template-parameter-list in lambda-declarator Adam Butcher
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 39+ messages in thread
From: Adam Butcher @ 2013-07-01 23:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill, Adam Butcher

---
 gcc/symtab.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/gcc/symtab.c b/gcc/symtab.c
index 85d47a8..1ada0f7 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -116,6 +116,15 @@ insert_to_assembler_name_hash (symtab_node node, bool with_clones)
 
       tree name = DECL_ASSEMBLER_NAME (node->symbol.decl);
 
+
+      // FIXME: how does this nullptr get here when declaring a C++
+      // FIXME: generic lambda and including iostream (or presumably
+      // FIXME: any other header with whatever property is triggering
+      // FIXME: this)!?
+      //
+      if (name == 0)
+	return;
+
       aslot = htab_find_slot_with_hash (assembler_name_hash, name,
 					decl_assembler_name_hash (name),
 					INSERT);
@@ -156,6 +165,15 @@ unlink_from_assembler_name_hash (symtab_node node, bool with_clones)
       else
 	{
 	  tree name = DECL_ASSEMBLER_NAME (node->symbol.decl);
+
+	  // FIXME: how does this nullptr get here when declaring a C++
+	  // FIXME: generic lambda and including iostream (or presumably
+	  // FIXME: any other header with whatever property is triggering
+	  // FIXME: this)!?
+	  //
+	  if (name == 0)
+	    return;
+
           void **slot;
 	  slot = htab_find_slot_with_hash (assembler_name_hash, name,
 					   decl_assembler_name_hash (name),
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH] [debug] Added DEBUG_FUNCTION void dump_backtrace.
  2013-07-01 23:27 [C++14/lambda] Experimental polymorphic lambda patches Adam Butcher
                   ` (3 preceding siblings ...)
  2013-07-01 23:27 ` [PATCH 3/4] [lambda] [polymorphic] Infer template parameter from auto used in function parameter list Adam Butcher
@ 2013-07-02  0:01 ` Adam Butcher
  2013-07-11 17:35 ` [C++14/lambda] Experimental polymorphic lambda patches Jason Merrill
  2013-08-03 18:38 ` [C++14/lambda] Experimental polymorphic lambda patches Paolo Carlini
  6 siblings, 0 replies; 39+ messages in thread
From: Adam Butcher @ 2013-07-02  0:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill, Adam Butcher

	* diagnostic-core.h: Declare dump_backtrace (void).
	* diagnostic.c: Define it.

---
Just realized that I've submitted an unintended hunk in [PATCH 3/4]
(http://gcc.gnu.org/ml/gcc-patches/2013-07/msg00042.html).  I didn't
notice that I'd left a tracing line in 'gcc/cp/decl.c'.  This patch
resolves the missing function.  Or you can just skip that change.

I've found this a useful tool when hacking on GCC before I found out
about '-wrapper gdb,--args'.  I cherry-pick it whenever I want to find
out where something is called without stopping the compiler.  Don't
know if any one else would find use in it.

Cheers,
Adam



 gcc/diagnostic-core.h |  1 +
 gcc/diagnostic.c      | 13 +++++++++++++
 2 files changed, 14 insertions(+)

diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h
index a210782..e204340 100644
--- a/gcc/diagnostic-core.h
+++ b/gcc/diagnostic-core.h
@@ -78,6 +78,7 @@ extern void verbatim (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
 extern bool emit_diagnostic (diagnostic_t, location_t, int,
 			     const char *, ...) ATTRIBUTE_GCC_DIAG(4,5);
 extern bool seen_error (void);
+extern void dump_backtrace (void);
 
 #ifdef BUFSIZ
   /* N.B. Unlike all the others, fnotice is just gettext+fprintf, and
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 2ec9620..0f12a38 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -1111,6 +1111,19 @@ fatal_error (const char *gmsgid, ...)
   gcc_unreachable ();
 }
 
+/* Intended for compiler developers to trace the compiler's call stack
+   to stderr without affecting compilation state.  The trace generated
+   here is the same as would occur with an ICE.  */
+DEBUG_FUNCTION void
+dump_backtrace (void)
+{
+  struct backtrace_state *state =
+    backtrace_create_state (NULL, 0, bt_err_callback, NULL);
+  int count = 0;
+  if (state != NULL)
+    backtrace_full (state, 2, bt_callback, bt_err_callback, (void *) &count);
+}
+
 /* An internal consistency check has failed.  We make no attempt to
    continue.  Note that unless there is debugging value to be had from
    a more specific message, or some other good reason, you should use
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [C++14/lambda] Experimental polymorphic lambda patches
  2013-07-01 23:27 [C++14/lambda] Experimental polymorphic lambda patches Adam Butcher
                   ` (4 preceding siblings ...)
  2013-07-02  0:01 ` [PATCH] [debug] Added DEBUG_FUNCTION void dump_backtrace Adam Butcher
@ 2013-07-11 17:35 ` Jason Merrill
  2013-07-12  2:04   ` Gabriel Dos Reis
  2013-07-19  9:01   ` [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches Adam Butcher
  2013-08-03 18:38 ` [C++14/lambda] Experimental polymorphic lambda patches Paolo Carlini
  6 siblings, 2 replies; 39+ messages in thread
From: Jason Merrill @ 2013-07-11 17:35 UTC (permalink / raw)
  To: Adam Butcher, gcc-patches

On 07/01/2013 04:26 PM, Adam Butcher wrote:
> I've finally reworked the generic lambda patches I made back in 2009
> (http://gcc.1065356.n5.nabble.com/lambda-Latest-experimental-polymorphic-lambda-patches-tt713016.html)
> to apply against GCC's mainline.

Great!

> Missing features:
>
>   - Conversion to function pointer of stateless generic lambdas is
>     currently unsupported.  Currently a warning is generated for all
>     such lambdas at their definition.
>
> Other issues: (see XXX, FIXME, TODO)
>
>    a)  Location of implementation.

Let's move all the lambda code into a new lambda.c, semantics.c has 
gotten huge.

>    b)  What to do about name mangling?

I think what you have already should do the right thing; for normal 
function template instantiations we mangle the uninstantiated type of 
the template along with the template arguments, so I think for a generic 
lambda just mangling the uninstantiated parameter types is the way to go.

> Any comments appreciated.  Guidance on implementing the conversion
> operator for stateless generic lambdas would be useful.  I've made a
> few attempts which were lacking!

It seemed to me that N3649's description of the semantics should 
translate pretty easily into an implementation.  What problems are you 
running into?

> +              Couldn't figure out a clean way to test for lambda inside
> +              check_member_template.  */

LAMBDA_TYPE_P (current_class_type) doesn't work?

>    fn = lambda_function (closure);
> +  if (TREE_CODE (fn) == TEMPLATE_DECL)
> +    fn = DECL_TEMPLATE_RESULT (fn);

I think you could use STRIP_TEMPLATE before returning from 
lambda_function so that we don't need to adjust all the callers to deal 
with stripping the template, so instead of

> -    lambda = BASELINK_FUNCTIONS (lambda);
> +    lambda = OVL_CURRENT (BASELINK_FUNCTIONS (lambda));

You could have

   lambda = STRIP_TEMPLATE (get_first_fn (lambda));

> +  if (TREE_CODE (d) == TEMPLATE_DECL)
> +    return d;

Instead of this, let's avoid calling instantiate_decl from 
instantiate_class_template_1.

>   e)  Should collect 'auto' parameters during parse and realloc
>       template parameter list once at the end of the parameter list
>       rather than incrementally.

I agree, I don't think you need to do anything special while parsing the 
parameter list.

Jason

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [C++14/lambda] Experimental polymorphic lambda patches
  2013-07-11 17:35 ` [C++14/lambda] Experimental polymorphic lambda patches Jason Merrill
@ 2013-07-12  2:04   ` Gabriel Dos Reis
  2013-07-14  9:07     ` [PATCH] [lambda] Extract lambda functions from semantics.c Adam Butcher
  2013-07-19  9:01   ` [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches Adam Butcher
  1 sibling, 1 reply; 39+ messages in thread
From: Gabriel Dos Reis @ 2013-07-12  2:04 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Adam Butcher, gcc-patches

On Wed, Jul 10, 2013 at 9:35 PM, Jason Merrill <jason@redhat.com> wrote:

> Let's move all the lambda code into a new lambda.c, semantics.c has gotten
> huge.

Amen to that, brother!

-- Gaby

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH] [lambda] Extract lambda functions from semantics.c.
  2013-07-12  2:04   ` Gabriel Dos Reis
@ 2013-07-14  9:07     ` Adam Butcher
  2013-07-14 17:30       ` Jason Merrill
  2013-09-04  2:33       ` Mike Stump
  0 siblings, 2 replies; 39+ messages in thread
From: Adam Butcher @ 2013-07-14  9:07 UTC (permalink / raw)
  To: Jason Merrill, Gabriel Dos Reis; +Cc: gcc-patches, Adam Butcher

	* gcc/cp/semantics.c (build_lambda_expr),
	(build_lambda_object), (begin_lambda_type), (lambda_return_type),
	(lambda_function), (lambda_capture_field_type), (is_capture_proxy),
	(is_normal_capture_proxy), (insert_capture_proxy),
	(insert_pending_capture_proxies), (lambda_proxy_type),
	(build_capture_proxy), (vla_capture_type),
	(register_capture_members), (add_default_capture),
	(lambda_expr_this_capture), (maybe_resolve_dummy),
	(nonlambda_method_basetype), (maybe_add_lambda_conv_op) and
	(is_lambda_ignored_entity): Moved definitions into ...
	* gcc/cp/lambda.c: ... this new file.
---
 gcc/cp/Make-lang.in |   2 +-
 gcc/cp/lambda.c     | 921 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/cp/semantics.c  | 888 --------------------------------------------------
 3 files changed, 922 insertions(+), 889 deletions(-)
 create mode 100644 gcc/cp/lambda.c

diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 6e80bcf..2cb919a 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -80,7 +80,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \
  cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
  cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \
  cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
- cp/cp-gimplify.o cp/cp-array-notation.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o cp/cp-array-notation.o cp/lambda.o $(CXX_C_OBJS)
 
 # Language-specific object files for C++.
 CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
new file mode 100644
index 0000000..75b4fdd
--- /dev/null
+++ b/gcc/cp/lambda.c
@@ -0,0 +1,921 @@
+/* Perform the semantic phase of lambda parsing, i.e., the process of
+   building tree structure, checking semantic consistency, and
+   building RTL.  These routines are used both during actual parsing
+   and during the instantiation of template functions.
+
+   Copyright (C) 1998-2013 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "cgraph.h"
+#include "tree-iterator.h"
+#include "cp-tree.h"
+#include "toplev.h"
+#include "vec.h"
+
+/* Constructor for a lambda expression.  */
+
+tree
+build_lambda_expr (void)
+{
+  tree lambda = make_node (LAMBDA_EXPR);
+  LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) = CPLD_NONE;
+  LAMBDA_EXPR_CAPTURE_LIST         (lambda) = NULL_TREE;
+  LAMBDA_EXPR_THIS_CAPTURE         (lambda) = NULL_TREE;
+  LAMBDA_EXPR_PENDING_PROXIES      (lambda) = NULL;
+  LAMBDA_EXPR_RETURN_TYPE          (lambda) = NULL_TREE;
+  LAMBDA_EXPR_MUTABLE_P            (lambda) = false;
+  return lambda;
+}
+
+/* Create the closure object for a LAMBDA_EXPR.  */
+
+tree
+build_lambda_object (tree lambda_expr)
+{
+  /* Build aggregate constructor call.
+     - cp_parser_braced_list
+     - cp_parser_functional_cast  */
+  vec<constructor_elt, va_gc> *elts = NULL;
+  tree node, expr, type;
+  location_t saved_loc;
+
+  if (processing_template_decl)
+    return lambda_expr;
+
+  /* Make sure any error messages refer to the lambda-introducer.  */
+  saved_loc = input_location;
+  input_location = LAMBDA_EXPR_LOCATION (lambda_expr);
+
+  for (node = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr);
+       node;
+       node = TREE_CHAIN (node))
+    {
+      tree field = TREE_PURPOSE (node);
+      tree val = TREE_VALUE (node);
+
+      if (field == error_mark_node)
+	{
+	  expr = error_mark_node;
+	  goto out;
+	}
+
+      if (DECL_P (val))
+	mark_used (val);
+
+      /* Mere mortals can't copy arrays with aggregate initialization, so
+	 do some magic to make it work here.  */
+      if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
+	val = build_array_copy (val);
+      else if (DECL_NORMAL_CAPTURE_P (field)
+	       && !DECL_VLA_CAPTURE_P (field)
+	       && TREE_CODE (TREE_TYPE (field)) != REFERENCE_TYPE)
+	{
+	  /* "the entities that are captured by copy are used to
+	     direct-initialize each corresponding non-static data
+	     member of the resulting closure object."
+
+	     There's normally no way to express direct-initialization
+	     from an element of a CONSTRUCTOR, so we build up a special
+	     TARGET_EXPR to bypass the usual copy-initialization.  */
+	  val = force_rvalue (val, tf_warning_or_error);
+	  if (TREE_CODE (val) == TARGET_EXPR)
+	    TARGET_EXPR_DIRECT_INIT_P (val) = true;
+	}
+
+      CONSTRUCTOR_APPEND_ELT (elts, DECL_NAME (field), val);
+    }
+
+  expr = build_constructor (init_list_type_node, elts);
+  CONSTRUCTOR_IS_DIRECT_INIT (expr) = 1;
+
+  /* N2927: "[The closure] class type is not an aggregate."
+     But we briefly treat it as an aggregate to make this simpler.  */
+  type = LAMBDA_EXPR_CLOSURE (lambda_expr);
+  CLASSTYPE_NON_AGGREGATE (type) = 0;
+  expr = finish_compound_literal (type, expr, tf_warning_or_error);
+  CLASSTYPE_NON_AGGREGATE (type) = 1;
+
+ out:
+  input_location = saved_loc;
+  return expr;
+}
+
+/* Return an initialized RECORD_TYPE for LAMBDA.
+   LAMBDA must have its explicit captures already.  */
+
+tree
+begin_lambda_type (tree lambda)
+{
+  tree type;
+
+  {
+    /* Unique name.  This is just like an unnamed class, but we cannot use
+       make_anon_name because of certain checks against TYPE_ANONYMOUS_P.  */
+    tree name;
+    name = make_lambda_name ();
+
+    /* Create the new RECORD_TYPE for this lambda.  */
+    type = xref_tag (/*tag_code=*/record_type,
+                     name,
+                     /*scope=*/ts_lambda,
+                     /*template_header_p=*/false);
+  }
+
+  /* Designate it as a struct so that we can use aggregate initialization.  */
+  CLASSTYPE_DECLARED_CLASS (type) = false;
+
+  /* Cross-reference the expression and the type.  */
+  LAMBDA_EXPR_CLOSURE (lambda) = type;
+  CLASSTYPE_LAMBDA_EXPR (type) = lambda;
+
+  /* Clear base types.  */
+  xref_basetypes (type, /*bases=*/NULL_TREE);
+
+  /* Start the class.  */
+  type = begin_class_definition (type);
+  if (type == error_mark_node)
+    return error_mark_node;
+
+  return type;
+}
+
+/* Returns the type to use for the return type of the operator() of a
+   closure class.  */
+
+tree
+lambda_return_type (tree expr)
+{
+  if (expr == NULL_TREE)
+    return void_type_node;
+  if (type_unknown_p (expr)
+      || BRACE_ENCLOSED_INITIALIZER_P (expr))
+    {
+      cxx_incomplete_type_error (expr, TREE_TYPE (expr));
+      return void_type_node;
+    }
+  gcc_checking_assert (!type_dependent_expression_p (expr));
+  return cv_unqualified (type_decays_to (unlowered_expr_type (expr)));
+}
+
+/* Given a LAMBDA_EXPR or closure type LAMBDA, return the op() of the
+   closure type.  */
+
+tree
+lambda_function (tree lambda)
+{
+  tree type;
+  if (TREE_CODE (lambda) == LAMBDA_EXPR)
+    type = LAMBDA_EXPR_CLOSURE (lambda);
+  else
+    type = lambda;
+  gcc_assert (LAMBDA_TYPE_P (type));
+  /* Don't let debug_tree cause instantiation.  */
+  if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)
+      && !COMPLETE_OR_OPEN_TYPE_P (type))
+    return NULL_TREE;
+  lambda = lookup_member (type, ansi_opname (CALL_EXPR),
+			  /*protect=*/0, /*want_type=*/false,
+			  tf_warning_or_error);
+  if (lambda)
+    lambda = BASELINK_FUNCTIONS (lambda);
+  return lambda;
+}
+
+/* Returns the type to use for the FIELD_DECL corresponding to the
+   capture of EXPR.
+   The caller should add REFERENCE_TYPE for capture by reference.  */
+
+tree
+lambda_capture_field_type (tree expr, bool explicit_init_p)
+{
+  tree type;
+  if (explicit_init_p)
+    {
+      type = make_auto ();
+      type = do_auto_deduction (type, expr, type);
+    }
+  else
+    type = non_reference (unlowered_expr_type (expr));
+  if (!type || WILDCARD_TYPE_P (type) || type_uses_auto (type))
+    {
+      type = cxx_make_type (DECLTYPE_TYPE);
+      DECLTYPE_TYPE_EXPR (type) = expr;
+      DECLTYPE_FOR_LAMBDA_CAPTURE (type) = true;
+      DECLTYPE_FOR_INIT_CAPTURE (type) = explicit_init_p;
+      SET_TYPE_STRUCTURAL_EQUALITY (type);
+    }
+  return type;
+}
+
+/* Returns true iff DECL is a lambda capture proxy variable created by
+   build_capture_proxy.  */
+
+bool
+is_capture_proxy (tree decl)
+{
+  return (VAR_P (decl)
+	  && DECL_HAS_VALUE_EXPR_P (decl)
+	  && !DECL_ANON_UNION_VAR_P (decl)
+	  && LAMBDA_FUNCTION_P (DECL_CONTEXT (decl)));
+}
+
+/* Returns true iff DECL is a capture proxy for a normal capture
+   (i.e. without explicit initializer).  */
+
+bool
+is_normal_capture_proxy (tree decl)
+{
+  if (!is_capture_proxy (decl))
+    /* It's not a capture proxy.  */
+    return false;
+
+  /* It is a capture proxy, is it a normal capture?  */
+  tree val = DECL_VALUE_EXPR (decl);
+  if (val == error_mark_node)
+    return true;
+
+  gcc_assert (TREE_CODE (val) == COMPONENT_REF);
+  val = TREE_OPERAND (val, 1);
+  return DECL_NORMAL_CAPTURE_P (val);
+}
+
+/* VAR is a capture proxy created by build_capture_proxy; add it to the
+   current function, which is the operator() for the appropriate lambda.  */
+
+void
+insert_capture_proxy (tree var)
+{
+  cp_binding_level *b;
+  tree stmt_list;
+
+  /* Put the capture proxy in the extra body block so that it won't clash
+     with a later local variable.  */
+  b = current_binding_level;
+  for (;;)
+    {
+      cp_binding_level *n = b->level_chain;
+      if (n->kind == sk_function_parms)
+	break;
+      b = n;
+    }
+  pushdecl_with_scope (var, b, false);
+
+  /* And put a DECL_EXPR in the STATEMENT_LIST for the same block.  */
+  var = build_stmt (DECL_SOURCE_LOCATION (var), DECL_EXPR, var);
+  stmt_list = (*stmt_list_stack)[1];
+  gcc_assert (stmt_list);
+  append_to_statement_list_force (var, &stmt_list);
+}
+
+/* We've just finished processing a lambda; if the containing scope is also
+   a lambda, insert any capture proxies that were created while processing
+   the nested lambda.  */
+
+void
+insert_pending_capture_proxies (void)
+{
+  tree lam;
+  vec<tree, va_gc> *proxies;
+  unsigned i;
+
+  if (!current_function_decl || !LAMBDA_FUNCTION_P (current_function_decl))
+    return;
+
+  lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl));
+  proxies = LAMBDA_EXPR_PENDING_PROXIES (lam);
+  for (i = 0; i < vec_safe_length (proxies); ++i)
+    {
+      tree var = (*proxies)[i];
+      insert_capture_proxy (var);
+    }
+  release_tree_vector (LAMBDA_EXPR_PENDING_PROXIES (lam));
+  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 (type && !WILDCARD_TYPE_P (non_reference (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.  */
+
+tree
+build_capture_proxy (tree member)
+{
+  tree var, object, fn, closure, name, lam, type;
+
+  closure = DECL_CONTEXT (member);
+  fn = lambda_function (closure);
+  lam = CLASSTYPE_LAMBDA_EXPR (closure);
+
+  /* The proxy variable forwards to the capture field.  */
+  object = build_fold_indirect_ref (DECL_ARGUMENTS (fn));
+  object = finish_non_static_data_member (member, object, NULL_TREE);
+  if (REFERENCE_REF_P (object))
+    object = TREE_OPERAND (object, 0);
+
+  /* Remove the __ inserted by add_capture.  */
+  if (DECL_NORMAL_CAPTURE_P (member))
+    name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
+  else
+    name = DECL_NAME (member);
+
+  type = lambda_proxy_type (object);
+
+  if (DECL_VLA_CAPTURE_P (member))
+    {
+      /* Rebuild the VLA type from the pointer and maxindex.  */
+      tree field = next_initializable_field (TYPE_FIELDS (type));
+      tree ptr = build_simple_component_ref (object, field);
+      field = next_initializable_field (DECL_CHAIN (field));
+      tree max = build_simple_component_ref (object, field);
+      type = build_array_type (TREE_TYPE (TREE_TYPE (ptr)),
+			       build_index_type (max));
+      type = build_reference_type (type);
+      REFERENCE_VLA_OK (type) = true;
+      object = convert (type, ptr);
+    }
+
+  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;
+  TREE_USED (var) = 1;
+  DECL_CONTEXT (var) = fn;
+
+  if (name == this_identifier)
+    {
+      gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (lam) == member);
+      LAMBDA_EXPR_THIS_CAPTURE (lam) = var;
+    }
+
+  if (fn == current_function_decl)
+    insert_capture_proxy (var);
+  else
+    vec_safe_push (LAMBDA_EXPR_PENDING_PROXIES (lam), var);
+
+  return var;
+}
+
+/* Return a struct containing a pointer and a length for lambda capture of
+   an array of runtime length.  */
+
+static tree
+vla_capture_type (tree array_type)
+{
+  static tree ptr_id, max_id;
+  tree type = xref_tag (record_type, make_anon_name (), ts_current, false);
+  xref_basetypes (type, NULL_TREE);
+  type = begin_class_definition (type);
+  if (!ptr_id)
+    {
+      ptr_id = get_identifier ("ptr");
+      max_id = get_identifier ("max");
+    }
+  tree ptrtype = build_pointer_type (TREE_TYPE (array_type));
+  tree field = build_decl (input_location, FIELD_DECL, ptr_id, ptrtype);
+  finish_member_declaration (field);
+  field = build_decl (input_location, FIELD_DECL, max_id, sizetype);
+  finish_member_declaration (field);
+  return finish_struct (type, NULL_TREE);
+}
+
+/* From an ID and INITIALIZER, create a capture (by reference if
+   BY_REFERENCE_P is true), add it to the capture-list for LAMBDA,
+   and return it.  */
+
+tree
+add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
+	     bool explicit_init_p)
+{
+  char *buf;
+  tree type, member, name;
+  bool vla = false;
+
+  if (TREE_CODE (initializer) == TREE_LIST)
+    initializer = build_x_compound_expr_from_list (initializer, ELK_INIT,
+						   tf_warning_or_error);
+  type = lambda_capture_field_type (initializer, explicit_init_p);
+  if (array_of_runtime_bound_p (type))
+    {
+      vla = true;
+      if (!by_reference_p)
+	error ("array of runtime bound cannot be captured by copy, "
+	       "only by reference");
+
+      /* For a VLA, we capture the address of the first element and the
+	 maximum index, and then reconstruct the VLA for the proxy.  */
+      tree elt = cp_build_array_ref (input_location, initializer,
+				     integer_zero_node, tf_warning_or_error);
+      initializer = build_constructor_va (init_list_type_node, 2,
+					  NULL_TREE, build_address (elt),
+					  NULL_TREE, array_type_nelts (type));
+      type = vla_capture_type (type);
+    }
+  else if (variably_modified_type_p (type, NULL_TREE))
+    {
+      error ("capture of variable-size type %qT that is not a C++1y array "
+	     "of runtime bound", type);
+      if (TREE_CODE (type) == ARRAY_TYPE
+	  && variably_modified_type_p (TREE_TYPE (type), NULL_TREE))
+	inform (input_location, "because the array element type %qT has "
+		"variable size", TREE_TYPE (type));
+      type = error_mark_node;
+    }
+  else if (by_reference_p)
+    {
+      type = build_reference_type (type);
+      if (!real_lvalue_p (initializer))
+	error ("cannot capture %qE by reference", initializer);
+    }
+  else
+    /* Capture by copy requires a complete type.  */
+    type = complete_type (type);
+
+  /* Add __ to the beginning of the field name so that user code
+     won't find the field with name lookup.  We can't just leave the name
+     unset because template instantiation uses the name to find
+     instantiated fields.  */
+  if (!explicit_init_p)
+    {
+      buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3);
+      buf[1] = buf[0] = '_';
+      memcpy (buf + 2, IDENTIFIER_POINTER (id),
+	      IDENTIFIER_LENGTH (id) + 1);
+      name = get_identifier (buf);
+    }
+  else
+    /* But captures with explicit initializers are named.  */
+    name = id;
+
+  /* If TREE_TYPE isn't set, we're still in the introducer, so check
+     for duplicates.  */
+  if (!LAMBDA_EXPR_CLOSURE (lambda))
+    {
+      if (IDENTIFIER_MARKED (name))
+	{
+	  pedwarn (input_location, 0,
+		   "already captured %qD in lambda expression", id);
+	  return NULL_TREE;
+	}
+      IDENTIFIER_MARKED (name) = true;
+    }
+
+  /* Make member variable.  */
+  member = build_lang_decl (FIELD_DECL, name, type);
+  DECL_VLA_CAPTURE_P (member) = vla;
+
+  if (!explicit_init_p)
+    /* Normal captures are invisible to name lookup but uses are replaced
+       with references to the capture field; we implement this by only
+       really making them invisible in unevaluated context; see
+       qualify_lookup.  For now, let's make explicitly initialized captures
+       always visible.  */
+    DECL_NORMAL_CAPTURE_P (member) = true;
+
+  if (id == this_identifier)
+    LAMBDA_EXPR_THIS_CAPTURE (lambda) = member;
+
+  /* Add it to the appropriate closure class if we've started it.  */
+  if (current_class_type
+      && current_class_type == LAMBDA_EXPR_CLOSURE (lambda))
+    finish_member_declaration (member);
+
+  LAMBDA_EXPR_CAPTURE_LIST (lambda)
+    = tree_cons (member, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
+
+  if (LAMBDA_EXPR_CLOSURE (lambda))
+    return build_capture_proxy (member);
+  /* For explicit captures we haven't started the function yet, so we wait
+     and build the proxy from cp_parser_lambda_body.  */
+  return NULL_TREE;
+}
+
+/* Register all the capture members on the list CAPTURES, which is the
+   LAMBDA_EXPR_CAPTURE_LIST for the lambda after the introducer.  */
+
+void
+register_capture_members (tree captures)
+{
+  if (captures == NULL_TREE)
+    return;
+
+  register_capture_members (TREE_CHAIN (captures));
+  /* We set this in add_capture to avoid duplicates.  */
+  IDENTIFIER_MARKED (DECL_NAME (TREE_PURPOSE (captures))) = false;
+  finish_member_declaration (TREE_PURPOSE (captures));
+}
+
+/* Similar to add_capture, except this works on a stack of nested lambdas.
+   BY_REFERENCE_P in this case is derived from the default capture mode.
+   Returns the capture for the lambda at the bottom of the stack.  */
+
+tree
+add_default_capture (tree lambda_stack, tree id, tree initializer)
+{
+  bool this_capture_p = (id == this_identifier);
+
+  tree var = NULL_TREE;
+
+  tree saved_class_type = current_class_type;
+
+  tree node;
+
+  for (node = lambda_stack;
+       node;
+       node = TREE_CHAIN (node))
+    {
+      tree lambda = TREE_VALUE (node);
+
+      current_class_type = LAMBDA_EXPR_CLOSURE (lambda);
+      var = add_capture (lambda,
+                            id,
+                            initializer,
+                            /*by_reference_p=*/
+			    (!this_capture_p
+			     && (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda)
+				 == CPLD_REFERENCE)),
+			    /*explicit_init_p=*/false);
+      initializer = convert_from_reference (var);
+    }
+
+  current_class_type = saved_class_type;
+
+  return var;
+}
+
+/* Return the capture pertaining to a use of 'this' in LAMBDA, in the form of an
+   INDIRECT_REF, possibly adding it through default capturing.  */
+
+tree
+lambda_expr_this_capture (tree lambda)
+{
+  tree result;
+
+  tree this_capture = LAMBDA_EXPR_THIS_CAPTURE (lambda);
+
+  /* In unevaluated context this isn't an odr-use, so just return the
+     nearest 'this'.  */
+  if (cp_unevaluated_operand)
+    return lookup_name (this_identifier);
+
+  /* Try to default capture 'this' if we can.  */
+  if (!this_capture
+      && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE)
+    {
+      tree lambda_stack = NULL_TREE;
+      tree init = NULL_TREE;
+
+      /* If we are in a lambda function, we can move out until we hit:
+           1. a non-lambda function or NSDMI,
+           2. a lambda function capturing 'this', or
+           3. a non-default capturing lambda function.  */
+      for (tree tlambda = lambda; ;)
+	{
+          lambda_stack = tree_cons (NULL_TREE,
+                                    tlambda,
+                                    lambda_stack);
+
+	  if (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)
+	      && TREE_CODE (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)) == FIELD_DECL)
+	    {
+	      /* In an NSDMI, we don't have a function to look up the decl in,
+		 but the fake 'this' pointer that we're using for parsing is
+		 in scope_chain.  */
+	      init = scope_chain->x_current_class_ptr;
+	      gcc_checking_assert
+		(init && (TREE_TYPE (TREE_TYPE (init))
+			  == current_nonlambda_class_type ()));
+	      break;
+	    }
+
+	  tree closure_decl = TYPE_NAME (LAMBDA_EXPR_CLOSURE (tlambda));
+	  tree containing_function = decl_function_context (closure_decl);
+
+	  if (containing_function == NULL_TREE)
+	    /* We ran out of scopes; there's no 'this' to capture.  */
+	    break;
+
+	  if (!LAMBDA_FUNCTION_P (containing_function))
+	    {
+	      /* We found a non-lambda function.  */
+	      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (containing_function))
+		/* First parameter is 'this'.  */
+		init = DECL_ARGUMENTS (containing_function);
+	      break;
+	    }
+
+	  tlambda
+            = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (containing_function));
+
+          if (LAMBDA_EXPR_THIS_CAPTURE (tlambda))
+	    {
+	      /* An outer lambda has already captured 'this'.  */
+	      init = LAMBDA_EXPR_THIS_CAPTURE (tlambda);
+	      break;
+	    }
+
+	  if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (tlambda) == CPLD_NONE)
+	    /* An outer lambda won't let us capture 'this'.  */
+	    break;
+	}
+
+      if (init)
+	this_capture = add_default_capture (lambda_stack,
+					    /*id=*/this_identifier,
+					    init);
+    }
+
+  if (!this_capture)
+    {
+      error ("%<this%> was not captured for this lambda function");
+      result = error_mark_node;
+    }
+  else
+    {
+      /* To make sure that current_class_ref is for the lambda.  */
+      gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref))
+		  == LAMBDA_EXPR_CLOSURE (lambda));
+
+      result = this_capture;
+
+      /* If 'this' is captured, each use of 'this' is transformed into an
+	 access to the corresponding unnamed data member of the closure
+	 type cast (_expr.cast_ 5.4) to the type of 'this'. [ The cast
+	 ensures that the transformed expression is an rvalue. ] */
+      result = rvalue (result);
+    }
+
+  return result;
+}
+
+/* We don't want to capture 'this' until we know we need it, i.e. after
+   overload resolution has chosen a non-static member function.  At that
+   point we call this function to turn a dummy object into a use of the
+   'this' capture.  */
+
+tree
+maybe_resolve_dummy (tree object)
+{
+  if (!is_dummy_object (object))
+    return object;
+
+  tree type = TYPE_MAIN_VARIANT (TREE_TYPE (object));
+  gcc_assert (!TYPE_PTR_P (type));
+
+  if (type != current_class_type
+      && current_class_type
+      && LAMBDA_TYPE_P (current_class_type)
+      && DERIVED_FROM_P (type, current_nonlambda_class_type ()))
+    {
+      /* In a lambda, need to go through 'this' capture.  */
+      tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type);
+      tree cap = lambda_expr_this_capture (lam);
+      object = build_x_indirect_ref (EXPR_LOCATION (object), cap,
+				     RO_NULL, tf_warning_or_error);
+    }
+
+  return object;
+}
+
+/* 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.  */
+
+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;
+  tree thistype, stattype, statfn, convfn, call, arg;
+  vec<tree, va_gc> *argvec;
+
+  if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE)
+    return;
+
+  if (processing_template_decl)
+    return;
+
+  if (DECL_INITIAL (callop) == NULL_TREE)
+    {
+      /* If the op() wasn't instantiated due to errors, give up.  */
+      gcc_assert (errorcount || sorrycount);
+      return;
+    }
+
+  stattype = build_function_type (TREE_TYPE (TREE_TYPE (callop)),
+				  FUNCTION_ARG_CHAIN (callop));
+
+  /* First build up the conversion op.  */
+
+  rettype = build_pointer_type (stattype);
+  name = mangle_conv_op_name_for_type (rettype);
+  thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST);
+  fntype = build_method_type_directly (thistype, rettype, void_list_node);
+  fn = convfn = 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_ARGUMENTS (fn) = build_this_parm (fntype, TYPE_QUAL_CONST);
+  if (nested)
+    DECL_INTERFACE_KNOWN (fn) = 1;
+
+  add_method (type, fn, NULL_TREE);
+
+  /* Generic thunk code fails for varargs; we'll complain in mark_used if
+     the conversion op is used.  */
+  if (varargs_function_p (callop))
+    {
+      DECL_DELETED_FN (fn) = 1;
+      return;
+    }
+
+  /* Now build up the thunk to be returned.  */
+
+  name = get_identifier ("_FUN");
+  fn = statfn = build_lang_decl (FUNCTION_DECL, name, stattype);
+  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;
+  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;
+  DECL_ARGUMENTS (fn) = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop)));
+  for (arg = DECL_ARGUMENTS (fn); arg; arg = DECL_CHAIN (arg))
+    {
+      /* Avoid duplicate -Wshadow warnings.  */
+      DECL_NAME (arg) = NULL_TREE;
+      DECL_CONTEXT (arg) = fn;
+    }
+  if (nested)
+    DECL_INTERFACE_KNOWN (fn) = 1;
+
+  add_method (type, fn, NULL_TREE);
+
+  if (nested)
+    push_function_context ();
+  else
+    /* Still increment function_depth so that we don't GC in the
+       middle of an expression.  */
+    ++function_depth;
+
+  /* Generate the body of the thunk.  */
+
+  start_preparsed_function (statfn, NULL_TREE,
+			    SF_PRE_PARSED | SF_INCLASS_INLINE);
+  if (DECL_ONE_ONLY (statfn))
+    {
+      /* Put the thunk in the same comdat group as the call op.  */
+      symtab_add_to_same_comdat_group
+	 ((symtab_node) cgraph_get_create_node (statfn),
+          (symtab_node) cgraph_get_create_node (callop));
+    }
+  body = begin_function_body ();
+  compound_stmt = begin_compound_stmt (0);
+
+  arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)),
+		null_pointer_node);
+  argvec = make_tree_vector ();
+  argvec->quick_push (arg);
+  for (arg = DECL_ARGUMENTS (statfn); arg; arg = DECL_CHAIN (arg))
+    {
+      mark_exp_read (arg);
+      vec_safe_push (argvec, arg);
+    }
+  call = build_call_a (callop, argvec->length (), argvec->address ());
+  CALL_FROM_THUNK_P (call) = 1;
+  if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
+    call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
+  call = convert_from_reference (call);
+  finish_return_stmt (call);
+
+  finish_compound_stmt (compound_stmt);
+  finish_function_body (body);
+
+  expand_or_defer_fn (finish_function (2));
+
+  /* Generate the body of the conversion op.  */
+
+  start_preparsed_function (convfn, NULL_TREE,
+			    SF_PRE_PARSED | SF_INCLASS_INLINE);
+  body = begin_function_body ();
+  compound_stmt = begin_compound_stmt (0);
+
+  /* decl_needed_p needs to see that it's used.  */
+  TREE_USED (statfn) = 1;
+  finish_return_stmt (decay_conversion (statfn, tf_warning_or_error));
+
+  finish_compound_stmt (compound_stmt);
+  finish_function_body (body);
+
+  expand_or_defer_fn (finish_function (2));
+
+  if (nested)
+    pop_function_context ();
+  else
+    --function_depth;
+}
+
+/* Returns true iff VAL is a lambda-related declaration which should
+   be ignored by unqualified lookup.  */
+
+bool
+is_lambda_ignored_entity (tree val)
+{
+  /* In unevaluated context, look past normal capture proxies.  */
+  if (cp_unevaluated_operand && is_normal_capture_proxy (val))
+    return true;
+
+  /* Always ignore lambda fields, their names are only for debugging.  */
+  if (TREE_CODE (val) == FIELD_DECL
+      && CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (val)))
+    return true;
+
+  /* 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 true;
+
+  return false;
+}
+
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 74a6a53..79b29e4 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -8993,201 +8993,6 @@ require_potential_rvalue_constant_expression (tree t)
   return potential_constant_expression_1 (t, true, tf_warning_or_error);
 }
 \f
-/* Constructor for a lambda expression.  */
-
-tree
-build_lambda_expr (void)
-{
-  tree lambda = make_node (LAMBDA_EXPR);
-  LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) = CPLD_NONE;
-  LAMBDA_EXPR_CAPTURE_LIST         (lambda) = NULL_TREE;
-  LAMBDA_EXPR_THIS_CAPTURE         (lambda) = NULL_TREE;
-  LAMBDA_EXPR_PENDING_PROXIES      (lambda) = NULL;
-  LAMBDA_EXPR_RETURN_TYPE          (lambda) = NULL_TREE;
-  LAMBDA_EXPR_MUTABLE_P            (lambda) = false;
-  return lambda;
-}
-
-/* Create the closure object for a LAMBDA_EXPR.  */
-
-tree
-build_lambda_object (tree lambda_expr)
-{
-  /* Build aggregate constructor call.
-     - cp_parser_braced_list
-     - cp_parser_functional_cast  */
-  vec<constructor_elt, va_gc> *elts = NULL;
-  tree node, expr, type;
-  location_t saved_loc;
-
-  if (processing_template_decl)
-    return lambda_expr;
-
-  /* Make sure any error messages refer to the lambda-introducer.  */
-  saved_loc = input_location;
-  input_location = LAMBDA_EXPR_LOCATION (lambda_expr);
-
-  for (node = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr);
-       node;
-       node = TREE_CHAIN (node))
-    {
-      tree field = TREE_PURPOSE (node);
-      tree val = TREE_VALUE (node);
-
-      if (field == error_mark_node)
-	{
-	  expr = error_mark_node;
-	  goto out;
-	}
-
-      if (DECL_P (val))
-	mark_used (val);
-
-      /* Mere mortals can't copy arrays with aggregate initialization, so
-	 do some magic to make it work here.  */
-      if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
-	val = build_array_copy (val);
-      else if (DECL_NORMAL_CAPTURE_P (field)
-	       && !DECL_VLA_CAPTURE_P (field)
-	       && TREE_CODE (TREE_TYPE (field)) != REFERENCE_TYPE)
-	{
-	  /* "the entities that are captured by copy are used to
-	     direct-initialize each corresponding non-static data
-	     member of the resulting closure object."
-
-	     There's normally no way to express direct-initialization
-	     from an element of a CONSTRUCTOR, so we build up a special
-	     TARGET_EXPR to bypass the usual copy-initialization.  */
-	  val = force_rvalue (val, tf_warning_or_error);
-	  if (TREE_CODE (val) == TARGET_EXPR)
-	    TARGET_EXPR_DIRECT_INIT_P (val) = true;
-	}
-
-      CONSTRUCTOR_APPEND_ELT (elts, DECL_NAME (field), val);
-    }
-
-  expr = build_constructor (init_list_type_node, elts);
-  CONSTRUCTOR_IS_DIRECT_INIT (expr) = 1;
-
-  /* N2927: "[The closure] class type is not an aggregate."
-     But we briefly treat it as an aggregate to make this simpler.  */
-  type = LAMBDA_EXPR_CLOSURE (lambda_expr);
-  CLASSTYPE_NON_AGGREGATE (type) = 0;
-  expr = finish_compound_literal (type, expr, tf_warning_or_error);
-  CLASSTYPE_NON_AGGREGATE (type) = 1;
-
- out:
-  input_location = saved_loc;
-  return expr;
-}
-
-/* Return an initialized RECORD_TYPE for LAMBDA.
-   LAMBDA must have its explicit captures already.  */
-
-tree
-begin_lambda_type (tree lambda)
-{
-  tree type;
-
-  {
-    /* Unique name.  This is just like an unnamed class, but we cannot use
-       make_anon_name because of certain checks against TYPE_ANONYMOUS_P.  */
-    tree name;
-    name = make_lambda_name ();
-
-    /* Create the new RECORD_TYPE for this lambda.  */
-    type = xref_tag (/*tag_code=*/record_type,
-                     name,
-                     /*scope=*/ts_lambda,
-                     /*template_header_p=*/false);
-  }
-
-  /* Designate it as a struct so that we can use aggregate initialization.  */
-  CLASSTYPE_DECLARED_CLASS (type) = false;
-
-  /* Cross-reference the expression and the type.  */
-  LAMBDA_EXPR_CLOSURE (lambda) = type;
-  CLASSTYPE_LAMBDA_EXPR (type) = lambda;
-
-  /* Clear base types.  */
-  xref_basetypes (type, /*bases=*/NULL_TREE);
-
-  /* Start the class.  */
-  type = begin_class_definition (type);
-  if (type == error_mark_node)
-    return error_mark_node;
-
-  return type;
-}
-
-/* Returns the type to use for the return type of the operator() of a
-   closure class.  */
-
-tree
-lambda_return_type (tree expr)
-{
-  if (expr == NULL_TREE)
-    return void_type_node;
-  if (type_unknown_p (expr)
-      || BRACE_ENCLOSED_INITIALIZER_P (expr))
-    {
-      cxx_incomplete_type_error (expr, TREE_TYPE (expr));
-      return void_type_node;
-    }
-  gcc_checking_assert (!type_dependent_expression_p (expr));
-  return cv_unqualified (type_decays_to (unlowered_expr_type (expr)));
-}
-
-/* Given a LAMBDA_EXPR or closure type LAMBDA, return the op() of the
-   closure type.  */
-
-tree
-lambda_function (tree lambda)
-{
-  tree type;
-  if (TREE_CODE (lambda) == LAMBDA_EXPR)
-    type = LAMBDA_EXPR_CLOSURE (lambda);
-  else
-    type = lambda;
-  gcc_assert (LAMBDA_TYPE_P (type));
-  /* Don't let debug_tree cause instantiation.  */
-  if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)
-      && !COMPLETE_OR_OPEN_TYPE_P (type))
-    return NULL_TREE;
-  lambda = lookup_member (type, ansi_opname (CALL_EXPR),
-			  /*protect=*/0, /*want_type=*/false,
-			  tf_warning_or_error);
-  if (lambda)
-    lambda = BASELINK_FUNCTIONS (lambda);
-  return lambda;
-}
-
-/* Returns the type to use for the FIELD_DECL corresponding to the
-   capture of EXPR.
-   The caller should add REFERENCE_TYPE for capture by reference.  */
-
-tree
-lambda_capture_field_type (tree expr, bool explicit_init_p)
-{
-  tree type;
-  if (explicit_init_p)
-    {
-      type = make_auto ();
-      type = do_auto_deduction (type, expr, type);
-    }
-  else
-    type = non_reference (unlowered_expr_type (expr));
-  if (!type || WILDCARD_TYPE_P (type) || type_uses_auto (type))
-    {
-      type = cxx_make_type (DECLTYPE_TYPE);
-      DECLTYPE_TYPE_EXPR (type) = expr;
-      DECLTYPE_FOR_LAMBDA_CAPTURE (type) = true;
-      DECLTYPE_FOR_INIT_CAPTURE (type) = explicit_init_p;
-      SET_TYPE_STRUCTURAL_EQUALITY (type);
-    }
-  return type;
-}
-
 /* Insert the deduced return type for an auto function.  */
 
 void
@@ -9287,697 +9092,4 @@ capture_decltype (tree decl)
   return type;
 }
 
-/* Returns true iff DECL is a lambda capture proxy variable created by
-   build_capture_proxy.  */
-
-bool
-is_capture_proxy (tree decl)
-{
-  return (VAR_P (decl)
-	  && DECL_HAS_VALUE_EXPR_P (decl)
-	  && !DECL_ANON_UNION_VAR_P (decl)
-	  && LAMBDA_FUNCTION_P (DECL_CONTEXT (decl)));
-}
-
-/* Returns true iff DECL is a capture proxy for a normal capture
-   (i.e. without explicit initializer).  */
-
-bool
-is_normal_capture_proxy (tree decl)
-{
-  if (!is_capture_proxy (decl))
-    /* It's not a capture proxy.  */
-    return false;
-
-  /* It is a capture proxy, is it a normal capture?  */
-  tree val = DECL_VALUE_EXPR (decl);
-  if (val == error_mark_node)
-    return true;
-
-  gcc_assert (TREE_CODE (val) == COMPONENT_REF);
-  val = TREE_OPERAND (val, 1);
-  return DECL_NORMAL_CAPTURE_P (val);
-}
-
-/* VAR is a capture proxy created by build_capture_proxy; add it to the
-   current function, which is the operator() for the appropriate lambda.  */
-
-void
-insert_capture_proxy (tree var)
-{
-  cp_binding_level *b;
-  tree stmt_list;
-
-  /* Put the capture proxy in the extra body block so that it won't clash
-     with a later local variable.  */
-  b = current_binding_level;
-  for (;;)
-    {
-      cp_binding_level *n = b->level_chain;
-      if (n->kind == sk_function_parms)
-	break;
-      b = n;
-    }
-  pushdecl_with_scope (var, b, false);
-
-  /* And put a DECL_EXPR in the STATEMENT_LIST for the same block.  */
-  var = build_stmt (DECL_SOURCE_LOCATION (var), DECL_EXPR, var);
-  stmt_list = (*stmt_list_stack)[1];
-  gcc_assert (stmt_list);
-  append_to_statement_list_force (var, &stmt_list);
-}
-
-/* We've just finished processing a lambda; if the containing scope is also
-   a lambda, insert any capture proxies that were created while processing
-   the nested lambda.  */
-
-void
-insert_pending_capture_proxies (void)
-{
-  tree lam;
-  vec<tree, va_gc> *proxies;
-  unsigned i;
-
-  if (!current_function_decl || !LAMBDA_FUNCTION_P (current_function_decl))
-    return;
-
-  lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl));
-  proxies = LAMBDA_EXPR_PENDING_PROXIES (lam);
-  for (i = 0; i < vec_safe_length (proxies); ++i)
-    {
-      tree var = (*proxies)[i];
-      insert_capture_proxy (var);
-    }
-  release_tree_vector (LAMBDA_EXPR_PENDING_PROXIES (lam));
-  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 (type && !WILDCARD_TYPE_P (non_reference (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.  */
-
-tree
-build_capture_proxy (tree member)
-{
-  tree var, object, fn, closure, name, lam, type;
-
-  closure = DECL_CONTEXT (member);
-  fn = lambda_function (closure);
-  lam = CLASSTYPE_LAMBDA_EXPR (closure);
-
-  /* The proxy variable forwards to the capture field.  */
-  object = build_fold_indirect_ref (DECL_ARGUMENTS (fn));
-  object = finish_non_static_data_member (member, object, NULL_TREE);
-  if (REFERENCE_REF_P (object))
-    object = TREE_OPERAND (object, 0);
-
-  /* Remove the __ inserted by add_capture.  */
-  if (DECL_NORMAL_CAPTURE_P (member))
-    name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
-  else
-    name = DECL_NAME (member);
-
-  type = lambda_proxy_type (object);
-
-  if (DECL_VLA_CAPTURE_P (member))
-    {
-      /* Rebuild the VLA type from the pointer and maxindex.  */
-      tree field = next_initializable_field (TYPE_FIELDS (type));
-      tree ptr = build_simple_component_ref (object, field);
-      field = next_initializable_field (DECL_CHAIN (field));
-      tree max = build_simple_component_ref (object, field);
-      type = build_array_type (TREE_TYPE (TREE_TYPE (ptr)),
-			       build_index_type (max));
-      type = build_reference_type (type);
-      REFERENCE_VLA_OK (type) = true;
-      object = convert (type, ptr);
-    }
-
-  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;
-  TREE_USED (var) = 1;
-  DECL_CONTEXT (var) = fn;
-
-  if (name == this_identifier)
-    {
-      gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (lam) == member);
-      LAMBDA_EXPR_THIS_CAPTURE (lam) = var;
-    }
-
-  if (fn == current_function_decl)
-    insert_capture_proxy (var);
-  else
-    vec_safe_push (LAMBDA_EXPR_PENDING_PROXIES (lam), var);
-
-  return var;
-}
-
-/* Return a struct containing a pointer and a length for lambda capture of
-   an array of runtime length.  */
-
-static tree
-vla_capture_type (tree array_type)
-{
-  static tree ptr_id, max_id;
-  tree type = xref_tag (record_type, make_anon_name (), ts_current, false);
-  xref_basetypes (type, NULL_TREE);
-  type = begin_class_definition (type);
-  if (!ptr_id)
-    {
-      ptr_id = get_identifier ("ptr");
-      max_id = get_identifier ("max");
-    }
-  tree ptrtype = build_pointer_type (TREE_TYPE (array_type));
-  tree field = build_decl (input_location, FIELD_DECL, ptr_id, ptrtype);
-  finish_member_declaration (field);
-  field = build_decl (input_location, FIELD_DECL, max_id, sizetype);
-  finish_member_declaration (field);
-  return finish_struct (type, NULL_TREE);
-}
-
-/* From an ID and INITIALIZER, create a capture (by reference if
-   BY_REFERENCE_P is true), add it to the capture-list for LAMBDA,
-   and return it.  */
-
-tree
-add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
-	     bool explicit_init_p)
-{
-  char *buf;
-  tree type, member, name;
-  bool vla = false;
-
-  if (TREE_CODE (initializer) == TREE_LIST)
-    initializer = build_x_compound_expr_from_list (initializer, ELK_INIT,
-						   tf_warning_or_error);
-  type = lambda_capture_field_type (initializer, explicit_init_p);
-  if (array_of_runtime_bound_p (type))
-    {
-      vla = true;
-      if (!by_reference_p)
-	error ("array of runtime bound cannot be captured by copy, "
-	       "only by reference");
-
-      /* For a VLA, we capture the address of the first element and the
-	 maximum index, and then reconstruct the VLA for the proxy.  */
-      tree elt = cp_build_array_ref (input_location, initializer,
-				     integer_zero_node, tf_warning_or_error);
-      initializer = build_constructor_va (init_list_type_node, 2,
-					  NULL_TREE, build_address (elt),
-					  NULL_TREE, array_type_nelts (type));
-      type = vla_capture_type (type);
-    }
-  else if (variably_modified_type_p (type, NULL_TREE))
-    {
-      error ("capture of variable-size type %qT that is not a C++1y array "
-	     "of runtime bound", type);
-      if (TREE_CODE (type) == ARRAY_TYPE
-	  && variably_modified_type_p (TREE_TYPE (type), NULL_TREE))
-	inform (input_location, "because the array element type %qT has "
-		"variable size", TREE_TYPE (type));
-      type = error_mark_node;
-    }
-  else if (by_reference_p)
-    {
-      type = build_reference_type (type);
-      if (!real_lvalue_p (initializer))
-	error ("cannot capture %qE by reference", initializer);
-    }
-  else
-    /* Capture by copy requires a complete type.  */
-    type = complete_type (type);
-
-  /* Add __ to the beginning of the field name so that user code
-     won't find the field with name lookup.  We can't just leave the name
-     unset because template instantiation uses the name to find
-     instantiated fields.  */
-  if (!explicit_init_p)
-    {
-      buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3);
-      buf[1] = buf[0] = '_';
-      memcpy (buf + 2, IDENTIFIER_POINTER (id),
-	      IDENTIFIER_LENGTH (id) + 1);
-      name = get_identifier (buf);
-    }
-  else
-    /* But captures with explicit initializers are named.  */
-    name = id;
-
-  /* If TREE_TYPE isn't set, we're still in the introducer, so check
-     for duplicates.  */
-  if (!LAMBDA_EXPR_CLOSURE (lambda))
-    {
-      if (IDENTIFIER_MARKED (name))
-	{
-	  pedwarn (input_location, 0,
-		   "already captured %qD in lambda expression", id);
-	  return NULL_TREE;
-	}
-      IDENTIFIER_MARKED (name) = true;
-    }
-
-  /* Make member variable.  */
-  member = build_lang_decl (FIELD_DECL, name, type);
-  DECL_VLA_CAPTURE_P (member) = vla;
-
-  if (!explicit_init_p)
-    /* Normal captures are invisible to name lookup but uses are replaced
-       with references to the capture field; we implement this by only
-       really making them invisible in unevaluated context; see
-       qualify_lookup.  For now, let's make explicitly initialized captures
-       always visible.  */
-    DECL_NORMAL_CAPTURE_P (member) = true;
-
-  if (id == this_identifier)
-    LAMBDA_EXPR_THIS_CAPTURE (lambda) = member;
-
-  /* Add it to the appropriate closure class if we've started it.  */
-  if (current_class_type
-      && current_class_type == LAMBDA_EXPR_CLOSURE (lambda))
-    finish_member_declaration (member);
-
-  LAMBDA_EXPR_CAPTURE_LIST (lambda)
-    = tree_cons (member, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
-
-  if (LAMBDA_EXPR_CLOSURE (lambda))
-    return build_capture_proxy (member);
-  /* For explicit captures we haven't started the function yet, so we wait
-     and build the proxy from cp_parser_lambda_body.  */
-  return NULL_TREE;
-}
-
-/* Register all the capture members on the list CAPTURES, which is the
-   LAMBDA_EXPR_CAPTURE_LIST for the lambda after the introducer.  */
-
-void
-register_capture_members (tree captures)
-{
-  if (captures == NULL_TREE)
-    return;
-
-  register_capture_members (TREE_CHAIN (captures));
-  /* We set this in add_capture to avoid duplicates.  */
-  IDENTIFIER_MARKED (DECL_NAME (TREE_PURPOSE (captures))) = false;
-  finish_member_declaration (TREE_PURPOSE (captures));
-}
-
-/* Similar to add_capture, except this works on a stack of nested lambdas.
-   BY_REFERENCE_P in this case is derived from the default capture mode.
-   Returns the capture for the lambda at the bottom of the stack.  */
-
-tree
-add_default_capture (tree lambda_stack, tree id, tree initializer)
-{
-  bool this_capture_p = (id == this_identifier);
-
-  tree var = NULL_TREE;
-
-  tree saved_class_type = current_class_type;
-
-  tree node;
-
-  for (node = lambda_stack;
-       node;
-       node = TREE_CHAIN (node))
-    {
-      tree lambda = TREE_VALUE (node);
-
-      current_class_type = LAMBDA_EXPR_CLOSURE (lambda);
-      var = add_capture (lambda,
-                            id,
-                            initializer,
-                            /*by_reference_p=*/
-			    (!this_capture_p
-			     && (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda)
-				 == CPLD_REFERENCE)),
-			    /*explicit_init_p=*/false);
-      initializer = convert_from_reference (var);
-    }
-
-  current_class_type = saved_class_type;
-
-  return var;
-}
-
-/* Return the capture pertaining to a use of 'this' in LAMBDA, in the form of an
-   INDIRECT_REF, possibly adding it through default capturing.  */
-
-tree
-lambda_expr_this_capture (tree lambda)
-{
-  tree result;
-
-  tree this_capture = LAMBDA_EXPR_THIS_CAPTURE (lambda);
-
-  /* In unevaluated context this isn't an odr-use, so just return the
-     nearest 'this'.  */
-  if (cp_unevaluated_operand)
-    return lookup_name (this_identifier);
-
-  /* Try to default capture 'this' if we can.  */
-  if (!this_capture
-      && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE)
-    {
-      tree lambda_stack = NULL_TREE;
-      tree init = NULL_TREE;
-
-      /* If we are in a lambda function, we can move out until we hit:
-           1. a non-lambda function or NSDMI,
-           2. a lambda function capturing 'this', or
-           3. a non-default capturing lambda function.  */
-      for (tree tlambda = lambda; ;)
-	{
-          lambda_stack = tree_cons (NULL_TREE,
-                                    tlambda,
-                                    lambda_stack);
-
-	  if (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)
-	      && TREE_CODE (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)) == FIELD_DECL)
-	    {
-	      /* In an NSDMI, we don't have a function to look up the decl in,
-		 but the fake 'this' pointer that we're using for parsing is
-		 in scope_chain.  */
-	      init = scope_chain->x_current_class_ptr;
-	      gcc_checking_assert
-		(init && (TREE_TYPE (TREE_TYPE (init))
-			  == current_nonlambda_class_type ()));
-	      break;
-	    }
-
-	  tree closure_decl = TYPE_NAME (LAMBDA_EXPR_CLOSURE (tlambda));
-	  tree containing_function = decl_function_context (closure_decl);
-
-	  if (containing_function == NULL_TREE)
-	    /* We ran out of scopes; there's no 'this' to capture.  */
-	    break;
-
-	  if (!LAMBDA_FUNCTION_P (containing_function))
-	    {
-	      /* We found a non-lambda function.  */
-	      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (containing_function))
-		/* First parameter is 'this'.  */
-		init = DECL_ARGUMENTS (containing_function);
-	      break;
-	    }
-
-	  tlambda
-            = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (containing_function));
-
-          if (LAMBDA_EXPR_THIS_CAPTURE (tlambda))
-	    {
-	      /* An outer lambda has already captured 'this'.  */
-	      init = LAMBDA_EXPR_THIS_CAPTURE (tlambda);
-	      break;
-	    }
-
-	  if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (tlambda) == CPLD_NONE)
-	    /* An outer lambda won't let us capture 'this'.  */
-	    break;
-	}
-
-      if (init)
-	this_capture = add_default_capture (lambda_stack,
-					    /*id=*/this_identifier,
-					    init);
-    }
-
-  if (!this_capture)
-    {
-      error ("%<this%> was not captured for this lambda function");
-      result = error_mark_node;
-    }
-  else
-    {
-      /* To make sure that current_class_ref is for the lambda.  */
-      gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref))
-		  == LAMBDA_EXPR_CLOSURE (lambda));
-
-      result = this_capture;
-
-      /* If 'this' is captured, each use of 'this' is transformed into an
-	 access to the corresponding unnamed data member of the closure
-	 type cast (_expr.cast_ 5.4) to the type of 'this'. [ The cast
-	 ensures that the transformed expression is an rvalue. ] */
-      result = rvalue (result);
-    }
-
-  return result;
-}
-
-/* We don't want to capture 'this' until we know we need it, i.e. after
-   overload resolution has chosen a non-static member function.  At that
-   point we call this function to turn a dummy object into a use of the
-   'this' capture.  */
-
-tree
-maybe_resolve_dummy (tree object)
-{
-  if (!is_dummy_object (object))
-    return object;
-
-  tree type = TYPE_MAIN_VARIANT (TREE_TYPE (object));
-  gcc_assert (!TYPE_PTR_P (type));
-
-  if (type != current_class_type
-      && current_class_type
-      && LAMBDA_TYPE_P (current_class_type)
-      && DERIVED_FROM_P (type, current_nonlambda_class_type ()))
-    {
-      /* In a lambda, need to go through 'this' capture.  */
-      tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type);
-      tree cap = lambda_expr_this_capture (lam);
-      object = build_x_indirect_ref (EXPR_LOCATION (object), cap,
-				     RO_NULL, tf_warning_or_error);
-    }
-
-  return object;
-}
-
-/* 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.  */
-
-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;
-  tree thistype, stattype, statfn, convfn, call, arg;
-  vec<tree, va_gc> *argvec;
-
-  if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE)
-    return;
-
-  if (processing_template_decl)
-    return;
-
-  if (DECL_INITIAL (callop) == NULL_TREE)
-    {
-      /* If the op() wasn't instantiated due to errors, give up.  */
-      gcc_assert (errorcount || sorrycount);
-      return;
-    }
-
-  stattype = build_function_type (TREE_TYPE (TREE_TYPE (callop)),
-				  FUNCTION_ARG_CHAIN (callop));
-
-  /* First build up the conversion op.  */
-
-  rettype = build_pointer_type (stattype);
-  name = mangle_conv_op_name_for_type (rettype);
-  thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST);
-  fntype = build_method_type_directly (thistype, rettype, void_list_node);
-  fn = convfn = 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_ARGUMENTS (fn) = build_this_parm (fntype, TYPE_QUAL_CONST);
-  if (nested)
-    DECL_INTERFACE_KNOWN (fn) = 1;
-
-  add_method (type, fn, NULL_TREE);
-
-  /* Generic thunk code fails for varargs; we'll complain in mark_used if
-     the conversion op is used.  */
-  if (varargs_function_p (callop))
-    {
-      DECL_DELETED_FN (fn) = 1;
-      return;
-    }
-
-  /* Now build up the thunk to be returned.  */
-
-  name = get_identifier ("_FUN");
-  fn = statfn = build_lang_decl (FUNCTION_DECL, name, stattype);
-  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;
-  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;
-  DECL_ARGUMENTS (fn) = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop)));
-  for (arg = DECL_ARGUMENTS (fn); arg; arg = DECL_CHAIN (arg))
-    {
-      /* Avoid duplicate -Wshadow warnings.  */
-      DECL_NAME (arg) = NULL_TREE;
-      DECL_CONTEXT (arg) = fn;
-    }
-  if (nested)
-    DECL_INTERFACE_KNOWN (fn) = 1;
-
-  add_method (type, fn, NULL_TREE);
-
-  if (nested)
-    push_function_context ();
-  else
-    /* Still increment function_depth so that we don't GC in the
-       middle of an expression.  */
-    ++function_depth;
-
-  /* Generate the body of the thunk.  */
-
-  start_preparsed_function (statfn, NULL_TREE,
-			    SF_PRE_PARSED | SF_INCLASS_INLINE);
-  if (DECL_ONE_ONLY (statfn))
-    {
-      /* Put the thunk in the same comdat group as the call op.  */
-      symtab_add_to_same_comdat_group
-	 ((symtab_node) cgraph_get_create_node (statfn),
-          (symtab_node) cgraph_get_create_node (callop));
-    }
-  body = begin_function_body ();
-  compound_stmt = begin_compound_stmt (0);
-
-  arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)),
-		null_pointer_node);
-  argvec = make_tree_vector ();
-  argvec->quick_push (arg);
-  for (arg = DECL_ARGUMENTS (statfn); arg; arg = DECL_CHAIN (arg))
-    {
-      mark_exp_read (arg);
-      vec_safe_push (argvec, arg);
-    }
-  call = build_call_a (callop, argvec->length (), argvec->address ());
-  CALL_FROM_THUNK_P (call) = 1;
-  if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
-    call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
-  call = convert_from_reference (call);
-  finish_return_stmt (call);
-
-  finish_compound_stmt (compound_stmt);
-  finish_function_body (body);
-
-  expand_or_defer_fn (finish_function (2));
-
-  /* Generate the body of the conversion op.  */
-
-  start_preparsed_function (convfn, NULL_TREE,
-			    SF_PRE_PARSED | SF_INCLASS_INLINE);
-  body = begin_function_body ();
-  compound_stmt = begin_compound_stmt (0);
-
-  /* decl_needed_p needs to see that it's used.  */
-  TREE_USED (statfn) = 1;
-  finish_return_stmt (decay_conversion (statfn, tf_warning_or_error));
-
-  finish_compound_stmt (compound_stmt);
-  finish_function_body (body);
-
-  expand_or_defer_fn (finish_function (2));
-
-  if (nested)
-    pop_function_context ();
-  else
-    --function_depth;
-}
-
-/* Returns true iff VAL is a lambda-related declaration which should
-   be ignored by unqualified lookup.  */
-
-bool
-is_lambda_ignored_entity (tree val)
-{
-  /* In unevaluated context, look past normal capture proxies.  */
-  if (cp_unevaluated_operand && is_normal_capture_proxy (val))
-    return true;
-
-  /* Always ignore lambda fields, their names are only for debugging.  */
-  if (TREE_CODE (val) == FIELD_DECL
-      && CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (val)))
-    return true;
-
-  /* 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 true;
-
-  return false;
-}
-
 #include "gt-cp-semantics.h"
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] [lambda] Extract lambda functions from semantics.c.
  2013-07-14  9:07     ` [PATCH] [lambda] Extract lambda functions from semantics.c Adam Butcher
@ 2013-07-14 17:30       ` Jason Merrill
  2013-09-04  2:33       ` Mike Stump
  1 sibling, 0 replies; 39+ messages in thread
From: Jason Merrill @ 2013-07-14 17:30 UTC (permalink / raw)
  To: Adam Butcher, Gabriel Dos Reis; +Cc: gcc-patches

Applied, thanks.

Jason

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 3/3] [lambda] [basic-terse-templates] Support using `auto' in a function parameter list to introduce an implicit template parameter.
  2013-07-19  9:01   ` [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches Adam Butcher
  2013-07-19  9:01     ` [PATCH 1/3] [lambda] Support template-parameter-list in lambda-declarator Adam Butcher
@ 2013-07-19  9:01     ` Adam Butcher
  2013-07-19  9:06     ` [PATCH 2/3] [lambda] Avoid crash on symbol table writing when generic lambda declared with iostream (or potentially other code) included Adam Butcher
  2 siblings, 0 replies; 39+ messages in thread
From: Adam Butcher @ 2013-07-19  9:01 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Andrew Sutton, Adam Butcher

---
 gcc/cp/cp-tree.h |  11 ++++
 gcc/cp/decl.c    |   4 +-
 gcc/cp/parser.c  |  57 ++++++++++++++---
 gcc/cp/pt.c      | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 231 insertions(+), 23 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a837d22..08d9d5e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1034,6 +1034,7 @@ struct GTY(()) saved_scope {
   int x_processing_template_decl;
   int x_processing_specialization;
   BOOL_BITFIELD x_processing_explicit_instantiation : 1;
+  BOOL_BITFIELD x_fully_implicit_template : 1;
   BOOL_BITFIELD need_pop_function_context : 1;
 
   int unevaluated_operand;
@@ -1088,6 +1089,12 @@ struct GTY(()) saved_scope {
 #define processing_specialization scope_chain->x_processing_specialization
 #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation
 
+/* Nonzero if the function being declared was made a template due to it's
+   parameter list containing generic type specifiers (`auto' or concept
+   identifiers) rather than an explicit template parameter list.  */
+
+#define fully_implicit_template scope_chain->x_fully_implicit_template
+
 /* The cached class binding level, from the most recently exited
    class, or NULL if none.  */
 
@@ -5453,12 +5460,16 @@ extern tree make_auto				(void);
 extern tree make_decltype_auto			(void);
 extern tree do_auto_deduction			(tree, tree, tree);
 extern tree type_uses_auto			(tree);
+extern tree type_uses_auto_or_concept		(tree);
 extern void append_type_to_template_for_access_check (tree, tree, tree,
 						      location_t);
 extern tree splice_late_return_type		(tree, tree);
 extern bool is_auto				(const_tree);
+extern bool is_auto_or_concept			(const_tree);
 extern tree process_template_parm		(tree, location_t, tree, 
 						 bool, bool);
+extern tree add_implicit_template_parms		(size_t, tree);
+extern tree finish_fully_implicit_template	(tree);
 extern tree end_template_parm_list		(tree);
 extern void end_template_decl			(void);
 extern tree maybe_update_decl_type		(tree, tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index c97134c..56b49dd 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10329,9 +10329,9 @@ grokdeclarator (const cp_declarator *declarator,
       if (ctype || in_namespace)
 	error ("cannot use %<::%> in parameter declaration");
 
-      if (type_uses_auto (type))
+      if (type_uses_auto (type) && cxx_dialect < cxx1y)
 	{
-	  error ("parameter declared %<auto%>");
+	  error ("parameter declared %<auto%> (unsupported prior to C++1y)");
 	  type = error_mark_node;
 	}
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 48c95e6..d6c4129 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8933,6 +8933,11 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 	    finish_template_decl (template_param_list);
 	    --parser->num_template_parameter_lists;
 	  }
+	else if (fully_implicit_template)
+	  {
+	    fco = finish_fully_implicit_template (fco);
+	    --parser->num_template_parameter_lists;
+	  }
       }
 
     finish_member_declaration (fco);
@@ -16807,8 +16812,10 @@ cp_parser_direct_declarator (cp_parser* parser,
 	      /* Parse the parameter-declaration-clause.  */
 	      params = cp_parser_parameter_declaration_clause (parser);
 
+	      /* Restore saved template parameter lists accounting for implicit
+		 template parameters.  */
 	      parser->num_template_parameter_lists
-		= saved_num_template_parameter_lists;
+		+= saved_num_template_parameter_lists;
 
 	      /* Consume the `)'.  */
 	      cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
@@ -17908,6 +17915,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
   tree *tail = &parameters; 
   bool saved_in_unbraced_linkage_specification_p;
   int index = 0;
+  int implicit_template_parms = 0;
 
   /* Assume all will go well.  */
   *is_error = false;
@@ -17935,11 +17943,17 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
       deprecated_state = DEPRECATED_SUPPRESS;
 
       if (parameter)
-	decl = grokdeclarator (parameter->declarator,
-			       &parameter->decl_specifiers,
-			       PARM,
-			       parameter->default_argument != NULL_TREE,
-			       &parameter->decl_specifiers.attributes);
+	{
+	  if (parameter->decl_specifiers.type && is_auto_or_concept
+	      (parameter->decl_specifiers.type))
+	    ++implicit_template_parms;
+
+	  decl = grokdeclarator (parameter->declarator,
+				 &parameter->decl_specifiers,
+				 PARM,
+				 parameter->default_argument != NULL_TREE,
+				 &parameter->decl_specifiers.attributes);
+	}
 
       deprecated_state = DEPRECATED_NORMAL;
 
@@ -18027,6 +18041,17 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
   parser->in_unbraced_linkage_specification_p
     = saved_in_unbraced_linkage_specification_p;
 
+  if (parameters != error_mark_node && implicit_template_parms)
+    {
+      parameters = add_implicit_template_parms (implicit_template_parms,
+						parameters);
+
+      // Let the parser know that there's an extra parameter list active if this
+      // function has become a template.
+      if (fully_implicit_template)
+	++parser->num_template_parameter_lists;
+    }
+
   return parameters;
 }
 
@@ -20033,7 +20058,14 @@ cp_parser_member_declaration (cp_parser* parser)
 							      attributes);
 		  /* If the member was not a friend, declare it here.  */
 		  if (!friend_p)
-		    finish_member_declaration (decl);
+		    {
+		      if (fully_implicit_template)
+			{
+			  decl = finish_fully_implicit_template (decl);
+			  --parser->num_template_parameter_lists;
+			}
+		      finish_member_declaration (decl);
+		    }
 		  /* Peek at the next token.  */
 		  token = cp_lexer_peek_token (parser->lexer);
 		  /* If the next token is a semicolon, consume it.  */
@@ -20049,6 +20081,11 @@ cp_parser_member_declaration (cp_parser* parser)
 				  initializer, /*init_const_expr_p=*/true,
 				  asm_specification,
 				  attributes);
+		if (fully_implicit_template)
+		  {
+		    decl = finish_fully_implicit_template (decl);
+		    --parser->num_template_parameter_lists;
+		  }
 	    }
 
 	  /* Reset PREFIX_ATTRIBUTES.  */
@@ -22316,6 +22353,12 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
     = saved_num_template_parameter_lists;
   parser->in_function_body = saved_in_function_body;
 
+  if (fully_implicit_template)
+    {
+      finish_fully_implicit_template (/*member_decl_opt=*/0);
+      --parser->num_template_parameter_lists;
+    }
+
   return fn;
 }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3694ccc..549430a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -21022,31 +21022,65 @@ is_auto (const_tree type)
     return false;
 }
 
-/* Returns true iff TYPE contains a use of 'auto'.  Since auto can only
-   appear as a type-specifier for the declaration in question, we don't
-   have to look through the whole type.  */
+/* Returns the first tree within T that is directly matched by PRED.  T may be a
+   type or PARM_DECL and is incrementally decomposed toward it's type-specifier
+   until a match is found.  NULL_TREE is returned if PRED does not match any
+   part of T.
 
-tree
-type_uses_auto (tree type)
+   This is primarily intended for detecting whether T uses `auto' or a concept
+   identifier.  Since either of these can only appear as a type-specifier for
+   the declaration in question, only top-level qualifications are traversed;
+   find_type_usage does not look through the whole type.  */
+
+static inline tree
+find_type_usage (tree t, bool (*pred) (const_tree))
 {
   enum tree_code code;
-  if (is_auto (type))
-    return type;
+  if (pred (t))
+    return t;
 
-  code = TREE_CODE (type);
+  code = TREE_CODE (t);
 
   if (code == POINTER_TYPE || code == REFERENCE_TYPE
-      || code == OFFSET_TYPE || code == FUNCTION_TYPE
-      || code == METHOD_TYPE || code == ARRAY_TYPE)
-    return type_uses_auto (TREE_TYPE (type));
+      || code == PARM_DECL || code == OFFSET_TYPE
+      || code == FUNCTION_TYPE || code == METHOD_TYPE
+      || code == ARRAY_TYPE)
+    return find_type_usage (TREE_TYPE (t), pred);
 
-  if (TYPE_PTRMEMFUNC_P (type))
-    return type_uses_auto (TREE_TYPE (TREE_TYPE
-				   (TYPE_PTRMEMFUNC_FN_TYPE (type))));
+  if (TYPE_PTRMEMFUNC_P (t))
+    return find_type_usage
+      (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (t))), pred);
 
   return NULL_TREE;
 }
 
+/* Returns the TEMPLATE_TYPE_PARM in TYPE representing `auto' iff TYPE contains
+   a use of `auto'.  Returns NULL_TREE otherwise.  */
+
+tree type_uses_auto (tree type)
+{
+  return find_type_usage (type, is_auto);
+}
+
+/* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto',
+   'decltype(auto)' or a concept.  */
+
+bool
+is_auto_or_concept (const_tree type)
+{
+  return is_auto (type); // or concept
+}
+
+/* Returns the TEMPLATE_TYPE_PARM in TYPE representing a generic type (`auto' or
+   a concept identifier) iff TYPE contains a use of a generic type.  Returns
+   NULL_TREE otherwise.  */
+
+tree type_uses_auto_or_concept (tree type)
+{
+  return find_type_usage (type, is_auto_or_concept);
+}
+
+
 /* For a given template T, return the vector of typedefs referenced
    in T for which access check is needed at T instantiation time.
    T is either  a FUNCTION_DECL or a RECORD_TYPE.
@@ -21197,4 +21231,124 @@ print_template_statistics (void)
 	   htab_collisions (type_specializations));
 }
 
+/* Create an identifier for a generic parameter type (a synthesized
+   template parameter implied by `auto' or a concept identifier). */
+
+static tree
+make_generic_type_name (int i)
+{
+  char buf[32];
+  sprintf (buf, "__GenT%d", i);
+  return get_identifier (buf);
+}
+
+/* Predicate that behaves as is_auto_or_concept but matches the parent
+   node of the generic type rather than the generic type itself.  This
+   allows for type transformation in add_implicit_template_parms.  */
+
+static inline bool
+tree_type_is_auto_or_concept (const_tree t)
+{
+  return TREE_TYPE (t) && is_auto_or_concept (TREE_TYPE (t));
+}
+
+/* Add COUNT implicit template parameters gleaned from the generic
+   type parameters in PARAMETERS to the CURRENT_TEMPLATE_PARMS
+   (creating a new template parameter list if necessary).  Returns
+   PARAMETERS suitably rewritten to reference the newly created types
+   or ERROR_MARK_NODE on failure.  */
+
+tree
+add_implicit_template_parms (size_t count, tree parameters)
+{
+  gcc_assert (current_binding_level->kind == sk_function_parms);
+
+  cp_binding_level *fn_parms_scope = current_binding_level;
+
+  bool become_template =
+    fn_parms_scope->level_chain->kind != sk_template_parms;
+
+  size_t synth_idx = 0;
+  tree tparms = NULL_TREE;
+
+  // Roll back a scope level and either introduce a new template parameter list
+  // or update an existing one.  The function scope is added back after template
+  // parameter synthesis below.
+  current_binding_level = fn_parms_scope->level_chain;
+
+  if (become_template)
+    {
+      ++fully_implicit_template;
+      push_deferring_access_checks (dk_deferred);
+      begin_template_parm_list ();
+    }
+  else // extend current template parameter list
+    {
+      gcc_assert (current_template_parms);
+
+      // pop the innermost template parms into tparms
+      tree inner_vec = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+      current_template_parms = TREE_CHAIN (current_template_parms);
+      for (size_t n = 0, end = TREE_VEC_LENGTH (inner_vec); n < end; ++n)
+	tparms = chainon (tparms, TREE_VEC_ELT (inner_vec, n));
+
+      ++processing_template_parmlist;
+    }
+
+  for (tree p = parameters; p && synth_idx < count; p = TREE_CHAIN (p))
+    {
+      tree generic_type_ptr
+	= find_type_usage (TREE_VALUE (p), tree_type_is_auto_or_concept);
+
+      if (!generic_type_ptr)
+	continue;
+
+      tree synth_id = make_generic_type_name (synth_idx++);
+      tree synth_tmpl_parm = finish_template_type_parm (class_type_node,
+							synth_id);
+      tparms = process_template_parm (tparms, DECL_SOURCE_LOCATION (TREE_VALUE
+								    (p)),
+				      build_tree_list (NULL_TREE,
+						       synth_tmpl_parm),
+				      /*non_type=*/false,
+				      /*param_pack=*/false); // TODO: support 'auto...'
+
+      // Rewrite the type of P to be the template_parm added above (getdecls is
+      // used to retrieve it since it is the most recent declaration in this
+      // scope).
+      TREE_TYPE (generic_type_ptr) = TREE_TYPE (getdecls ());
+    }
+
+  gcc_assert (synth_idx == count);
+
+  push_binding_level (fn_parms_scope);
+
+  end_template_parm_list (tparms);
+
+  return parameters;
+}
+
+/* Finish the declaration of a fully implicit function template.  Such a
+   template has no explicit template parameter list so has not been through the
+   normal template head and tail processing.  add_implicit_template_parms tries
+   to do the head; this tries to do the tail.  MEMBER_DECL_OPT should be
+   provided if the declaration is a class member such that it's template
+   declaration can be completed.  If MEMBER_DECL_OPT is provided the finished
+   form is returned.  Otherwise NULL_TREE is returned. */
+
+tree
+finish_fully_implicit_template (tree member_decl_opt)
+{
+  gcc_assert (fully_implicit_template > 0);
+
+  pop_deferring_access_checks ();
+  if (member_decl_opt)
+    member_decl_opt = finish_member_template_decl (member_decl_opt);
+  end_template_decl ();
+
+  --fully_implicit_template;
+
+  return member_decl_opt;
+}
+
 #include "gt-cp-pt.h"
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 1/3] [lambda] Support template-parameter-list in lambda-declarator.
  2013-07-19  9:01   ` [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches Adam Butcher
@ 2013-07-19  9:01     ` Adam Butcher
  2013-07-19 17:33       ` Jason Merrill
  2013-07-19  9:01     ` [PATCH 3/3] [lambda] [basic-terse-templates] Support using `auto' in a function parameter list to introduce an implicit template parameter Adam Butcher
  2013-07-19  9:06     ` [PATCH 2/3] [lambda] Avoid crash on symbol table writing when generic lambda declared with iostream (or potentially other code) included Adam Butcher
  2 siblings, 1 reply; 39+ messages in thread
From: Adam Butcher @ 2013-07-19  9:01 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Andrew Sutton, Adam Butcher

---
 gcc/cp/decl2.c  |  5 +++--
 gcc/cp/lambda.c |  9 ++++++++-
 gcc/cp/parser.c | 36 ++++++++++++++++++++++++++++++++++--
 gcc/cp/pt.c     |  4 +++-
 4 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 1573ced..c166f6e 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -507,8 +507,9 @@ check_member_template (tree tmpl)
       || (TREE_CODE (decl) == TYPE_DECL
 	  && MAYBE_CLASS_TYPE_P (TREE_TYPE (decl))))
     {
-      /* The parser rejects template declarations in local classes.  */
-      gcc_assert (!current_function_decl);
+      /* The parser rejects template declarations in local classes
+	 (with the exception of generic lambdas).  */
+      gcc_assert (!current_function_decl || LAMBDA_FUNCTION_P (decl));
       /* The parser rejects any use of virtual in a function template.  */
       gcc_assert (!(TREE_CODE (decl) == FUNCTION_DECL
 		    && DECL_VIRTUAL_P (decl)));
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index a53e692..98a7925 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -196,7 +196,7 @@ lambda_function (tree lambda)
 			  /*protect=*/0, /*want_type=*/false,
 			  tf_warning_or_error);
   if (lambda)
-    lambda = BASELINK_FUNCTIONS (lambda);
+    lambda = STRIP_TEMPLATE (get_first_fn (lambda));
   return lambda;
 }
 
@@ -759,6 +759,13 @@ maybe_add_lambda_conv_op (tree type)
   if (processing_template_decl)
     return;
 
+  if (DECL_TEMPLATE_INFO (callop) && DECL_TEMPLATE_RESULT
+        (DECL_TI_TEMPLATE (callop)) == callop)
+    {
+      warning (0, "Conversion of a generic lambda to a function pointer is not currently implemented.");
+      return;
+    }
+
   if (DECL_INITIAL (callop) == NULL_TREE)
     {
       /* If the op() wasn't instantiated due to errors, give up.  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 4b683bf..48c95e6 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8790,6 +8790,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
 /* Parse the (optional) middle of a lambda expression.
 
    lambda-declarator:
+     < template-parameter-list [opt] >
      ( parameter-declaration-clause [opt] )
        attribute-specifier [opt]
        mutable [opt]
@@ -8809,10 +8810,32 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
   tree param_list = void_list_node;
   tree attributes = NULL_TREE;
   tree exception_spec = NULL_TREE;
+  tree template_param_list = NULL_TREE;
   tree t;
 
-  /* The lambda-declarator is optional, but must begin with an opening
-     parenthesis if present.  */
+  /* The template-parameter-list is optional, but must begin with
+     an opening angle if present.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+    {
+      cp_lexer_consume_token (parser->lexer);
+
+      if (cxx_dialect < cxx1y)
+	cp_parser_error (parser,
+			 "Generic lambdas are only supported in C++1y mode.");
+
+      push_deferring_access_checks (dk_deferred);
+
+      template_param_list = cp_parser_template_parameter_list (parser);
+
+      cp_parser_skip_to_end_of_template_parameter_list (parser);
+
+      /* We just processed one more parameter list.  */
+      ++parser->num_template_parameter_lists;
+    }
+
+  /* The parameter-declaration-clause is optional (unless
+     template-parameter-list was given), but must begin with an
+     opening parenthesis if present.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
     {
       cp_lexer_consume_token (parser->lexer);
@@ -8858,6 +8881,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 
       leave_scope ();
     }
+  else if (template_param_list != NULL_TREE) // generate diagnostic
+    cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
 
   /* Create the function call operator.
 
@@ -8901,6 +8926,13 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 	DECL_ARTIFICIAL (fco) = 1;
 	/* Give the object parameter a different name.  */
 	DECL_NAME (DECL_ARGUMENTS (fco)) = get_identifier ("__closure");
+	if (template_param_list)
+	  {
+	    pop_deferring_access_checks ();
+	    fco = finish_member_template_decl (fco);
+	    finish_template_decl (template_param_list);
+	    --parser->num_template_parameter_lists;
+	  }
       }
 
     finish_member_declaration (fco);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index de054ac..3694ccc 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -9028,7 +9028,9 @@ instantiate_class_template_1 (tree type)
       tree decl = lambda_function (type);
       if (decl)
 	{
-	  instantiate_decl (decl, false, false);
+	  if (!DECL_TEMPLATE_INFO (decl) || DECL_TEMPLATE_RESULT
+	      (DECL_TI_TEMPLATE (decl)) != decl)
+	    instantiate_decl (decl, false, false);
 
 	  /* We need to instantiate the capture list from the template
 	     after we've instantiated the closure members, but before we
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches
  2013-07-11 17:35 ` [C++14/lambda] Experimental polymorphic lambda patches Jason Merrill
  2013-07-12  2:04   ` Gabriel Dos Reis
@ 2013-07-19  9:01   ` Adam Butcher
  2013-07-19  9:01     ` [PATCH 1/3] [lambda] Support template-parameter-list in lambda-declarator Adam Butcher
                       ` (2 more replies)
  1 sibling, 3 replies; 39+ messages in thread
From: Adam Butcher @ 2013-07-19  9:01 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Andrew Sutton, Adam Butcher

Hi Jason,

There follows a re-spin of the previous patches.  I've addressed your
review comments and cleaned up much of the implementation (including
code location).  I've also redesigned the `auto' param handling
(implicit function template generation) to work for plain functions
and member functions as well as lambdas.

This is intended as a step towards implementing the basics of `Terse
Templates' as proposed in section 6.2.1 of N3580.  Indeed, if you
consider `auto' to be a concept whose constexpr implementation simply
returns 'true', this is what the current implementation does.  I've
Ccd Andrew Sutton for visibility of the work in this area (PATCH 3/3
is the one of interest).  I might have a play with this on the
c++-concepts branch if I get time.

As well as the syntax supported by the previous patch-set, this
re-spin also supports the syntax demonstrated by the following
examples for plain functions and member functions:

  4. auto plain_fn_or_mem_fn (auto x, auto& y, auto const& z) { return x + y + z; }
  5. template <typename Z> auto plain_fn_or_mem_fn (auto x, auto& y, Z const& z) { return x + y + z; }

Currently out-of-line implicit member templates are supported but the
template parameter list must be explicitly specified at the definition
and the return type must be specified.  For example:

   struct S
   {
      auto f(auto& a, auto b) { a += b; }
      void g(auto& a, auto b);
   };

   template <typename A, typename B>
   void S::g(A& a, B b)
   {
      a += b;
   }


On Wed, 10 Jul 2013 19:35:24 -0700, Jason Merrill wrote:
> On 07/01/2013 04:26 PM, Adam Butcher wrote:
> > Any comments appreciated.  Guidance on implementing the conversion
> > operator for stateless generic lambdas would be useful.  I've made a
> > few attempts which were lacking!
>
> It seemed to me that N3649's description of the semantics should
> translate pretty easily into an implementation.
>
Indeed.  It is quite simple from a spec point of view.  And a plain
C++ implementation would be easy.  Unfortunately in the compiler I
have not found it as straight-forward.

> What problems are you running into?
>
My previous attempts tried to reuse the existing non-template
conversion-op code with numerous conditional blocks that got out of
hand -- and SEGVd or ICEd to boot.  I think it was due to not properly
transforming the type declarators.

Since reworking the implicit function template code I am going to
experiment with a cleaner way.  I'll get back to you if I get it done
or if I hit a brick wall!

As always, any feedback appreciated.

Cheers,
Adam


Patch summary (3):
  Support template-parameter-list in lambda-declarator.
  Avoid crash on symbol table writing when generic lambda declared with
    iostream (or potentially other code) included.
  Support using `auto' in a function parameter list to introduce an
    implicit template parameter.

 gcc/cp/cp-tree.h |  11 ++++
 gcc/cp/decl.c    |   4 +-
 gcc/cp/decl2.c   |   5 +-
 gcc/cp/lambda.c  |   9 ++-
 gcc/cp/parser.c  |  93 +++++++++++++++++++++++++---
 gcc/cp/pt.c      | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 gcc/symtab.c     |  18 ++++++
 7 files changed, 297 insertions(+), 29 deletions(-)

-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 2/3] [lambda] Avoid crash on symbol table writing when generic lambda declared with iostream (or potentially other code) included.
  2013-07-19  9:01   ` [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches Adam Butcher
  2013-07-19  9:01     ` [PATCH 1/3] [lambda] Support template-parameter-list in lambda-declarator Adam Butcher
  2013-07-19  9:01     ` [PATCH 3/3] [lambda] [basic-terse-templates] Support using `auto' in a function parameter list to introduce an implicit template parameter Adam Butcher
@ 2013-07-19  9:06     ` Adam Butcher
  2 siblings, 0 replies; 39+ messages in thread
From: Adam Butcher @ 2013-07-19  9:06 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Andrew Sutton, Adam Butcher

---
 gcc/symtab.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/gcc/symtab.c b/gcc/symtab.c
index 85d47a8..1ada0f7 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -116,6 +116,15 @@ insert_to_assembler_name_hash (symtab_node node, bool with_clones)
 
       tree name = DECL_ASSEMBLER_NAME (node->symbol.decl);
 
+
+      // FIXME: how does this nullptr get here when declaring a C++
+      // FIXME: generic lambda and including iostream (or presumably
+      // FIXME: any other header with whatever property is triggering
+      // FIXME: this)!?
+      //
+      if (name == 0)
+	return;
+
       aslot = htab_find_slot_with_hash (assembler_name_hash, name,
 					decl_assembler_name_hash (name),
 					INSERT);
@@ -156,6 +165,15 @@ unlink_from_assembler_name_hash (symtab_node node, bool with_clones)
       else
 	{
 	  tree name = DECL_ASSEMBLER_NAME (node->symbol.decl);
+
+	  // FIXME: how does this nullptr get here when declaring a C++
+	  // FIXME: generic lambda and including iostream (or presumably
+	  // FIXME: any other header with whatever property is triggering
+	  // FIXME: this)!?
+	  //
+	  if (name == 0)
+	    return;
+
           void **slot;
 	  slot = htab_find_slot_with_hash (assembler_name_hash, name,
 					   decl_assembler_name_hash (name),
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 1/3] [lambda] Support template-parameter-list in lambda-declarator.
  2013-07-19  9:01     ` [PATCH 1/3] [lambda] Support template-parameter-list in lambda-declarator Adam Butcher
@ 2013-07-19 17:33       ` Jason Merrill
  2013-08-03 13:29         ` [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches Adam Butcher
  0 siblings, 1 reply; 39+ messages in thread
From: Jason Merrill @ 2013-07-19 17:33 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Andrew Sutton

On 07/19/2013 05:00 AM, Adam Butcher wrote:
> +      warning (0, "Conversion of a generic lambda to a function pointer is not
> currently implemented.");
...
> +                        "Generic lambdas are only supported in C++1y mode.");

We generally don't capitalize diagnostics or end them with a period. 
And the second message should mention "-std=c++1y or -std=gnu++1y".

> +      push_deferring_access_checks (dk_deferred);

Why do you need this?

> +/* Nonzero if the function being declared was made a template due to it's

"its"

> +         error ("parameter declared %<auto%> (unsupported prior to C++1y)");

This should also mention the compiler flags.  We should probably 
introduce a maybe_warn_cpp1y function to go along with ..._cpp0x.

> +  else // extend current template parameter list

Do we still need to do this, now that we're handling all the parameters 
at the end of the parameter list?

Jason

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches
  2013-07-19 17:33       ` Jason Merrill
@ 2013-08-03 13:29         ` Adam Butcher
  2013-08-03 13:29           ` [PATCH 3/4] [lambda] Address review comments Adam Butcher
                             ` (3 more replies)
  0 siblings, 4 replies; 39+ messages in thread
From: Adam Butcher @ 2013-08-03 13:29 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

Hi Jason,

I've addressed your review comments and provided support for
conversion to function pointer for generic lambdas.  I've sent the
patches as updates to the previous set.  I'll wait for any further
comments before formalizing them into a cleaner set.

The changes now support the examples given in N3690 §5.1.2.{5,6} and
the test program included at the end of this mail.  I think it is
feature-complete.

On 19.07.2013 17:56, Jason Merrill wrote:
> On 07/19/2013 05:00 AM, Adam Butcher wrote:
> >
> > +      push_deferring_access_checks (dk_deferred);
> >
> Why do you need this?
>
I don't think I do.  I had thought that it would be necessary to
handle deferred friendship situations but I don't think that can apply
to generic lambdas.  I've ditched them.

> > +/* Nonzero if the function being declared was made a template due to it's
> >
> "its"
>
I've fixed this and a couple of others in my own comments.  I've also
fixed others I found in the same file (as a separate patch).

> > +  else // extend current template parameter list
> >
> Do we still need to do this, now that we're handling all the
> parameters at the end of the parameter list?
>
I think extending the current parameter list is still needed when
'auto' is found in a parameter declaration of an existing function
template.

E.g.
   template <typename T> void f(T& t, auto& a) { ... }

I think that it is necessary to keep everything consistent as if the
template had been declared in the 'conventional' way.  The template
parameter generated for the generic parameter 'a' effectively makes
'f's template parameter list into '<typename T, typename __Gen0>'.

Cheers,
Adam


Patch summary (4):
  Preserve type qualifiers for implicit template parameters.
  Support implicit conversion of a stateless generic lambda to a
    function pointer.
  Address review comments.
  Grammar "it's" to "its".

 gcc/cp/cp-tree.h |  2 +-
 gcc/cp/decl.c    |  3 ++-
 gcc/cp/lambda.c  | 77 +++++++++++++++++++++++++++++++++++++++++---------------
 gcc/cp/parser.c  |  6 ++---
 gcc/cp/pt.c      | 21 ++++++++++------
 5 files changed, 76 insertions(+), 33 deletions(-)


Test program:


  /* Function templates at namespace scope.  */
  
  auto f1 (auto& a, auto const& b) { return a += b; }
  
  template <typename A>
  auto f2 (A& a, auto const& b) { return a += b; }
  
  template <typename B>
  auto f3 (auto& a, B const& b) { return a += b; }
  
  template <typename A, typename B>
  auto f4 (A& a, B const& b) { return a += b; }
  
  
  struct S
  {
    /* Non-static member function templates.  */
  
    auto mf1 (auto& a, auto const& b) { return a += b; }
  
    template <typename A>
    auto mf2 (A& a, auto const& b) { return a += b; }
  
    template <typename B>
    auto mf3 (auto& a, B const& b) { return a += b; }
  
    template <typename A, typename B>
    auto mf4 (A& a, B const& b) { return a += b; }
  
    /* Static member function templates.  */
  
    static auto smf1 (auto& a, auto const& b) { return a += b; }
  
    template <typename A>
    static auto smf2 (A& a, auto const& b) { return a += b; }
  
    template <typename B>
    static auto smf3 (auto& a, B const& b) { return a += b; }
  
    template <typename A, typename B>
    static auto smf4 (A& a, B const& b) { return a += b; }
  };
  
  
  #undef NDEBUG
  #include <cassert>
  
  
  #define CHECK(A, b, f) do {      \
     A a1 = 5, a2 = 12;            \
     auto r1 = f (a1, b);          \
     auto r2 = f (a2, b);          \
     assert ((#f, a1 == 5 + b));   \
     assert ((#f, a2 == 12 + b));  \
     assert ((#f, r1 == a1));      \
     assert ((#f, r2 == a2));      \
  } while (0)
  
  
  #define INVOKEi(f, A, b, i) do { CHECK (A, b, f ## i); } while (0)
  #define INVOKE4(f, A, b) do { INVOKEi (f, A, b, 1); \
  			      INVOKEi (f, A, b, 2); \
  			      INVOKEi (f, A, b, 3); \
  			      INVOKEi (f, A, b, 4); } while (0)
  
  #define AS_FUNi(f, A, b, i) do { CHECK (A, b, f ## i._FUN); } while (0)
  #define AS_FUN4(f, A, b) do { AS_FUNi (f, A, b, 1); \
  			      AS_FUNi (f, A, b, 2); \
  			      AS_FUNi (f, A, b, 3); \
  			      AS_FUNi (f, A, b, 4); } while (0)
  
  #define AS_PTRi(f, A, B, b, i) do { A (*pfn) (A&, B const&) = f ## i; \
  				    CHECK (A, b, pfn); } while (0)
  #define AS_PTR4(f, A, B, b) do { AS_PTRi (f, A, B, b, 1); \
  				 AS_PTRi (f, A, B, b, 2); \
  				 AS_PTRi (f, A, B, b, 3); \
  				 AS_PTRi (f, A, B, b, 4); } while (0)
  
  
  int main()
  {
    /* Check namespace templates.  */
  
    INVOKE4 (f, float, 7);
    AS_PTR4 (f, float, int, 7);
  
    /* Check member templates.  */
  
    S s;
    INVOKE4 (s.mf, float, 7);
    INVOKE4 (s.smf, float, 7);
    INVOKE4 (S::smf, float, 7);
    AS_PTR4 (s.smf, float, int, 7);
    AS_PTR4 (S::smf, float, int, 7);
  
    /* Regression check non-template stateless lambda and its conversion
       to function pointer.  */
  
    auto lf0 = [] (float& a, int const& b) { return a += b; };
  
    INVOKEi (lf, float, 7, 0);
    AS_FUNi (lf, float, 7, 0);
    AS_PTRi (lf, float, int, 7, 0);
  
    /* Check stateless lambda templates.  */
  
    auto lf1 = [] (auto& a, auto const& b) { return a += b; };
    auto lf2 = [] <typename A> (A& a, auto const& b) { return a += b; };
    auto lf3 = [] <typename B> (auto& a, B const& b) { return a += b; };
    auto lf4 = [] <typename A, typename B> (A& a, B const& b) { return a += b; };
  
    INVOKE4 (lf, float, 7);
    AS_FUN4 (lf, float, 7);
    AS_PTR4 (lf, float, int, 7);
  
    /* Check capturing lambda templates.  */
  
    int i;
  
    auto lc1 = [i] (auto& a, auto const& b) { return a += b; };
    auto lc2 = [i] <typename A> (A& a, auto const& b) { return a += b; };
    auto lc3 = [i] <typename B> (auto& a, B const& b) { return a += b; };
    auto lc4 = [i] <typename A, typename B> (A& a, B const& b) { return a += b; };
  
    INVOKE4 (lc, float, 7);
  }


-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 2/4] [lambda] Support implicit conversion of a stateless generic lambda to a function pointer.
  2013-08-03 13:29         ` [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches Adam Butcher
                             ` (2 preceding siblings ...)
  2013-08-03 13:29           ` [PATCH 4/4] Grammar "it's" to "its" Adam Butcher
@ 2013-08-03 13:29           ` Adam Butcher
  2013-08-03 16:19             ` Jason Merrill
  3 siblings, 1 reply; 39+ messages in thread
From: Adam Butcher @ 2013-08-03 13:29 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

---
 gcc/cp/lambda.c | 77 ++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 57 insertions(+), 20 deletions(-)

diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 98a7925..cf662bb 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -759,12 +759,9 @@ maybe_add_lambda_conv_op (tree type)
   if (processing_template_decl)
     return;
 
-  if (DECL_TEMPLATE_INFO (callop) && DECL_TEMPLATE_RESULT
-        (DECL_TI_TEMPLATE (callop)) == callop)
-    {
-      warning (0, "Conversion of a generic lambda to a function pointer is not currently implemented.");
-      return;
-    }
+  bool generic_lambda_p
+    = DECL_TEMPLATE_INFO (callop)
+    && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop;
 
   if (DECL_INITIAL (callop) == NULL_TREE)
     {
@@ -773,7 +770,38 @@ maybe_add_lambda_conv_op (tree type)
       return;
     }
 
-  stattype = build_function_type (TREE_TYPE (TREE_TYPE (callop)),
+  tree fn_result = TREE_TYPE (TREE_TYPE (callop));
+  tree fn_args = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop)));
+
+  if (generic_lambda_p)
+    {
+      /* Construct the dependent member call for the static member function
+	 '_FUN' and remove 'auto' from it's return type to allow for simple
+	 implementation of the conversion operator.  */
+
+      tree instance = build_nop (type, null_pointer_node);
+      argvec = make_tree_vector ();
+      for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
+	{
+	  mark_exp_read (arg);
+	  vec_safe_push (argvec, arg);
+	}
+
+      tree objfn = build_min (COMPONENT_REF, NULL_TREE,
+			      instance, DECL_NAME (callop), NULL_TREE);
+      call = build_nt_call_vec (objfn, argvec);
+
+      if (type_uses_auto (fn_result))
+	{
+	  ++processing_template_decl;
+	  fn_result = finish_decltype_type
+	    (call, /*id_expression_or_member_access_p=*/false,
+	     tf_warning_or_error);
+	  --processing_template_decl;
+	}
+    }
+
+  stattype = build_function_type (fn_result,
 				  FUNCTION_ARG_CHAIN (callop));
 
   /* First build up the conversion op.  */
@@ -801,6 +829,9 @@ maybe_add_lambda_conv_op (tree type)
   if (nested)
     DECL_INTERFACE_KNOWN (fn) = 1;
 
+  if (generic_lambda_p)
+    fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop));
+
   add_method (type, fn, NULL_TREE);
 
   /* Generic thunk code fails for varargs; we'll complain in mark_used if
@@ -827,8 +858,8 @@ maybe_add_lambda_conv_op (tree type)
   DECL_NOT_REALLY_EXTERN (fn) = 1;
   DECL_DECLARED_INLINE_P (fn) = 1;
   DECL_STATIC_FUNCTION_P (fn) = 1;
-  DECL_ARGUMENTS (fn) = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop)));
-  for (arg = DECL_ARGUMENTS (fn); arg; arg = DECL_CHAIN (arg))
+  DECL_ARGUMENTS (fn) = fn_args;
+  for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
     {
       /* Avoid duplicate -Wshadow warnings.  */
       DECL_NAME (arg) = NULL_TREE;
@@ -837,6 +868,9 @@ maybe_add_lambda_conv_op (tree type)
   if (nested)
     DECL_INTERFACE_KNOWN (fn) = 1;
 
+  if (generic_lambda_p)
+    fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop));
+
   add_method (type, fn, NULL_TREE);
 
   if (nested)
@@ -860,19 +894,22 @@ maybe_add_lambda_conv_op (tree type)
   body = begin_function_body ();
   compound_stmt = begin_compound_stmt (0);
 
-  arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)),
-		null_pointer_node);
-  argvec = make_tree_vector ();
-  argvec->quick_push (arg);
-  for (arg = DECL_ARGUMENTS (statfn); arg; arg = DECL_CHAIN (arg))
+  if (!generic_lambda_p)
     {
-      mark_exp_read (arg);
-      vec_safe_push (argvec, arg);
+      arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)),
+		    null_pointer_node);
+      argvec = make_tree_vector ();
+      argvec->quick_push (arg);
+      for (arg = DECL_ARGUMENTS (statfn); arg; arg = DECL_CHAIN (arg))
+	{
+	  mark_exp_read (arg);
+	  vec_safe_push (argvec, arg);
+	}
+      call = build_call_a (callop, argvec->length (), argvec->address ());
+      CALL_FROM_THUNK_P (call) = 1;
+      if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
+	call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
     }
-  call = build_call_a (callop, argvec->length (), argvec->address ());
-  CALL_FROM_THUNK_P (call) = 1;
-  if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
-    call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
   call = convert_from_reference (call);
   finish_return_stmt (call);
 
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 1/4] [lambda] Preserve type qualifiers for implicit template parameters.
  2013-08-03 13:29         ` [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches Adam Butcher
  2013-08-03 13:29           ` [PATCH 3/4] [lambda] Address review comments Adam Butcher
@ 2013-08-03 13:29           ` Adam Butcher
  2013-08-03 13:29           ` [PATCH 4/4] Grammar "it's" to "its" Adam Butcher
  2013-08-03 13:29           ` [PATCH 2/4] [lambda] Support implicit conversion of a stateless generic lambda to a function pointer Adam Butcher
  3 siblings, 0 replies; 39+ messages in thread
From: Adam Butcher @ 2013-08-03 13:29 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

---
 gcc/cp/pt.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index dea1ec0..6e209f8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -21317,8 +21317,15 @@ add_implicit_template_parms (size_t count, tree parameters)
 
       // Rewrite the type of P to be the template_parm added above (getdecls is
       // used to retrieve it since it is the most recent declaration in this
-      // scope).
-      TREE_TYPE (generic_type_ptr) = TREE_TYPE (getdecls ());
+      // scope).  Qualifiers need to be preserved also.
+
+      tree& cur_type = TREE_TYPE (generic_type_ptr);
+      tree new_type = TREE_TYPE (getdecls ());
+
+      if (TYPE_QUALS (cur_type))
+	cur_type = cp_build_qualified_type (new_type, TYPE_QUALS (cur_type));
+      else
+	cur_type = new_type;
     }
 
   gcc_assert (synth_idx == count);
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 3/4] [lambda] Address review comments.
  2013-08-03 13:29         ` [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches Adam Butcher
@ 2013-08-03 13:29           ` Adam Butcher
  2013-08-03 13:40             ` Gabriel Dos Reis
  2013-08-03 13:29           ` [PATCH 1/4] [lambda] Preserve type qualifiers for implicit template parameters Adam Butcher
                             ` (2 subsequent siblings)
  3 siblings, 1 reply; 39+ messages in thread
From: Adam Butcher @ 2013-08-03 13:29 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

---
 gcc/cp/cp-tree.h | 2 +-
 gcc/cp/decl.c    | 3 ++-
 gcc/cp/lambda.c  | 2 +-
 gcc/cp/parser.c  | 6 ++----
 gcc/cp/pt.c      | 4 ++--
 5 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 64ff4e3..17bb8b9 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1089,7 +1089,7 @@ struct GTY(()) saved_scope {
 #define processing_specialization scope_chain->x_processing_specialization
 #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation
 
-/* Nonzero if the function being declared was made a template due to it's
+/* Nonzero if the function being declared was made a template due to its
    parameter list containing generic type specifiers (`auto' or concept
    identifiers) rather than an explicit template parameter list.  */
 
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 98e8dc9..72332ba 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10331,7 +10331,8 @@ grokdeclarator (const cp_declarator *declarator,
 
       if (type_uses_auto (type) && cxx_dialect < cxx1y)
 	{
-	  error ("parameter declared %<auto%> (unsupported prior to C++1y)");
+	  error ("use of %<auto%> in parameter declaration only available with "
+		 "-std=c++1y or -std=gnu++1y");
 	  type = error_mark_node;
 	}
 
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index cf662bb..015e6d1 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -776,7 +776,7 @@ maybe_add_lambda_conv_op (tree type)
   if (generic_lambda_p)
     {
       /* Construct the dependent member call for the static member function
-	 '_FUN' and remove 'auto' from it's return type to allow for simple
+	 '_FUN' and remove 'auto' from its return type to allow for simple
 	 implementation of the conversion operator.  */
 
       tree instance = build_nop (type, null_pointer_node);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 45f5d7e..5169f66 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8821,9 +8821,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 
       if (cxx_dialect < cxx1y)
 	cp_parser_error (parser,
-			 "Generic lambdas are only supported in C++1y mode.");
-
-      push_deferring_access_checks (dk_deferred);
+			 "generic lambdas are only available with "
+			 "-std=c++1y or -std=gnu++1y");
 
       template_param_list = cp_parser_template_parameter_list (parser);
 
@@ -8928,7 +8927,6 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 	DECL_NAME (DECL_ARGUMENTS (fco)) = get_identifier ("__closure");
 	if (template_param_list)
 	  {
-	    pop_deferring_access_checks ();
 	    fco = finish_member_template_decl (fco);
 	    finish_template_decl (template_param_list);
 	    --parser->num_template_parameter_lists;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 6e209f8..a7baaba 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -21025,7 +21025,7 @@ is_auto (const_tree type)
 }
 
 /* Returns the first tree within T that is directly matched by PRED.  T may be a
-   type or PARM_DECL and is incrementally decomposed toward it's type-specifier
+   type or PARM_DECL and is incrementally decomposed toward its type-specifier
    until a match is found.  NULL_TREE is returned if PRED does not match any
    part of T.
 
@@ -21341,7 +21341,7 @@ add_implicit_template_parms (size_t count, tree parameters)
    template has no explicit template parameter list so has not been through the
    normal template head and tail processing.  add_implicit_template_parms tries
    to do the head; this tries to do the tail.  MEMBER_DECL_OPT should be
-   provided if the declaration is a class member such that it's template
+   provided if the declaration is a class member such that its template
    declaration can be completed.  If MEMBER_DECL_OPT is provided the finished
    form is returned.  Otherwise NULL_TREE is returned. */
 
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 4/4] Grammar "it's" to "its".
  2013-08-03 13:29         ` [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches Adam Butcher
  2013-08-03 13:29           ` [PATCH 3/4] [lambda] Address review comments Adam Butcher
  2013-08-03 13:29           ` [PATCH 1/4] [lambda] Preserve type qualifiers for implicit template parameters Adam Butcher
@ 2013-08-03 13:29           ` Adam Butcher
  2013-08-03 13:36             ` Gabriel Dos Reis
  2013-08-03 13:29           ` [PATCH 2/4] [lambda] Support implicit conversion of a stateless generic lambda to a function pointer Adam Butcher
  3 siblings, 1 reply; 39+ messages in thread
From: Adam Butcher @ 2013-08-03 13:29 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

---
 gcc/cp/pt.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a7baaba..99bc71b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -1986,7 +1986,7 @@ determine_specialization (tree template_id,
 	  tree decl_arg_types;
 
 	  /* This is an ordinary member function.  However, since
-	     we're here, we can assume it's enclosing class is a
+	     we're here, we can assume its enclosing class is a
 	     template class.  For example,
 
 	       template <typename T> struct S { void f(); };
@@ -4337,7 +4337,7 @@ check_default_tmpl_args (tree decl, tree parms, bool is_primary,
 	  || DECL_INITIALIZED_IN_CLASS_P (decl)))
     /* We already checked these parameters when the template was
        declared, so there's no need to do it again now.  This function
-       was defined in class scope, but we're processing it's body now
+       was defined in class scope, but we're processing its body now
        that the class is complete.  */
     return true;
 
@@ -7482,7 +7482,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 	the one of #0.
 
 	When we encounter #1, we want to store the partial instantiation
-	of M (template<class T> S<int>::M<T>) in it's CLASSTYPE_TI_TEMPLATE.
+	of M (template<class T> S<int>::M<T>) in its CLASSTYPE_TI_TEMPLATE.
 
 	For all cases other than this "explicit specialization of member of a
 	class template", we just want to store the most general template into
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 4/4] Grammar "it's" to "its".
  2013-08-03 13:29           ` [PATCH 4/4] Grammar "it's" to "its" Adam Butcher
@ 2013-08-03 13:36             ` Gabriel Dos Reis
  2013-08-03 13:54               ` Adam Butcher
  0 siblings, 1 reply; 39+ messages in thread
From: Gabriel Dos Reis @ 2013-08-03 13:36 UTC (permalink / raw)
  To: Adam Butcher; +Cc: Jason Merrill, gcc-patches, Andrew Sutton

On Thu, Aug 1, 2013 at 7:25 AM, Adam Butcher <adam@jessamine.co.uk> wrote:
> ---
>  gcc/cp/pt.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index a7baaba..99bc71b 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -1986,7 +1986,7 @@ determine_specialization (tree template_id,
>           tree decl_arg_types;
>
>           /* This is an ordinary member function.  However, since
> -            we're here, we can assume it's enclosing class is a
> +            we're here, we can assume its enclosing class is a
>              template class.  For example,
>
>                template <typename T> struct S { void f(); };
> @@ -4337,7 +4337,7 @@ check_default_tmpl_args (tree decl, tree parms, bool is_primary,
>           || DECL_INITIALIZED_IN_CLASS_P (decl)))
>      /* We already checked these parameters when the template was
>         declared, so there's no need to do it again now.  This function
> -       was defined in class scope, but we're processing it's body now
> +       was defined in class scope, but we're processing its body now
>         that the class is complete.  */
>      return true;
>
> @@ -7482,7 +7482,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
>         the one of #0.
>
>         When we encounter #1, we want to store the partial instantiation
> -       of M (template<class T> S<int>::M<T>) in it's CLASSTYPE_TI_TEMPLATE.
> +       of M (template<class T> S<int>::M<T>) in its CLASSTYPE_TI_TEMPLATE.
>
>         For all cases other than this "explicit specialization of member of a
>         class template", we just want to store the most general template into
> --
> 1.8.3
>

OK.
Do you have copyright assignment on file?

-- Gaby

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 3/4] [lambda] Address review comments.
  2013-08-03 13:29           ` [PATCH 3/4] [lambda] Address review comments Adam Butcher
@ 2013-08-03 13:40             ` Gabriel Dos Reis
  2013-08-03 13:51               ` Adam Butcher
  0 siblings, 1 reply; 39+ messages in thread
From: Gabriel Dos Reis @ 2013-08-03 13:40 UTC (permalink / raw)
  To: Adam Butcher; +Cc: Jason Merrill, gcc-patches, Andrew Sutton

On Thu, Aug 1, 2013 at 7:25 AM, Adam Butcher <adam@jessamine.co.uk> wrote:
> ---
>  gcc/cp/cp-tree.h | 2 +-
>  gcc/cp/decl.c    | 3 ++-
>  gcc/cp/lambda.c  | 2 +-
>  gcc/cp/parser.c  | 6 ++----
>  gcc/cp/pt.c      | 4 ++--
>  5 files changed, 8 insertions(+), 9 deletions(-)

When submitting patches, you also need to add ChangeLogs:

  http://www.gnu.org/prep/standards/html_node/Change-Logs.html
  http://gcc.gnu.org/wiki/ChangeLog

-- Gaby

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 3/4] [lambda] Address review comments.
  2013-08-03 13:40             ` Gabriel Dos Reis
@ 2013-08-03 13:51               ` Adam Butcher
  0 siblings, 0 replies; 39+ messages in thread
From: Adam Butcher @ 2013-08-03 13:51 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Jason Merrill, gcc-patches, Andrew Sutton

On 03.08.2013 14:39, Gabriel Dos Reis wrote:
> On Thu, Aug 1, 2013 at 7:25 AM, Adam Butcher <adam@jessamine.co.uk> 
> wrote:
>> ---
>>  gcc/cp/cp-tree.h | 2 +-
>>  gcc/cp/decl.c    | 3 ++-
>>  gcc/cp/lambda.c  | 2 +-
>>  gcc/cp/parser.c  | 6 ++----
>>  gcc/cp/pt.c      | 4 ++--
>>  5 files changed, 8 insertions(+), 9 deletions(-)
>
> When submitting patches, you also need to add ChangeLogs:
>
>   http://www.gnu.org/prep/standards/html_node/Change-Logs.html
>   http://gcc.gnu.org/wiki/ChangeLog
>
These patches were intended as incremental updates to an ongoing review

   http://gcc.gnu.org/ml/gcc-patches/2013-07/threads.html#00755
   http://gcc.gnu.org/ml/gcc-patches/2013-08/msg00130.html

I intend to submit a clean set with appropriate changelog once Jason is 
happy with them.  I wasn't intending these to be committed as is.

Cheers,
Adam

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 4/4] Grammar "it's" to "its".
  2013-08-03 13:36             ` Gabriel Dos Reis
@ 2013-08-03 13:54               ` Adam Butcher
  0 siblings, 0 replies; 39+ messages in thread
From: Adam Butcher @ 2013-08-03 13:54 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Jason Merrill, gcc-patches, Andrew Sutton

On 03.08.2013 14:35, Gabriel Dos Reis wrote:
> On Thu, Aug 1, 2013 at 7:25 AM, Adam Butcher <adam@jessamine.co.uk> 
> wrote:
>> ---
>>  gcc/cp/pt.c | 6 +++---
>>  1 file changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
>> index a7baaba..99bc71b 100644
>> --- a/gcc/cp/pt.c
>> +++ b/gcc/cp/pt.c
>> @@ -1986,7 +1986,7 @@ determine_specialization (tree template_id,
>>           tree decl_arg_types;
>>
>>           /* This is an ordinary member function.  However, since
>> -            we're here, we can assume it's enclosing class is a
>> +            we're here, we can assume its enclosing class is a
>>              template class.  For example,
>>
>>                template <typename T> struct S { void f(); };
>> @@ -4337,7 +4337,7 @@ check_default_tmpl_args (tree decl, tree 
>> parms, bool is_primary,
>>           || DECL_INITIALIZED_IN_CLASS_P (decl)))
>>      /* We already checked these parameters when the template was
>>         declared, so there's no need to do it again now.  This 
>> function
>> -       was defined in class scope, but we're processing it's body 
>> now
>> +       was defined in class scope, but we're processing its body 
>> now
>>         that the class is complete.  */
>>      return true;
>>
>> @@ -7482,7 +7482,7 @@ lookup_template_class_1 (tree d1, tree 
>> arglist, tree in_decl, tree context,
>>         the one of #0.
>>
>>         When we encounter #1, we want to store the partial 
>> instantiation
>> -       of M (template<class T> S<int>::M<T>) in it's 
>> CLASSTYPE_TI_TEMPLATE.
>> +       of M (template<class T> S<int>::M<T>) in its 
>> CLASSTYPE_TI_TEMPLATE.
>>
>>         For all cases other than this "explicit specialization of 
>> member of a
>>         class template", we just want to store the most general 
>> template into
>> --
>> 1.8.3
>>
>
> OK.
> Do you have copyright assignment on file?
>
Yes.  I only came across these as I was addressing one of Jason's 
comments for my own bad grammar!

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 2/4] [lambda] Support implicit conversion of a stateless generic lambda to a function pointer.
  2013-08-03 13:29           ` [PATCH 2/4] [lambda] Support implicit conversion of a stateless generic lambda to a function pointer Adam Butcher
@ 2013-08-03 16:19             ` Jason Merrill
  2013-08-04 23:46               ` Adam Butcher
  0 siblings, 1 reply; 39+ messages in thread
From: Jason Merrill @ 2013-08-03 16:19 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 08/01/2013 08:25 AM, Adam Butcher wrote:
> +    = DECL_TEMPLATE_INFO (callop)
> +    && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop;

An expression broken across lines should be parenthesized.

And let's move the building of 'call' for the non-template case up to be 
with the template case.

Otherwise, looks good!

Jason

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [C++14/lambda] Experimental polymorphic lambda patches
  2013-07-01 23:27 [C++14/lambda] Experimental polymorphic lambda patches Adam Butcher
                   ` (5 preceding siblings ...)
  2013-07-11 17:35 ` [C++14/lambda] Experimental polymorphic lambda patches Jason Merrill
@ 2013-08-03 18:38 ` Paolo Carlini
  2013-08-04 22:52   ` Adam Butcher
  6 siblings, 1 reply; 39+ messages in thread
From: Paolo Carlini @ 2013-08-03 18:38 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Jason Merrill

.. I don't know if at this Stage we are paying attention to these minor 
details, but at least Patch 1 and 3 appear to have some overlong lines.

Thanks!
Paolo.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [C++14/lambda] Experimental polymorphic lambda patches
  2013-08-03 18:38 ` [C++14/lambda] Experimental polymorphic lambda patches Paolo Carlini
@ 2013-08-04 22:52   ` Adam Butcher
  2013-08-04 23:02     ` Paolo Carlini
  0 siblings, 1 reply; 39+ messages in thread
From: Adam Butcher @ 2013-08-04 22:52 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches, Jason Merrill

Hi Paolo,

On 03.08.2013 19:38, Paolo Carlini wrote:
> .. I don't know if at this Stage we are paying attention to these
> minor details, but at least Patch 1 and 3 appear to have some 
> overlong
> lines.
>
The patch set referenced by your mail has been superseded (see [1] and 
[2]).  I think most of the overlong lines were review queries or partial 
implementation which have now gone away.  I will ensure prior to 
submitting a final set that changelogs are done and that, to the best of 
my knowledge, the code style guidelines are followed.

For future, is there a convention for the mail 'Subject' that I should 
use to make it clear that I'm requesting feedback rather than expecting 
to get the patch committed as is?  "RFC" rather than "PATCH" perhaps?  I 
have simply been omitting changelogs in the commit logs for "non-final" 
patches.

Cheers,
Adam

[1] http://gcc.gnu.org/ml/gcc-patches/2013-07/threads.html#00755
[2] http://gcc.gnu.org/ml/gcc-patches/2013-08/threads.html#00130

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [C++14/lambda] Experimental polymorphic lambda patches
  2013-08-04 22:52   ` Adam Butcher
@ 2013-08-04 23:02     ` Paolo Carlini
  0 siblings, 0 replies; 39+ messages in thread
From: Paolo Carlini @ 2013-08-04 23:02 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches

On 08/05/2013 12:52 AM, Adam Butcher wrote:
> Hi Paolo,
>
> On 03.08.2013 19:38, Paolo Carlini wrote:
>> .. I don't know if at this Stage we are paying attention to these
>> minor details, but at least Patch 1 and 3 appear to have some overlong
>> lines.
>>
> The patch set referenced by your mail has been superseded (see [1] and 
> [2]).  I think most of the overlong lines were review queries or 
> partial implementation which have now gone away.  I will ensure prior 
> to submitting a final set that changelogs are done and that, to the 
> best of my knowledge, the code style guidelines are followed.
Ah good, thanks!

Paolo.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 2/4] [lambda] Support implicit conversion of a stateless generic lambda to a function pointer.
  2013-08-03 16:19             ` Jason Merrill
@ 2013-08-04 23:46               ` Adam Butcher
  2013-08-05 21:26                 ` Jason Merrill
  0 siblings, 1 reply; 39+ messages in thread
From: Adam Butcher @ 2013-08-04 23:46 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

Hi Jason,

On 03.08.2013 17:18, Jason Merrill wrote:
> On 08/01/2013 08:25 AM, Adam Butcher wrote:
>> +    = DECL_TEMPLATE_INFO (callop)
>> +    && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop;
>
> An expression broken across lines should be parenthesized.
>
> And let's move the building of 'call' for the non-template case up to
> be with the template case.
>
Done.

> Otherwise, looks good!
>
Cheers.  What should I do about the symtab nullptr issue? 
(http://gcc.gnu.org/ml/gcc-patches/2013-07/msg00043.html)  Should I 
leave the workaround in my patch set as a standalone commit to be 
remedied later or should I try to squash it?  Or is the hack appropriate 
for some reason?

It occurs when <iostream> is included (I'm assuming it will with other 
code too) when a generic lambda is defined (whether using 'auto' params 
or an explicit template param list).  The following program is minimal 
and sufficient (with regard to the lambda expression) to cause it.  I've 
deliberately used a capturing explicit lambda template below to remove 
the possibility that the conversion op or implicit template code has 
anything to do with it.

    #include <iostream>

    int main()
    {
      int i;
      [i] <typename T> (T) {};
    }

It does not matter whether the lambda is declared within a function or 
referenced by an initializer at namespace scope.  The backtrace looks 
like this (when the nullptr checks are removed of course):

   0xaeea1f crash_signal
   	../../gcc/toplev.c:334
   0xcdff04 tree_check
   	../../gcc/tree.h:3899
   0xcdff04 decl_assembler_name_hash(tree_node const*)
   	../../gcc/tree.c:602
   0x8068cf insert_to_assembler_name_hash
	../../gcc/symtab.c:130
   0x806d91 symtab_initialize_asm_name_hash()
   	../../gcc/symtab.c:361
   0x806db8 symtab_node_for_asm(tree_node const*)
   	../../gcc/symtab.c:374
   0x810670 handle_alias_pairs
   	../../gcc/cgraphunit.c:1014
   0x81443c finalize_compilation_unit()
   	../../gcc/cgraphunit.c:2104
   0x62b7ce cp_write_global_declarations()
   	../../gcc/cp/decl2.c:4357

It occurs because at

   symtab.c:117   tree name = DECL_ASSEMBLER_NAME (node->symbol.decl);

'name' ends up being 0.  GDB gives the following for 
debug_tree(node->symbol.decl) which may give you a clue:

  <function_decl 0x7ffff4f45900 operator()
     type <method_type 0x7ffff4f46a80
         type <template_type_parm 0x7ffff4f467e0 auto type_0 type_6 VOID
             align 8 symtab 0 alias set -1 canonical type 0x7ffff5c6c9d8
            index 0 level 2 orig_level 2
             chain <type_decl 0x7ffff4f3bc38 auto>>
         type_0 type_6 QI
         size <integer_cst 0x7ffff66fbf80 constant 8>
         unit size <integer_cst 0x7ffff66fbfa0 constant 1>
         align 8 symtab 0 alias set -1 canonical type 0x7ffff4f46bd0 
method basetype <record_type 0x7ffff4f465e8 __lambda0>
         arg-types <tree_list 0x7ffff4f42ed8 value <pointer_type 
0x7ffff4f46b28>
             chain <tree_list 0x7ffff4f42e88 value <template_type_parm 
0x7ffff4f46738 T>
                 chain <tree_list 0x7ffff6707988 value <void_type 
0x7ffff6716bd0 void>>>>>
     static external autoinline decl_3 decl_5 QI file bug.cpp line 6 col 
22 align 16 context <record_type 0x7ffff4f465e8 __lambda0> initial 
<block 0x7ffff52ff9b0>
     arguments <parm_decl 0x7ffff4f44b00 __closure
         type <pointer_type 0x7ffff4f46c78 type <record_type 
0x7ffff4f469d8 __lambda0>
             readonly unsigned type_6 DI
             size <integer_cst 0x7ffff66fbdc0 constant 64>
             unit size <integer_cst 0x7ffff66fbde0 constant 8>
             align 64 symtab 0 alias set -1 canonical type 
0x7ffff4f46c78>
         readonly used unsigned DI file bug.cpp line 6 col 22 size 
<integer_cst 0x7ffff66fbdc0 64> unit size <integer_cst 0x7ffff66fbde0 8>
         align 64 context <function_decl 0x7ffff4f45900 operator()> 
arg-type <pointer_type 0x7ffff4f46c78>
         chain <parm_decl 0x7ffff4f44a80 D.29283 type 
<template_type_parm 0x7ffff4f46738 T>
             VOID file bug.cpp line 6 col 21
             align 8 context <function_decl 0x7ffff4f45900 operator()>
            >>
     result <result_decl 0x7ffff52ed5a0 D.29288 type <template_type_parm 
0x7ffff4f467e0 auto>
         ignored VOID file bug.cpp line 6 col 22
         align 8 context <function_decl 0x7ffff4f45900 operator()>>
     full-name "main()::<lambda(T)>"
     not-really-extern template-info 0x7ffff4f41c00
     struct-function 0x7ffff52cfbe0>

Do you know what could be causing this?  Presumably something that's 
generated in the non-template lambda case needs to be removed in the 
template case (or something new added)?  It is strange that it occurs 
only when <iostream> (or presumably some other headers) are included.  
With the two early outs for nullptrs in symtab.c the resulting programs 
behave as expected, I'm just not happy with that solution.

Cheers,
Adam

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 2/4] [lambda] Support implicit conversion of a stateless generic lambda to a function pointer.
  2013-08-04 23:46               ` Adam Butcher
@ 2013-08-05 21:26                 ` Jason Merrill
  2013-08-07  7:53                   ` [FIXED] Generic lambda symbol table bug Adam Butcher
  0 siblings, 1 reply; 39+ messages in thread
From: Jason Merrill @ 2013-08-05 21:26 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 08/04/2013 07:45 PM, Adam Butcher wrote:
> What should I do about the symtab nullptr issue?
> (http://gcc.gnu.org/ml/gcc-patches/2013-07/msg00043.html)  Should I
> leave the workaround in my patch set as a standalone commit to be
> remedied later or should I try to squash it?  Or is the hack appropriate
> for some reason?

Let's fix it.

>    0x810670 handle_alias_pairs
>        ../../gcc/cgraphunit.c:1014

This suggests that somehow the call operator template wound up in 
alias_pairs.  This is very mysterious; I really don't know why there 
would be any aliases in this testcase, much less one involving the 
operator().  The offending code should be pretty straightforward to find 
with a watchpoint on alias_pairs.

Jason

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [FIXED] Generic lambda symbol table bug
  2013-08-05 21:26                 ` Jason Merrill
@ 2013-08-07  7:53                   ` Adam Butcher
  2013-08-07 15:59                     ` Jason Merrill
  0 siblings, 1 reply; 39+ messages in thread
From: Adam Butcher @ 2013-08-07  7:53 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

Hi Jason,

On Mon, 05 Aug 2013 17:26:12 -0400, Jason Merrill wrote:
> On 08/04/2013 07:45 PM, Adam Butcher wrote:
> > What should I do about the symtab nullptr issue?
> > (http://gcc.gnu.org/ml/gcc-patches/2013-07/msg00043.html)  Should I
> > leave the workaround in my patch set as a standalone commit to be
> > remedied later or should I try to squash it?  Or is the hack appropriate
> > for some reason?
>
> Let's fix it.
>
> >    0x810670 handle_alias_pairs
> >        ../../gcc/cgraphunit.c:1014
>
> This suggests that somehow the call operator template wound up in
> alias_pairs.  This is very mysterious; I really don't know why there
> would be any aliases in this testcase, much less one involving the
> operator().  The offending code should be pretty straightforward to find
> with a watchpoint on alias_pairs.
>
Turns out that it was the presence of any alias that was triggering the issue.
The call op itself was not in the 'alias_pairs' vector.  It happened because, if
aliases are present, 'handle_alias_pairs' causes an initialization of the
'assembler_name_hash' containing every known symbol.  And for some reason, which
I now understand, the uninstantiated call operator template result declaration
was being added to the symbol table (without an asmname).  The particular
aliases my original program encountered from <iostream> were the gthread ones.
The following program (no includes, no conversion ops, no implicit templates) is
sufficient and minimal to reproduce the issue.

   int dummy() {}
   static decltype(dummy) weak_dummy __attribute__ ((__weakref__("dummy")));

   int main()
   {
     int i;
     [i] <typename T> (T) {};
   }

The patch below fixes it.  But a cleaner way might be to extend the "processing
template declaration" state from lambda declarator all the way to the end of the
lambda body.  This would match with the scenario that occurs with a standard
in-class member function template definition.  To do that elegantly would
require a bit of refactoring of the lambda parser code.

The patch below does the job by avoiding the cause of the erroneous symbol table
entry, 'expand_or_defer_fn', explicitly.

Assuming you're okay with this fix, how do you want me to submit the final
patchset for this stuff?  There are two features here which I was intending to
submit in the following order as two patches:

  - Generic lambdas specified with explicit template parameter list.  This
    teaches GCC how to deal with lambda call op templates (and their conversion
    operators) but does not actually implement the 'generic lambda' spec in
    N3690 5.1.2.5. 

  - Generalized implicit function template support via 'auto params'; a step
    along the road to terse templates.  The necessary propagation into the
    lambda code has a side-effect of supporting 'generic lambdas' as proposed by
    the C++14 draft standard.

I'm not sure which dialect guards to put these features behind though.
Strictly:

  a) Generic lambdas created fully implicitly via 'auto params' should be
     accepted with -std=c++1y and -std=gnu++1y since it is actually spec'd by
     the draft.

  b) Generic lambdas created with an explicit template parameter list should be
     accepted with -std=gnu++1y only.

  c) Generalized implicit function templates should be accepted by -std=gnu++1y
     only.

Due to the generalized implementation of the feature guarded by (c), it may be
messy (or maybe costly) to implement (a).

Cheers,
Adam


----------------- fix for symtab issue ------------------

Don't add generic lambda call ops to the symbol table.

Typically, 'processing_template_decl' is high throughout an in-class member
function template definition, so 'expand_or_defer_fn' normally does nothing.
It is difficult, without considerable refactoring of the current lambda parser
implementation, to mimic the situation that arises with a conventional in-class
member template definition.  Hence, this patch prevents 'expand_or_defer_fn'
from being called for generic lambdas.

The bug was triggered by the presence of at least one alias (such as a weak ref)
causing the assembler name hash to be initialized with every known symbol.  The
call operator template should not be added to the symbol table; only
instantiations of it should.

---
 gcc/cp/lambda.c |  8 ++++++--
 gcc/cp/parser.c |  6 +++++-
 gcc/symtab.c    | 18 ------------------
 3 files changed, 11 insertions(+), 21 deletions(-)

diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index c90a27c..5fdc551 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -915,7 +915,9 @@ maybe_add_lambda_conv_op (tree type)
   finish_compound_stmt (compound_stmt);
   finish_function_body (body);
 
-  expand_or_defer_fn (finish_function (2));
+  fn = finish_function (/*inline*/2);
+  if (!generic_lambda_p)
+    expand_or_defer_fn (fn);
 
   /* Generate the body of the conversion op.  */
 
@@ -931,7 +933,9 @@ maybe_add_lambda_conv_op (tree type)
   finish_compound_stmt (compound_stmt);
   finish_function_body (body);
 
-  expand_or_defer_fn (finish_function (2));
+  fn = finish_function (/*inline*/2);
+  if (!generic_lambda_p)
+    expand_or_defer_fn (fn);
 
   if (nested)
     pop_function_context ();
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 7cd197d..8107ff1 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -9135,7 +9135,11 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
     finish_lambda_scope ();
 
     /* Finish the function and generate code for it if necessary.  */
-    expand_or_defer_fn (finish_function (/*inline*/2));
+    tree fn = finish_function (/*inline*/2);
+
+    /* Only expand if the call op is not a template.  */
+    if (!DECL_TEMPLATE_INFO (fco))
+      expand_or_defer_fn (fn);
   }
 
   parser->local_variables_forbidden_p = local_variables_forbidden_p;
diff --git a/gcc/symtab.c b/gcc/symtab.c
index a23a905..d15881b 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -116,15 +116,6 @@ insert_to_assembler_name_hash (symtab_node node, bool with_clones)
 
       tree name = DECL_ASSEMBLER_NAME (node->symbol.decl);
 
-
-      // FIXME: how does this nullptr get here when declaring a C++
-      // FIXME: generic lambda and including iostream (or presumably
-      // FIXME: any other header with whatever property is triggering
-      // FIXME: this)!?
-      //
-      if (name == 0)
-	return;
-
       aslot = htab_find_slot_with_hash (assembler_name_hash, name,
 					decl_assembler_name_hash (name),
 					INSERT);
@@ -165,15 +156,6 @@ unlink_from_assembler_name_hash (symtab_node node, bool with_clones)
       else
 	{
 	  tree name = DECL_ASSEMBLER_NAME (node->symbol.decl);
-
-	  // FIXME: how does this nullptr get here when declaring a C++
-	  // FIXME: generic lambda and including iostream (or presumably
-	  // FIXME: any other header with whatever property is triggering
-	  // FIXME: this)!?
-	  //
-	  if (name == 0)
-	    return;
-
           void **slot;
 	  slot = htab_find_slot_with_hash (assembler_name_hash, name,
 					   decl_assembler_name_hash (name),
-- 
1.8.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [FIXED] Generic lambda symbol table bug
  2013-08-07  7:53                   ` [FIXED] Generic lambda symbol table bug Adam Butcher
@ 2013-08-07 15:59                     ` Jason Merrill
  2013-08-07 19:56                       ` Adam Butcher
  0 siblings, 1 reply; 39+ messages in thread
From: Jason Merrill @ 2013-08-07 15:59 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 08/07/2013 03:52 AM, Adam Butcher wrote:
> But a cleaner way might be to extend the "processing
> template declaration" state from lambda declarator all the way to the end of the
> lambda body.  This would match with the scenario that occurs with a standard
> in-class member function template definition.  To do that elegantly would
> require a bit of refactoring of the lambda parser code.

It isn't already set through the whole lambda body?  That seems 
necessary to support non-trivial lambda bodies; otherwise we won't be 
able to handle dependence properly.

> I'm not sure which dialect guards to put these features behind though.
> Strictly:
>
>   a) Generic lambdas created fully implicitly via 'auto params' should be
>      accepted with -std=c++1y and -std=gnu++1y since it is actually spec'd by
>      the draft.
>
>   b) Generic lambdas created with an explicit template parameter list should be
>      accepted with -std=gnu++1y only.
>
>   c) Generalized implicit function templates should be accepted by -std=gnu++1y
>      only.

This makes sense to me.  Or perhaps add (c) to the concepts lite flag, 
when there is one.

Jason

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [FIXED] Generic lambda symbol table bug
  2013-08-07 15:59                     ` Jason Merrill
@ 2013-08-07 19:56                       ` Adam Butcher
  2013-08-08 22:28                         ` Adam Butcher
  0 siblings, 1 reply; 39+ messages in thread
From: Adam Butcher @ 2013-08-07 19:56 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 07.08.2013 16:59, Jason Merrill wrote:
> On 08/07/2013 03:52 AM, Adam Butcher wrote:
>> But a cleaner way might be to extend the "processing
>> template declaration" state from lambda declarator all the way to 
>> the end of the
>> lambda body.  This would match with the scenario that occurs with a 
>> standard
>> in-class member function template definition.  To do that elegantly 
>> would
>> require a bit of refactoring of the lambda parser code.
>
> It isn't already set through the whole lambda body?
>
No.  It is within cp_parser_lambda_declarator_opt.

> That seems
> necessary to support non-trivial lambda bodies; otherwise we won't be
> able to handle dependence properly.
>
Agreed.  Okay, I will produce three patches:

   1) Refactor existing monomorphic implementation to give a cleaner
      parser separation of concerns; extract the fco creation and
      provide begin and end for the lambda function operator.

   2) Add explicit lambda template support.

   3) Add implicit function template support.

>> I'm not sure which dialect guards to put these features behind 
>> though.
>> Strictly:
>>
>>   a) Generic lambdas created fully implicitly via 'auto params' 
>> should be
>>      accepted with -std=c++1y and -std=gnu++1y since it is actually 
>> spec'd by
>>      the draft.
>>
>>   b) Generic lambdas created with an explicit template parameter 
>> list should be
>>      accepted with -std=gnu++1y only.
>>
>>   c) Generalized implicit function templates should be accepted by 
>> -std=gnu++1y
>>      only.
>
> This makes sense to me.  Or perhaps add (c) to the concepts lite
> flag, when there is one.
>
Okay.  Will do as originally suggested.  I am intending to try out
constrained implicit function templates on the c++-concepts branch
at some point also (which might already have such a flag).

Cheers,
Adam

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [FIXED] Generic lambda symbol table bug
  2013-08-07 19:56                       ` Adam Butcher
@ 2013-08-08 22:28                         ` Adam Butcher
  2013-08-09  2:01                           ` Jason Merrill
  0 siblings, 1 reply; 39+ messages in thread
From: Adam Butcher @ 2013-08-08 22:28 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 07.08.2013 20:56, Adam Butcher wrote:
> On 07.08.2013 16:59, Jason Merrill wrote:
>> On 08/07/2013 03:52 AM, Adam Butcher wrote:
>>> But a cleaner way might be to extend the "processing
>>> template declaration" state from lambda declarator all the way to 
>>> the end of the
>>> lambda body.  This would match with the scenario that occurs with a 
>>> standard
>>> in-class member function template definition.  To do that elegantly 
>>> would
>>> require a bit of refactoring of the lambda parser code.
>>
>> It isn't already set through the whole lambda body?
>>
> No.  It is within cp_parser_lambda_declarator_opt.
>
>> That seems
>> necessary to support non-trivial lambda bodies; otherwise we won't 
>> be
>> able to handle dependence properly.
>>
> Agreed.  Okay, I will produce three patches:
>
>   1) Refactor existing monomorphic implementation to give a cleaner
>      parser separation of concerns; extract the fco creation and
>      provide begin and end for the lambda function operator.
>
I did this---well not exactly as written---but I extended the template 
decl state through until the end of the lambda body.  And it works with 
my dependence test.  However, the previous version does too.  The 
following program works fine (conv ops an all) with the refactored 
version and without it.  I'm now questioning whether it is worth making 
any change in this area.  What do you think?  The test code is as 
follows and the resulting program correctly executes S::N::test() 4 
times as expected -- were you thinking of some other dependence case?

   #include <iostream>

   struct S
   {
      struct N
      {
         float test () { std::cout << "S::N::test() -> 7.f\n"; return 
7.f; }
      };
   };

   int main()
   {
      auto f = [] <typename T> (T const& s) {
         typename T::N x;
         return x.test ();
      };
      auto g = [] (auto const& s) {
         typename std::decay<decltype (s)>::type::N x;
         return x.test ();
      };

      S i;

      f(i);
      g(i);

      float (*pfn) (S const&) = f;

      pfn(i);

      pfn = g;

      return pfn(i);
   }

Error messages are reasonable also.  Omitting the necessary 'typename's 
gives:

    : need ‘typename’ before ‘T::N’ because ‘T’ is a dependent scope
    : need ‘typename’ before ‘typename std::decay<decltype 
(s)>::type::N’ because ‘typename std::decay<decltype (s)>::type’ is a 
dependent scope

Passing a local 'struct X {}' instead of 'S' gives:

   : In instantiation of ‘auto main()::<lambda(const T&)> const [with T 
= main()::X]’:
   :24:9:   required from here
   :14:23: error: no type named ‘N’ in ‘struct main()::X’
   ...

So all seems to be okay with both versions.  Any ideas why?

Cheers,
Adam

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [FIXED] Generic lambda symbol table bug
  2013-08-08 22:28                         ` Adam Butcher
@ 2013-08-09  2:01                           ` Jason Merrill
  2013-08-09  7:29                             ` Adam Butcher
  0 siblings, 1 reply; 39+ messages in thread
From: Jason Merrill @ 2013-08-09  2:01 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 08/08/2013 06:28 PM, Adam Butcher wrote:
> So all seems to be okay with both versions.  Any ideas why?

Hmm, it sounds like processing_template_decl is being set after all, 
even without your change.

Jason

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [FIXED] Generic lambda symbol table bug
  2013-08-09  2:01                           ` Jason Merrill
@ 2013-08-09  7:29                             ` Adam Butcher
  0 siblings, 0 replies; 39+ messages in thread
From: Adam Butcher @ 2013-08-09  7:29 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 09.08.2013 03:01, Jason Merrill wrote:
> On 08/08/2013 06:28 PM, Adam Butcher wrote:
>> So all seems to be okay with both versions.  Any ideas why?
>
> Hmm, it sounds like processing_template_decl is being set after all,
> even without your change.
>
Yup.  Although the lambda template code I originally added scoped it to 
within the the 'cp_parser_lambda_declarator_opt' function, since the 
call op being declared is an in-class inline member, 
'start_preparsed_function' is entering 
'maybe_begin_member_template_processing'.   'finish_function' matches 
that with 'maybe_end_member_template_processing' prior to the function 
being passed to 'expand_or_defer_fn' (which then causes the erroneous 
symtab entry).

So I think my original fix might be okay here; omitting 
'expand_or_defer_fn' if 'generic_lambda_p'.

What do you think?  Shall I just include it as part of the first patch? 
If so that'd just be two patches, "teach GCC to deal with lambda 
templates" and "implicit function templates with auto".

Cheers,
Adam


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] [lambda] Extract lambda functions from semantics.c.
  2013-07-14  9:07     ` [PATCH] [lambda] Extract lambda functions from semantics.c Adam Butcher
  2013-07-14 17:30       ` Jason Merrill
@ 2013-09-04  2:33       ` Mike Stump
       [not found]         ` <CAAiZkiDeMcumAPK=Dvvtocufanj9uqFg=T1oj8RnFXY5K6VdMQ@mail.gmail.com>
  1 sibling, 1 reply; 39+ messages in thread
From: Mike Stump @ 2013-09-04  2:33 UTC (permalink / raw)
  To: Adam Butcher; +Cc: Jason Merrill, Gabriel Dos Reis, gcc-patches

On Jul 12, 2013, at 11:18 PM, Adam Butcher <adam@jessamine.co.uk> wrote:
> 	* gcc/cp/semantics.c (build_lambda_expr),
> 	(build_lambda_object), (begin_lambda_type), (lambda_return_type),
> 	(lambda_function), (lambda_capture_field_type), (is_capture_proxy),
> 	(is_normal_capture_proxy), (insert_capture_proxy),
> 	(insert_pending_capture_proxies), (lambda_proxy_type),
> 	(build_capture_proxy), (vla_capture_type),
> 	(register_capture_members), (add_default_capture),
> 	(lambda_expr_this_capture), (maybe_resolve_dummy),
> 	(nonlambda_method_basetype), (maybe_add_lambda_conv_op) and
> 	(is_lambda_ignored_entity): Moved definitions into ...
> 	* gcc/cp/lambda.c: ... this new file.


This can cause an incremental build failure because there are no dependencies:

diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 2c1774f..65dfe08 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -351,6 +351,7 @@ cp/vtable-class-hierarchy.o: cp/vtable-class-hierarchy.c \
 cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
        $(TM_H) $(CXX_TREE_H) $(TIMEVAR_H) gt-cp-name-lookup.h $(PARAMS_H) \
        $(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h pointer-set.h
+cp/lambda.o: cp/lambda.c $(CXX_TREE_H) $(CGRAPH_H) $(VEC_H) $(SYSTEM_H) coretypes.h
 
 cp/cxx-pretty-print.o: cp/cxx-pretty-print.c $(CXX_PRETTY_PRINT_H) \
   $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h $(CXX_TREE_H) tree-pretty-print.h

When tree codes are added or moved, the check is then against the wrong number, and this will kill the build.

I'm still looking forward to the day when all the dependancies are unceremoniously ripped out, until then...

Ok?

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] [lambda] Extract lambda functions from semantics.c.
       [not found]         ` <CAAiZkiDeMcumAPK=Dvvtocufanj9uqFg=T1oj8RnFXY5K6VdMQ@mail.gmail.com>
@ 2013-09-04 17:55           ` Adam Butcher
       [not found]             ` <CAAiZkiBrDFuMOVuYobXPifvVQH=TDw9HZgk9s-A_vK+z7KEPZQ@mail.gmail.com>
  0 siblings, 1 reply; 39+ messages in thread
From: Adam Butcher @ 2013-09-04 17:55 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Mike Stump, Jason Merrill, gcc-patches

On 04.09.2013 03:41, Gabriel Dos Reis wrote:
> On Tue, Sep 3, 2013 at 9:33 PM, Mike Stump <mikestump@comcast.net> 
> wrote:
>> On Jul 12, 2013, at 11:18 PM, Adam Butcher <adam@jessamine.co.uk> 
>> wrote:
>>>       * gcc/cp/semantics.c (build_lambda_expr),
>>>       (build_lambda_object), (begin_lambda_type), 
>>> (lambda_return_type),
>>>       (lambda_function), (lambda_capture_field_type), 
>>> (is_capture_proxy),
>>>       (is_normal_capture_proxy), (insert_capture_proxy),
>>>       (insert_pending_capture_proxies), (lambda_proxy_type),
>>>       (build_capture_proxy), (vla_capture_type),
>>>       (register_capture_members), (add_default_capture),
>>>       (lambda_expr_this_capture), (maybe_resolve_dummy),
>>>       (nonlambda_method_basetype), (maybe_add_lambda_conv_op) and
>>>       (is_lambda_ignored_entity): Moved definitions into ...
>>>       * gcc/cp/lambda.c: ... this new file.
>>
>>
>> This can cause an incremental build failure because there are no 
>> dependencies:
>>
>> diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
>> index 2c1774f..65dfe08 100644
>> --- a/gcc/cp/Make-lang.in
>> +++ b/gcc/cp/Make-lang.in
>> @@ -351,6 +351,7 @@ cp/vtable-class-hierarchy.o: 
>> cp/vtable-class-hierarchy.c \
>>  cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) 
>> coretypes.h \
>>         $(TM_H) $(CXX_TREE_H) $(TIMEVAR_H) gt-cp-name-lookup.h 
>> $(PARAMS_H) \
>>         $(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h pointer-set.h
>> +cp/lambda.o: cp/lambda.c $(CXX_TREE_H) $(CGRAPH_H) $(VEC_H) 
>> $(SYSTEM_H) coretypes.h
>>
>>  cp/cxx-pretty-print.o: cp/cxx-pretty-print.c $(CXX_PRETTY_PRINT_H) 
>> \
>>    $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h $(CXX_TREE_H) 
>> tree-pretty-print.h
>>
>> When tree codes are added or moved, the check is then against the 
>> wrong number, and this will kill the build.
>>
>> I'm still looking forward to the day when all the dependancies are 
>> unceremoniously ripped out, until then...
>>
>> Ok?
>
> OK.
>
Eek.  I didn't realize dependencies had to be manually specified.  
That's prompted me to update a more recent patchset I'm working on where 
I've introduced a new header.

Is anyone working on using some use, perhaps filtered, of -MD (or -MDD) 
to generate deps on the fly?  I haven't looked into the GCC makefile 
system in any detail but I assume dependency handling is more complex 
than the standard usage pattern for -MD or I guess someone would have 
done it already.  Or are maintainers worried that auto deps will slow 
the build down too much?  In our team's experience with using -MD the 
overhead is negligible; especially when weighed up against the effort 
required to manually maintain deps.  It just takes make a little longer 
to start actually building anything.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] [lambda] Extract lambda functions from semantics.c.
       [not found]             ` <CAAiZkiBrDFuMOVuYobXPifvVQH=TDw9HZgk9s-A_vK+z7KEPZQ@mail.gmail.com>
@ 2013-09-04 20:29               ` Adam Butcher
  0 siblings, 0 replies; 39+ messages in thread
From: Adam Butcher @ 2013-09-04 20:29 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Mike Stump, Jason Merrill, gcc-patches, Tom Tromey

On 04.09.2013 20:39, Gabriel Dos Reis wrote:
> On Wed, Sep 4, 2013 at 12:55 PM, Adam Butcher <adam@jessamine.co.uk> 
> wrote:
>
>> Is anyone working on using some use, perhaps filtered, of -MD (or 
>> -MDD) to
>> generate deps on the fly?
>
> See Tom's patch series.
>
Ah, yes.  Cool.  I guess it's just waiting on approval for each part; I 
note that a few front ends have already been OK'd.

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2013-09-04 20:29 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-01 23:27 [C++14/lambda] Experimental polymorphic lambda patches Adam Butcher
2013-07-01 23:27 ` [PATCH 4/4] [lambda] [polymorphic] [HACK] Avoid crash on symbol table writing when generic lambda declared with iostream (or potentially other code) included Adam Butcher
2013-07-01 23:27 ` [PATCH 1/4] [lambda] [polymorphic] Support template-parameter-list in lambda-declarator Adam Butcher
2013-07-01 23:27 ` [PATCH 2/4] [lambda] [polymorphic] Support generic lambdas in templates Adam Butcher
2013-07-01 23:27 ` [PATCH 3/4] [lambda] [polymorphic] Infer template parameter from auto used in function parameter list Adam Butcher
2013-07-02  0:01 ` [PATCH] [debug] Added DEBUG_FUNCTION void dump_backtrace Adam Butcher
2013-07-11 17:35 ` [C++14/lambda] Experimental polymorphic lambda patches Jason Merrill
2013-07-12  2:04   ` Gabriel Dos Reis
2013-07-14  9:07     ` [PATCH] [lambda] Extract lambda functions from semantics.c Adam Butcher
2013-07-14 17:30       ` Jason Merrill
2013-09-04  2:33       ` Mike Stump
     [not found]         ` <CAAiZkiDeMcumAPK=Dvvtocufanj9uqFg=T1oj8RnFXY5K6VdMQ@mail.gmail.com>
2013-09-04 17:55           ` Adam Butcher
     [not found]             ` <CAAiZkiBrDFuMOVuYobXPifvVQH=TDw9HZgk9s-A_vK+z7KEPZQ@mail.gmail.com>
2013-09-04 20:29               ` Adam Butcher
2013-07-19  9:01   ` [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches Adam Butcher
2013-07-19  9:01     ` [PATCH 1/3] [lambda] Support template-parameter-list in lambda-declarator Adam Butcher
2013-07-19 17:33       ` Jason Merrill
2013-08-03 13:29         ` [C++14/lambda/impicit-templates] Experimental polymorphic lambda and implicit function template patches Adam Butcher
2013-08-03 13:29           ` [PATCH 3/4] [lambda] Address review comments Adam Butcher
2013-08-03 13:40             ` Gabriel Dos Reis
2013-08-03 13:51               ` Adam Butcher
2013-08-03 13:29           ` [PATCH 1/4] [lambda] Preserve type qualifiers for implicit template parameters Adam Butcher
2013-08-03 13:29           ` [PATCH 4/4] Grammar "it's" to "its" Adam Butcher
2013-08-03 13:36             ` Gabriel Dos Reis
2013-08-03 13:54               ` Adam Butcher
2013-08-03 13:29           ` [PATCH 2/4] [lambda] Support implicit conversion of a stateless generic lambda to a function pointer Adam Butcher
2013-08-03 16:19             ` Jason Merrill
2013-08-04 23:46               ` Adam Butcher
2013-08-05 21:26                 ` Jason Merrill
2013-08-07  7:53                   ` [FIXED] Generic lambda symbol table bug Adam Butcher
2013-08-07 15:59                     ` Jason Merrill
2013-08-07 19:56                       ` Adam Butcher
2013-08-08 22:28                         ` Adam Butcher
2013-08-09  2:01                           ` Jason Merrill
2013-08-09  7:29                             ` Adam Butcher
2013-07-19  9:01     ` [PATCH 3/3] [lambda] [basic-terse-templates] Support using `auto' in a function parameter list to introduce an implicit template parameter Adam Butcher
2013-07-19  9:06     ` [PATCH 2/3] [lambda] Avoid crash on symbol table writing when generic lambda declared with iostream (or potentially other code) included Adam Butcher
2013-08-03 18:38 ` [C++14/lambda] Experimental polymorphic lambda patches Paolo Carlini
2013-08-04 22:52   ` Adam Butcher
2013-08-04 23:02     ` Paolo Carlini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).