public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [c++-concepts] Parsing for template requirements
@ 2013-03-01 16:13 Andrew Sutton
  2013-03-01 17:09 ` Gabriel Dos Reis
  0 siblings, 1 reply; 2+ messages in thread
From: Andrew Sutton @ 2013-03-01 16:13 UTC (permalink / raw)
  To: gcc-patches; +Cc: Gabriel Dos Reis, Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 1195 bytes --]

Two patches attached.

The reqs-parsing patch adds parsing support for template requirements
(i.e., requires clauses). This is supported for all template
declarations and non-template member functions of class templates.
Grammar changes are documented in comments. Semantic processing of
constraints is stubbed out for the time being.

The flags patch just enables -fconcepts by default.

The combined change log is:

2013-03-01  Andrew Sutton  <andrew.n.sutton@gmail.com>

        * cp-tree.h (saved_scope): Add template requirements.
        (finish_template_requirements): Declare
        * parser.c (cp_parser_template_requirement_opt): Declare.
        (cp_parser_template_declaration): Document grammar extensions.
        (cp_parser_type_parameter): Parse requirements for template
        template parameters.
        (cp_parser_member_declaration): Parse requirements for
        members of class templates.
        (cp_parser_template_requirement_opt): Define.
        (cp_parser_template_declaration_after_exp): Parse requirements
        for template declarations.
        * semantics.c (finish_template_requirements): Define.
        * lex.c (cxx_init): Enable concepts by default.

[-- Attachment #2: flags.patch --]
[-- Type: application/octet-stream, Size: 395 bytes --]

Index: gcc/cp/lex.c
===================================================================
--- gcc/cp/lex.c	(revision 196385)
+++ gcc/cp/lex.c	(working copy)
@@ -228,6 +228,8 @@ cxx_init (void)
    EXPR_STMT
   };
 
+  flag_concepts = true;
+
   memset (&statement_code_p, 0, sizeof (statement_code_p));
   for (i = 0; i < ARRAY_SIZE (stmt_codes); i++)
     statement_code_p[stmt_codes[i]] = true;

[-- Attachment #3: reqs-parsing.patch --]
[-- Type: application/octet-stream, Size: 12800 bytes --]

Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 196384)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -992,6 +992,7 @@ struct GTY(()) saved_scope {
   vec<tree, va_gc> *lang_base;
   tree lang_name;
   tree template_parms;
+  tree template_reqs;
   cp_binding_level *x_previous_class_level;
   tree x_saved_tree;
 
@@ -1052,6 +1053,11 @@ struct GTY(()) saved_scope {
 
 #define current_template_parms scope_chain->template_parms
 
+// When parsing a template declaration this node represents the
+// active template requirements. This includes the lists of
+// actual assumptions in the current scope.
+#define current_template_reqs scope_chain->template_reqs
+
 #define processing_template_decl scope_chain->x_processing_template_decl
 #define processing_specialization scope_chain->x_processing_specialization
 #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation
@@ -5725,6 +5731,7 @@ extern tree lambda_expr_this_capture
 extern tree nonlambda_method_basetype		(void);
 extern void maybe_add_lambda_conv_op            (tree);
 extern bool is_lambda_ignored_entity            (tree);
+extern tree finish_template_requirements        (tree);
 
 /* in tree.c */
 extern int cp_tree_operand_length		(const_tree);
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 196384)
+++ gcc/cp/parser.c	(working copy)
@@ -2136,6 +2136,11 @@ static bool cp_parser_extension_opt
 static void cp_parser_label_declaration
   (cp_parser *);
 
+/* Concept Extensions */
+
+static tree cp_parser_template_requirement_opt
+  (cp_parser *);
+
 /* Transactional Memory Extensions */
 
 static tree cp_parser_transaction
@@ -12104,7 +12109,16 @@ cp_parser_operator (cp_parser* parser)
 
    template-parameter-list-seq:
      template-parameter-list-seq [opt]
-     template < template-parameter-list >  */
+     template < template-parameter-list >
+
+   Concept Extensions:
+
+   template-parameter-list-seq:
+     template < template-parameter-list > template-requirement [opt]
+
+   template-requirement:
+     requires logical-or-expression
+  */
 
 static void
 cp_parser_template_declaration (cp_parser* parser, bool member_p)
@@ -12442,7 +12456,21 @@ cp_parser_type_parameter (cp_parser* par
 	cp_parser_template_parameter_list (parser);
 	/* Look for the `>'.  */
 	cp_parser_require (parser, CPP_GREATER, RT_GREATER);
