This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Concepts code review


I don't believe I'll be able to familiarize myself adequately with the more complex issues before the stage 1 deadline (from what I understand Andrew is/was taking care of the blocking issues?), so I will leave what I have for the more trivial issues and a few comments.

On 11/11/2014 12:05 PM, Jason Merrill wrote:

// Diagnose constraint failures in a variable concept.
void
diagnose_var (location_t loc, tree t, tree args)

The name and comment seem misleading since T is actually a TEMPLATE_ID_EXPR.

Variable templates (and thus concepts) are TEMPLATE_ID_EXPR. I changed the comment to explicitly state that it will be a TEMPLATE_ID_EXPR, but I'm not sure the name needs to be changed. If I recall correctly, I initially implemented as *_var_concept and Andrew told me to shorten it. Note that this also matches up with normalize_var.

+// Bring the parameters of a function declaration back into
+// scope without entering the function body. The declarator
+// must be a function declarator. The caller is responsible
+// for calling finish_scope.
+void
+push_function_parms (cp_declarator *declarator)

I think if the caller is calling finish_scope, I'd prefer for the begin_scope call to be there as well.

Even though Andrew said that this will change later for other reasons, it's a function I wrote so: I actually debated this with Andrew before. My rationale for calling begin_scope in the function was that it feels consistent with the semantics of the call. Specifically it can be seen as reopening the function parameter scope. Thus the call is balanced by calling finish_scope. Either way would work of course, but perhaps it just needed a better name and/or comment?

+      // Save the current template requirements.
+      saved_template_reqs = release (current_template_reqs);

It seems like a lot of places with saved_template_reqs variables could be converted to use cp_manage_requirements.

Probably. The instance you quoted isn't very trivial though. The requirements are saved in two different branches and need to be restored before a certain point in the function. Might just need to spend more time looking over the code.

+  // FIXME: This could be improved. Perhaps the type of the requires
+  // expression depends on the satisfaction of its constraints. That
+  // is, its type is bool only if its substitution into its normalized
+  // constraints succeeds.

The requires-expression is not type-dependent, but it can be instantiation-dependent and value-dependent.

This is an interesting change. The REQUIRES_EXPR is currently marked as value dependent. The ChangeLog indicates that Andrew loosened the conditions for being value dependent for some cases, but then added it as type dependent when something else failed. May require some time to pin down exactly what needs to be done here.

- Braden Obrzut

2014-11-15  Braden Obrzut  <admin@maniacsvault.net>

    * gcc/cp/constraint.cc (resolve_constraint_check): Move definition
    check to grokfndecl.
    (normalize_template_id): Use expression location if available when
    informing about missing parentheses.
    (build_requires_expr): Added comment.
    (diagnose_var): Clarified comment.
    * gcc/cp/decl.c (check_concept_refinement): Remove outdated comment
    regarding variable concepts.
    (grokfndecl): Ensure that all concept declarations are definitions.
    (grokdeclarator): Remove outdated comment regarding variable concepts.
    * gcc/cp/parser.c (cp_parser_introduction_list): Use vec for temporary
    list instead of a TREE_LIST.
    (get_id_declarator): Renamed from cp_get_id_declarator.
    (get_unqualified_id): Renamed from cp_get_identifier.
    (is_constrained_parameter): Renamed from cp_is_constrained_parameter.
    (cp_parser_check_constrained_type_parm): Renamed from
    cp_check_constrained_type_parm.
    (cp_parser_constrained_type_template_parm): Renamed from
    cp_constrained_type_template_parm.
    (cp_parser_constrained_template_template_parm): Renamed from
    cp_constrained_template_template_parm.
    (constrained_non_type_template_parm): Renamed from
    cp_constrained_non_type_tmeplate_parm.
    (finish_constrained_parameter): Renamed from
    cp_finish_constrained_parameter.
    (maybe_type_parameter): Renamed from cp_maybe_type_parameter.
    (declares_type_parameter): Renamed from cp_declares_type_parameter.
    (declares_type_template_parameter): Renamed from
    cp_declares_type_template_parameter.
    (declares_template_template_parameter): Renamed from
    cp_declares_template_template_parameter.
    (cp_parser_type_parameter): Call
    cp_parser_default_type_template_argument and
    cp_parser_default_template_template_argument which were already
    factored out from this function.
    (cp_maybe_constrained_type_specifier): Use the new INTRODUCED_PARM_DECL
    instead of PLACEHOLDER_EXPR.
    (cp_parser_requires_expr_scope): Remove old comment and change
    destructor to use pop_bindings_and_leave_scope.
    (cp_parser_requires_expression): Remove old comment.
    (get_concept_from_constraint): Remove old comment.
    * gcc/testsuite/g++.dg/concepts/decl-diagnose.C: Changed expected
    errors now that missing concept definitions are diagnosed earlier.

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 2915b43..6550ec3 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -156,17 +156,6 @@ resolve_constraint_check (tree ovl, tree args)
   if (!DECL_DECLARED_CONCEPT_P (decl))
     return NULL_TREE;
 
