Patchwork [1/4,lambda,polymorphic] Support template-parameter-list in lambda-declarator.

login
register
mail settings
Submitter Adam Butcher
Date July 1, 2013, 11:26 p.m.
Message ID <1372721221-6201-2-git-send-email-adam@jessamine.co.uk>
Download mbox | patch
Permalink /patch/256242/
State New
Headers show

Comments

Adam Butcher - July 1, 2013, 11:26 p.m.
---
 gcc/cp/mangle.c    |  2 ++
 gcc/cp/parser.c    | 43 +++++++++++++++++++++++++++++++++++++++++--
 gcc/cp/semantics.c | 10 +++++++++-
 3 files changed, 52 insertions(+), 3 deletions(-)

Patch

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.  */