-	/* Look for the `class' keyword.  */
+	
+        // If template requirements are present, parse them.
+        tree saved_template_reqs = current_template_reqs;
+        if (flag_concepts)
+          {
+            if (tree req = cp_parser_template_requirement_opt (parser))
+              {
+                // The prameter's constraints are independent of
+                // the enclosing scope.
+                current_template_reqs = NULL_TREE;
+                current_template_reqs = finish_template_requirements (req);
+              }
+          }
+
+        /* Look for the `class' keyword.  */
 	cp_parser_require_keyword (parser, RID_CLASS, RT_CLASS);
         /* If the next token is an ellipsis, we have a template
            argument pack. */
@@ -12474,6 +12502,8 @@ cp_parser_type_parameter (cp_parser* par
 	parameter = finish_template_template_parm (class_type_node,
 						   identifier);
 
+        current_template_reqs = saved_template_reqs;
+
 	/* If the next token is an `=', then there is a
 	   default-argument.  */
 	if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
@@ -19024,7 +19054,20 @@ cp_parser_member_specification_opt (cp_p
    C++0x Extensions:
 
    member-declaration:
-     static_assert-declaration  */
+     static_assert-declaration  
+
+
+   Concepts Extensions:
+
+   member-declaration:
+     constrained-member-declaration:
+
+   constrained-member-declaration:
+     requires logical-or-expression constrained-member-declarator
+
+   constrained-member-declarator:
+     decl-specifier-seq [opt] member-declarator-list [opt] ;
+     function-definition ; [opt] */
 
 static void
 cp_parser_member_declaration (cp_parser* parser)
@@ -19051,81 +19094,99 @@ cp_parser_member_declaration (cp_parser*
       return;
     }
 
-  /* Check for a template-declaration.  */
-  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
+  // If the declaration starts with a requires clause, parse a constrained
+  // member declaration. Note that we can only have constrained members
+  // in a template.
+  tree saved_template_reqs = current_template_reqs;
+  bool unconstrained = true;
+  if (flag_concepts && processing_template_decl)
     {
-      /* An explicit specialization here is an error condition, and we
-	 expect the specialization handler to detect and report this.  */
-      if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_LESS
-	  && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_GREATER)
-	cp_parser_explicit_specialization (parser);
-      else
-	cp_parser_template_declaration (parser, /*member_p=*/true);
-
-      return;
+      if (tree req = cp_parser_template_requirement_opt (parser))
+        {
+          current_template_reqs = finish_template_requirements (req);
+          unconstrained = false;
+        }
     }
 
-  /* Check for a using-declaration.  */
-  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
+  if (unconstrained)
     {
-      if (cxx_dialect < cxx0x)
-	{
-	  /* Parse the using-declaration.  */
-	  cp_parser_using_declaration (parser,
-				       /*access_declaration_p=*/false);
-	  return;
-	}
-      else
-	{
-	  tree decl;
-	  bool alias_decl_expected;
-	  cp_parser_parse_tentatively (parser);
-	  decl = cp_parser_alias_declaration (parser);
-	  /* Note that if we actually see the '=' token after the
-	     identifier, cp_parser_alias_declaration commits the
-	     tentative parse.  In that case, we really expects an
-	     alias-declaration.  Otherwise, we expect a using
-	     declaration.  */
-	  alias_decl_expected =
-	    !cp_parser_uncommitted_to_tentative_parse_p (parser);
-	  cp_parser_parse_definitely (parser);
+      /* Check for a template-declaration.  */
+      if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
+        {
+          /* An explicit specialization here is an error condition, and we
+             expect the specialization handler to detect and report this.  */
+          if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_LESS
+              && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_GREATER)
+            cp_parser_explicit_specialization (parser);
+          else
+            cp_parser_template_declaration (parser, /*member_p=*/true);
 
-	  if (alias_decl_expected)
-	    finish_member_declaration (decl);
-	  else
-	    cp_parser_using_declaration (parser,
-					 /*access_declaration_p=*/false);
-	  return;
-	}
-    }
+          return;
+        }
 