-  // Concept declarations must have a corresponding definition.
-  //
-  // TODO: This should be part of the up-front checking for
-  // a concept declaration.
-  if (!DECL_SAVED_TREE (decl))
-    {
-      error_at (DECL_SOURCE_LOCATION (decl),
-                "concept %q#D has no definition", decl);
-      return NULL;
-    }
-
   return cands;
 }
 
@@ -610,13 +599,12 @@ normalize_template_id (tree t)
     return normalize_var (t);
   else
     {
-      // FIXME: input_location is probably wrong, but there's not necessarly
-      // an expr location with the tree.
-      error_at (input_location, "invalid constraint %qE", t);
+      location_t locus = EXPR_LOC_OR_LOC (t, input_location);
+      error_at (locus, "invalid constraint %qE", t);
 
       vec<tree, va_gc>* args = NULL;
       tree c = finish_call_expr (t, &args, true, false, 0);
-      inform (input_location, "did you mean %qE", c);
+      inform (locus, "did you mean %qE", c);
 
       return error_mark_node;
     }
@@ -865,6 +853,8 @@ valid_requirements_p (tree cinfo)
   return CI_ASSUMPTIONS (cinfo) != error_mark_node;
 }
 
+// Constructs a REQUIRES_EXPR with parameters, PARMS, and requirements, REQS,
+// that can be evaluated as a constant expression.
 tree
 build_requires_expr (tree parms, tree reqs)
 {
@@ -1836,7 +1826,7 @@ diagnose_call (location_t loc, tree t, tree args)
     inform (loc, "  %qE evaluated to false", t);
 }
 