-  /* Check for @defs.  */
-  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_DEFS))
-    {
-      tree ivar, member;
-      tree ivar_chains = cp_parser_objc_defs_expression (parser);
-      ivar = ivar_chains;
-      while (ivar)
-	{
-	  member = ivar;
-	  ivar = TREE_CHAIN (member);
-	  TREE_CHAIN (member) = NULL_TREE;
-	  finish_member_declaration (member);
-	}
-      return;
-    }
+      /* Check for a using-declaration.  */
+      if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
+        {
+          if (cxx_dialect < cxx0x)
+           	{
+              /* Parse the using-declaration.  */
+              cp_parser_using_declaration (parser,
+                  /*access_declaration_p=*/false);
+              return;
+    	      }
+          else
+            {
+              tree decl;
+              bool alias_decl_expected;
+              cp_parser_parse_tentatively (parser);
+              decl = cp_parser_alias_declaration (parser);
+              /* Note that if we actually see the '=' token after the
+                 identifier, cp_parser_alias_declaration commits the
+                 tentative parse.  In that case, we really expects an
+                 alias-declaration.  Otherwise, we expect a using
+                 declaration.  */
+              alias_decl_expected =
+                !cp_parser_uncommitted_to_tentative_parse_p (parser);
+              cp_parser_parse_definitely (parser);
+
+              if (alias_decl_expected)
+                finish_member_declaration (decl);
+              else
+                cp_parser_using_declaration (parser,
+                    /*access_declaration_p=*/false);
+              return;
+          	}
+        }
 
-  /* If the next token is `static_assert' we have a static assertion.  */
-  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC_ASSERT))
-    {
-      cp_parser_static_assert (parser, /*member_p=*/true);
-      return;
+      /* Check for @defs.  */
+      if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_DEFS))
+        {
+          tree ivar, member;
+          tree ivar_chains = cp_parser_objc_defs_expression (parser);
+          ivar = ivar_chains;
+          while (ivar)
+            {
+              member = ivar;
+              ivar = TREE_CHAIN (member);
+              TREE_CHAIN (member) = NULL_TREE;
+              finish_member_declaration (member);
+            }
+          return;
+        }
+
+      /* If the next token is `static_assert' we have a static assertion.  */
+      if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC_ASSERT))
+        {
+          cp_parser_static_assert (parser, /*member_p=*/true);
+          return;
+        }
     }
 
   parser->colon_corrects_to_scope_p = false;
 
-  if (cp_parser_using_declaration (parser, /*access_declaration=*/true))
-      goto out;
+  if (unconstrained)
+    if (cp_parser_using_declaration (parser, /*access_declaration=*/true))
+        goto out;
 
   /* Parse the decl-specifier-seq.  */
   decl_spec_token_start = cp_lexer_peek_token (parser->lexer);
@@ -19501,6 +19562,7 @@ cp_parser_member_declaration (cp_parser*
 
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
  out:
+  current_template_reqs = saved_template_reqs;
   parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
 }
 
@@ -20919,6 +20981,30 @@ cp_parser_label_declaration (cp_parser*
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
 }
 
+
+// Parse an optional template requirement, returning NULL_TREE if no
+// 'requires' clause is found. The template requirement is required to
+// be a constant expression.
+static tree
+cp_parser_template_requirement_opt (cp_parser* parser)
+{
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
+    cp_lexer_consume_token (parser->lexer);
+  else
+    return NULL_TREE;
+
+  // Parse a logical-or-expression as a constant expression.
+  tree expression = 
+    cp_parser_binary_expression (parser, false, false, PREC_NOT_OPERATOR, NULL);
+  if (!potential_rvalue_constant_expression (expression))
+    {
+      require_potential_rvalue_constant_expression (expression);
+      return error_mark_node;
+    }
+  return expression;
+}
+
+
 /* Support Functions */
 
 /* Looks up NAME in the current scope, as given by PARSER->SCOPE.
@@ -21778,6 +21864,15 @@ cp_parser_template_declaration_after_exp
   cp_parser_skip_to_end_of_template_parameter_list (parser);
   /* We just processed one more parameter list.  */
   ++parser->num_template_parameter_lists;
+
+  // Parse template requirements if any have been given.
+  tree saved_template_reqs = current_template_reqs;
+  if (flag_concepts)
+    {
+      if (tree req = cp_parser_template_requirement_opt (parser))
+        current_template_reqs = finish_template_requirements (req);
+    }
+
   /* If the next token is `template', there are more template
      parameters.  */
   if (cp_lexer_next_token_is_keyword (parser->lexer,
@@ -21821,6 +21916,7 @@ cp_parser_template_declaration_after_exp
 
   /* Finish up.  */
   finish_template_decl (parameter_list);
+  current_template_reqs = saved_template_reqs;
 
   /* Check the template arguments for a literal operator template.  */
   if (decl
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 196384)
+++ gcc/cp/semantics.c	(working copy)
@@ -9561,4 +9561,16 @@ is_lambda_ignored_entity (tree val)
   return false;
 }
 
+// Decompose the template requirements, given by EXPRESSION, into a set of
+// assumptions for the local scope.
+tree
+finish_template_requirements (tree expression)
+{
+  if (expression == error_mark_node)
+    return NULL_TREE;
+
+  sorry ("no template requirements yet");
+  return NULL_TREE;
+}
+
 #include "gt-cp-semantics.h"

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

* Re: [c++-concepts] Parsing for template requirements
  2013-03-01 16:13 [c++-concepts] Parsing for template requirements Andrew Sutton
@ 2013-03-01 17:09 ` Gabriel Dos Reis
  0 siblings, 0 replies; 2+ messages in thread
From: Gabriel Dos Reis @ 2013-03-01 17:09 UTC (permalink / raw)
  To: Andrew Sutton; +Cc: gcc-patches, Gabriel Dos Reis, Jason Merrill

On Fri, Mar 1, 2013 at 10:12 AM, Andrew Sutton
<andrew.n.sutton@gmail.com> wrote:
> Two patches attached.
>
> The reqs-parsing patch adds parsing support for template requirements
> (i.e., requires clauses). This is supported for all template
> declarations and non-template member functions of class templates.
> Grammar changes are documented in comments. Semantic processing of
> constraints is stubbed out for the time being.
>
> The flags patch just enables -fconcepts by default.
>
> The combined change log is:
>
> 2013-03-01  Andrew Sutton  <andrew.n.sutton@gmail.com>

Patch OK, thanks.  Please adjust the paths in the log to include
the directories -- since everything is going in the toplevel ChangeLog.concepts.

-- Gaby

>
>         * cp-tree.h (saved_scope): Add template requirements.
>         (finish_template_requirements): Declare
>         * parser.c (cp_parser_template_requirement_opt): Declare.
>         (cp_parser_template_declaration): Document grammar extensions.
>         (cp_parser_type_parameter): Parse requirements for template
>         template parameters.
>         (cp_parser_member_declaration): Parse requirements for
>         members of class templates.
>         (cp_parser_template_requirement_opt): Define.
>         (cp_parser_template_declaration_after_exp): Parse requirements
>         for template declarations.
>         * semantics.c (finish_template_requirements): Define.
>         * lex.c (cxx_init): Enable concepts by default.

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

end of thread, other threads:[~2013-03-01 17:09 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-01 16:13 [c++-concepts] Parsing for template requirements Andrew Sutton
2013-03-01 17:09 ` Gabriel Dos Reis

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).