-// Diagnose constraint failures in a variable concept.
+// Diagnose constraint failures in a variable template-id T.
 void
 diagnose_var (location_t loc, tree t, tree args)
 {
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 0f9926c..bb635d8 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1262,8 +1262,6 @@ check_concept_refinement (tree olddecl, tree newdecl)
   if (!DECL_DECLARED_CONCEPT_P (olddecl) || !DECL_DECLARED_CONCEPT_P (newdecl))
     return false;
 
-  // TODO: This isn't currently possible, but it will almost certainly
-  // change with variable templates.
   tree d1 = DECL_TEMPLATE_RESULT (olddecl);
   tree d2 = DECL_TEMPLATE_RESULT (newdecl);
   if (TREE_CODE (d1) != TREE_CODE (d2))
@@ -7724,6 +7722,13 @@ grokfndecl (tree ctype,
   // Was the concept specifier present?
   bool concept_p = inlinep & 4;
 
+  // Concept declarations must have a corresponding definition.
+  if (concept_p && !funcdef_flag)
+    {
+      error ("concept %qD has no definition", declarator);
+      return NULL_TREE;
+    }
+
   if (rqual)
     type = build_ref_qualified_type (type, rqual);
   if (raises)
@@ -11052,8 +11057,6 @@ grokdeclarator (const cp_declarator *declarator,
 		      DECL_GNU_TLS_P (decl) = true;
 		  }
 		if (concept_p)
-		  // TODO: This needs to be revisited once variable
-		  // templates are supported
 		    error ("static data member %qE declared %<concept%>",
 			   unqualified_id);
 		else if (constexpr_p && !initialized)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 65d4acc..70bbbab 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -13344,7 +13344,7 @@ cp_parser_template_parameter_list (cp_parser* parser)
 static tree
 cp_parser_introduction_list (cp_parser *parser)
 {
-  tree introduction_list = NULL_TREE;
+  vec<tree, va_gc> *introduction_vec = make_tree_vector ();
 
   while (true)
     {
@@ -13358,8 +13358,7 @@ cp_parser_introduction_list (cp_parser *parser)
 	= cp_lexer_peek_token (parser->lexer)->location;
       DECL_NAME (parm) = cp_parser_identifier (parser);
       INTRODUCED_PACK_P (parm) = is_pack;
-      introduction_list = chainon (introduction_list,
-				   build_tree_list (NULL_TREE, parm));
+      introduction_vec->quick_push (parm);
 
       // If the next token is not a `,', we're done.
       if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
@@ -13368,27 +13367,23 @@ cp_parser_introduction_list (cp_parser *parser)
       cp_lexer_consume_token (parser->lexer);
     }
 
-  // Convert the TREE_LIST into a TREE_VEC, similar to what is done in
-  // end_template_parm_list.
-  tree introduction_vec = make_tree_vec (list_length (introduction_list));
-  int n = 0;
-  while (introduction_list != NULL_TREE)
+  // Convert the vec into a TREE_VEC.
+  tree introduction_list = make_tree_vec (introduction_vec->length ());
+  unsigned int n;
+  tree parm;
+  FOR_EACH_VEC_ELT (*introduction_vec, n, parm)
     {
-       tree next = TREE_CHAIN (introduction_list);
-       TREE_VEC_ELT (introduction_vec, n) = TREE_VALUE (introduction_list);
-       TREE_CHAIN (introduction_list) = NULL_TREE;
-
-       introduction_list = next;
-       ++n;
+       TREE_VEC_ELT (introduction_list, n) = parm;
     }
 
-  return introduction_vec;
+  release_tree_vector (introduction_vec);
+  return introduction_list;
 }
 
 // Given a declarator, get the declarator-id part, or NULL_TREE if this
 // is an abstract declarator.
 static inline cp_declarator*
-cp_get_id_declarator (cp_declarator *declarator)
+get_id_declarator (cp_declarator *declarator)
 {
   cp_declarator *d = declarator;
   while (d && d->kind != cdk_id)
@@ -13399,9 +13394,9 @@ cp_get_id_declarator (cp_declarator *declarator)
 // Get the unqualified-id from the DECLARATOR or NULL_TREE if this
 // is an abstract declarator.
 static inline tree
-cp_get_identifier (cp_declarator *declarator)
+get_unqualified_id (cp_declarator *declarator)
 {
-  declarator = cp_get_id_declarator (declarator);
+  declarator = get_id_declarator (declarator);
   if (declarator)
     return declarator->u.id.unqualified_name;
   else
@@ -13410,7 +13405,7 @@ cp_get_identifier (cp_declarator *declarator)
 
 // Returns true if PARM declares a constrained-parameter.
 static inline bool
-cp_is_constrained_parameter (cp_parameter_declarator *parm)
+is_constrained_parameter (cp_parameter_declarator *parm)
 {
   gcc_assert (parm);
   tree decl = parm->decl_specifiers.type;
@@ -13426,8 +13421,8 @@ cp_is_constrained_parameter (cp_parameter_declarator *parm)
 // Check that the type parameter is only a declarator-id, and that its
 // type is not cv-qualified.
 bool
-cp_check_constrained_type_parm (cp_parser *parser,
-                                cp_parameter_declarator *parm)
+cp_parser_check_constrained_type_parm (cp_parser *parser,
+				       cp_parameter_declarator *parm)
 {
   if (!parm->declarator)
     return true;
@@ -13452,11 +13447,11 @@ cp_check_constrained_type_parm (cp_parser *parser,
 // Finish parsing/processing a template type parameter and chekcing
 // various restrictions.
 static inline tree
-cp_constrained_type_template_parm (cp_parser *parser,
-                                   tree id,
-                                   cp_parameter_declarator* parmdecl)
+cp_parser_constrained_type_template_parm (cp_parser *parser,
+                                          tree id,
+                                          cp_parameter_declarator* parmdecl)
 {
-  if (cp_check_constrained_type_parm (parser, parmdecl))
+  if (cp_parser_check_constrained_type_parm (parser, parmdecl))
     return finish_template_type_parm (class_type_node, id);
   else
     return error_mark_node;
@@ -13465,12 +13460,12 @@ cp_constrained_type_template_parm (cp_parser *parser,
 // Finish parsing/processing a template template parameter by borrowing
 // the template parameter list from the prototype parameter.
 static tree
-cp_constrained_template_template_parm (cp_parser *parser,
-                                       tree proto,
-                                       tree id,
-                                       cp_parameter_declarator *parmdecl)
+cp_parser_constrained_template_template_parm (cp_parser *parser,
+                                              tree proto,
+                                              tree id,
+                                              cp_parameter_declarator *parmdecl)
 {
-  if (!cp_check_constrained_type_parm (parser, parmdecl))
+  if (!cp_parser_check_constrained_type_parm (parser, parmdecl))
     return error_mark_node;
 
   // FIXME: This should probably be copied, and we may need to adjust
@@ -13487,8 +13482,8 @@ cp_constrained_template_template_parm (cp_parser *parser,
 
 // Create a new non-type template parameter from the given PARM declarator.
 static tree
-cp_constrained_non_type_template_parm (bool *is_non_type,
-                                       cp_parameter_declarator *parm)
+constrained_non_type_template_parm (bool *is_non_type,
+                                    cp_parameter_declarator *parm)
 {
   *is_non_type = true;
   cp_declarator *decl = parm->declarator;
@@ -13502,13 +13497,13 @@ cp_constrained_non_type_template_parm (bool *is_non_type,
 // refers to the prototype template parameter that ultimately
 // specifies the type of the declared parameter.
 static tree
-cp_finish_constrained_parameter (cp_parser *parser,
-                                 cp_parameter_declarator *parmdecl,
-                                 bool *is_non_type,
-                                 bool *is_parameter_pack)
+finish_constrained_parameter (cp_parser *parser,
+                              cp_parameter_declarator *parmdecl,
+                              bool *is_non_type,
+                              bool *is_parameter_pack)
 {
   tree decl = parmdecl->decl_specifiers.type;
-  tree id = cp_get_identifier (parmdecl->declarator);
+  tree id = get_unqualified_id (parmdecl->declarator);
   tree def = parmdecl->default_argument;
   tree proto = DECL_INITIAL (decl);
 
@@ -13521,11 +13516,12 @@ cp_finish_constrained_parameter (cp_parser *parser,
   // Build the parameter. Return an error if the declarator was invalid.
   tree parm;
   if (TREE_CODE (proto) == TYPE_DECL)
-    parm = cp_constrained_type_template_parm (parser, id, parmdecl);
+    parm = cp_parser_constrained_type_template_parm (parser, id, parmdecl);
   else if (TREE_CODE (proto) == TEMPLATE_DECL)
-    parm = cp_constrained_template_template_parm (parser, proto, id, parmdecl);
+    parm = cp_parser_constrained_template_template_parm (parser, proto, id,
+							 parmdecl);
   else
-    parm = cp_constrained_non_type_template_parm (is_non_type, parmdecl);
+    parm = constrained_non_type_template_parm (is_non_type, parmdecl);
   if (parm == error_mark_node)
     return error_mark_node;
 
@@ -13540,7 +13536,7 @@ cp_finish_constrained_parameter (cp_parser *parser,
 // a template type parameter. This is a helper function for the
 // cp_declares_type* functions below.
 static inline bool
-cp_maybe_type_parameter (tree type)
+maybe_type_parameter (tree type)
 {
   return type
          && TREE_CODE (type) == TYPE_DECL
@@ -13551,9 +13547,9 @@ cp_maybe_type_parameter (tree type)
 // Returns true if the parsed type actually represents a type or template
 // template parameter.
 static inline bool
-cp_declares_type_parameter (tree type)
+declares_type_parameter (tree type)
 {
-  if (cp_maybe_type_parameter (type))
+  if (maybe_type_parameter (type))
     {
       tree_code c = TREE_CODE (TREE_TYPE (type));
       return c == TEMPLATE_TYPE_PARM || c == TEMPLATE_TEMPLATE_PARM;
@@ -13564,9 +13560,9 @@ cp_declares_type_parameter (tree type)
 // Returns true if the parsed type actually represents the declaration
 // of a type template-parameter.
 static inline bool
-cp_declares_type_template_parameter (tree type)
+declares_type_template_parameter (tree type)
 {
-  return cp_maybe_type_parameter (type)
+  return maybe_type_parameter (type)
          && TREE_CODE (TREE_TYPE (type)) == TEMPLATE_TYPE_PARM;
 }
 
@@ -13574,9 +13570,9 @@ cp_declares_type_template_parameter (tree type)
 // Returns true if the parsed type actually represents the declaration of
 // a template template-parameter.
 static bool
-cp_declares_template_template_parameter (tree type)
+declares_template_template_parameter (tree type)
 {
-  return cp_maybe_type_parameter (type)
+  return maybe_type_parameter (type)
          && TREE_CODE (TREE_TYPE (type)) == TEMPLATE_TEMPLATE_PARM;
 }
 
@@ -13784,20 +13780,20 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type,
 		  "template parameter pack cannot have a default argument");
       
       /* Parse the default argument, but throw away the result.  */
-      if (cp_declares_type_template_parameter (declared_type))
+      if (declares_type_template_parameter (declared_type))
         cp_parser_default_type_template_argument (parser);
-      else if (cp_declares_template_template_parameter (declared_type))
+      else if (declares_template_template_parameter (declared_type))
         cp_parser_default_template_template_argument (parser);
       else
         cp_parser_default_argument (parser, /*template_parm_p=*/true);
     }
 
   // The parameter may have been constrained.
-  if (cp_is_constrained_parameter (parameter_declarator))
-    return cp_finish_constrained_parameter (parser,
-                                            parameter_declarator,
-                                            is_non_type,
-                                            is_parameter_pack);
+  if (is_constrained_parameter (parameter_declarator))
+    return finish_constrained_parameter (parser,
+                                         parameter_declarator,
+                                         is_non_type,
+                                         is_parameter_pack);
 
   // Now we're sure that the parameter is a non-type parameter.
   *is_non_type = true;
@@ -13878,11 +13874,8 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
 	/* If the next token is an `=', we have a default argument.  */
 	if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
 	  {
-	    /* Consume the `=' token.  */
-	    cp_lexer_consume_token (parser->lexer);
-	    /* Parse the default-argument.  */
-	    push_deferring_access_checks (dk_no_deferred);
-	    default_argument = cp_parser_type_id (parser);
+	    default_argument
+	      = cp_parser_default_type_template_argument (parser);
 
             /* Template parameter packs cannot have default
                arguments. */
@@ -13898,7 +13891,6 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
 			    "default arguments");
                 default_argument = NULL_TREE;
               }
-	    pop_deferring_access_checks ();
 	  }
 	else
 	  default_argument = NULL_TREE;
@@ -13977,40 +13969,8 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
 	   default-argument.  */
 	if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
 	  {
-	    bool is_template;
-
-	    /* Consume the `='.  */
-	    cp_lexer_consume_token (parser->lexer);
-	    /* Parse the id-expression.  */
-	    push_deferring_access_checks (dk_no_deferred);
-	    /* save token before parsing the id-expression, for error
-	       reporting */
-	    token = cp_lexer_peek_token (parser->lexer);
-	    default_argument
-	      = cp_parser_id_expression (parser,
-					 /*template_keyword_p=*/false,
-					 /*check_dependency_p=*/true,
-					 /*template_p=*/&is_template,
-					 /*declarator_p=*/false,
-					 /*optional_p=*/false);
-	    if (TREE_CODE (default_argument) == TYPE_DECL)
-	      /* If the id-expression was a template-id that refers to
-		 a template-class, we already have the declaration here,
-		 so no further lookup is needed.  */
-		 ;
-	    else
-	      /* Look up the name.  */
-	      default_argument
-		= cp_parser_lookup_name (parser, default_argument,
-					 none_type,
-					 /*is_template=*/is_template,
-					 /*is_namespace=*/false,
-					 /*check_dependency=*/true,
-					 /*ambiguous_decls=*/NULL,
-					 token->location);
-	    /* See if the default argument is valid.  */
 	    default_argument
-	      = check_template_template_default_arg (default_argument);
+	      = cp_parser_default_template_template_argument (parser);
 
             /* Template parameter packs cannot have default
                arguments. */
@@ -14026,7 +13986,6 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
 			    "have default arguments");
                 default_argument = NULL_TREE;
               }
-	    pop_deferring_access_checks ();
 	  }
 	else
 	  default_argument = NULL_TREE;
@@ -15586,7 +15545,7 @@ cp_parser_type_name (cp_parser* parser)
 	  && TREE_CODE (type_decl) == TYPE_DECL
 	  && TYPE_DECL_ALIAS_P (type_decl))
 	gcc_assert (DECL_TEMPLATE_INSTANTIATION (type_decl));
-      else if (cp_maybe_type_parameter (type_decl))
+      else if (maybe_type_parameter (type_decl))
         /* Don't do anything. */ ;
       else
 	cp_parser_simulate_error (parser);
@@ -15639,7 +15598,7 @@ cp_maybe_constrained_type_specifier (cp_parser *parser, tree decl, tree args)
 
   // Try to build a call expression that evaluates the concept. This
   // can fail if the overload set refers only to non-templates.
-  tree placeholder = build_nt (PLACEHOLDER_EXPR);
+  tree placeholder = build_nt (INTRODUCED_PARM_DECL);
   tree call = build_concept_check (decl, placeholder, args);
   if (call == error_mark_node)
     return NULL_TREE;
@@ -19639,12 +19598,12 @@ cp_parser_parameter_declaration (cp_parser *parser,
 	default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false);
 
       // A constrained-type-specifier may declare a type template-parameter.
-      else if (cp_declares_type_template_parameter (type))
+      else if (declares_type_template_parameter (type))
         default_argument
           = cp_parser_default_type_template_argument (parser);
 
       // A constrained-type-specifier may declare a template-template-parameter.
-      else if (cp_declares_template_template_parameter (type))
+      else if (declares_template_template_parameter (type))
         default_argument
           = cp_parser_default_template_template_argument (parser);
 
@@ -23311,7 +23270,6 @@ cp_parser_requires_clause_opt (cp_parser *parser)
 // within the scope are popped prior to exiting the scope.
 struct cp_parser_requires_expr_scope
 {
-  // Enter a scope of kind K belonging to the decl D.
   cp_parser_requires_expr_scope ()
   {
     begin_scope (sk_block, NULL_TREE);
@@ -23319,9 +23277,7 @@ struct cp_parser_requires_expr_scope
 
   ~cp_parser_requires_expr_scope ()
   {
-    for (tree t = current_binding_level->names; t; t = DECL_CHAIN (t))
-      pop_binding (DECL_NAME (t), t);
-    leave_scope ();
+    pop_bindings_and_leave_scope ();
   }
 };
 
@@ -23345,10 +23301,6 @@ cp_parser_requires_expression (cp_parser *parser)
       return error_mark_node;
     }
 
-
-  // TODO: Check that requires expressions are only written inside of
-  // template declarations. They don't need to be concepts, just templates.
-
   // Parse the optional parameter list. Any local parameter declarations
   // are added to a new scope and are visible within the nested
   // requirement list.
@@ -33692,13 +33644,6 @@ tree_type_is_auto_or_concept (const_tree t)
 
 // Return the template decl being called or evaluated as part of the
 // constraint check.
-//
-// TODO: This is a bit of a hack. When we finish the template parameter
-// the constraint is just a call expression, but we don't have the full
-// context that we used to build that call expression. Since we're going
-// to be comparing declarations, it would helpful to have that. This
-// means we'll have to make the TREE_TYPE of the parameter node a pair
-// containing the context (the TYPE_DECL) and the constraint.
 static tree
 get_concept_from_constraint (tree t)
 {
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 6e57a72..ee6e2b2 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -397,9 +397,9 @@ typedef struct GTY(()) cp_parser {
      member definition using a generic type, it is the sk_class scope.  */
   cp_binding_level* implicit_template_scope;
 
-  /* True if parsing a template parameter list. The interpretation of a
-     constrained-type-specifiers differs inside a template parameter
-     list than outside. */
+  /* True if parsing a result type in a compound requirement. This permits
+     constrained-type-specifiers inside what would normally be a trailing
+     return type. */
   bool in_result_type_constraint_p;
 
 } cp_parser;
diff --git a/gcc/testsuite/g++.dg/concepts/decl-diagnose.C b/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
index d3374f9..77fc40d 100644
--- a/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
+++ b/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
@@ -4,14 +4,17 @@ typedef concept int CINT; // { dg-error "'concept' cannot appear in a typedef de
 
 void f(concept int); // { dg-error "a parameter cannot be declared 'concept'" }
 
-concept int f2(); // { dg-error "return type" }
-concept bool f3();
+template<typename T>
+concept int f2() { return 0; } // { dg-error "return type" }
+concept bool f3(); // { dg-error "no definition" }
 
 struct X
 {
-  concept int f4(); // { dg-error "return type|function parameters" }
-  concept bool f5(); // { dg-error "declared with function parameters" }
-  static concept bool f6(); // { dg-error "a concept cannot be a static member function" }
+  template<typename T>
+  concept int f4() { return 0; } // { dg-error "return type|function parameters" }
+  concept bool f5() { return true; } // { dg-error "declared with function parameters" }
+  template<typename T>
+  static concept bool f6() { return true; } // { dg-error "a concept cannot be a static member function" }
   static concept bool x; // { dg-error "declared 'concept'" }
   concept int x2; // { dg-error "declared 'concept'" }
   concept ~X(); // { dg-error "a destructor cannot be 'concept'" }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]