>> 2. I left the <cstdlib> include in system.h, because removing it will
>> result in errors due to an inclusion of <algorithm>. It's probable
>> that both can be removed, but I didn't test it with this patch.
>
>
> You mean you don't need <algorithm> anymore in logic.cc?  I think we want
> the <cstdlib> include in general if we're going to support people using the
> C++ standard library.

I don't. Those decisions are above my pay grade, so I'm doing my best
not to make them.



>> +          reason = template_unification_error_rejection ();
>
>
> Can't you do
>
>   template_constraint_failure (DECL_TI_TEMPLATE (fn), DECL_TI_ARGS (fn))

I can indeed. Fixed.


>>    if (fn == error_mark_node)
>>      {
>> +      if (!check_template_constraints (tmpl, targs))
>> +          reason = template_constraint_failure (tmpl, targs);
>> +      else if (errorcount+sorrycount == errs)
>>        /* Don't repeat unification later if it already resulted in errors.
>> */
>
>
> A constraint failure is a form of unification failure, like SFINAE; let's
> handle it in that context rather than separately here, and reserve
> rr_constraint_failure for the case of a non-template member function.

And emit the diagnostics in fn_type_unification when explain_p is set?
Seems reasonable.


> The uses of "actual template" in the comment and function name seem to mean
> different things.  Maybe call the function template_decl_for_candidate?

Fixed.

> Can friend temploids be constrained?

I have not thought deeply about constrained friend declarations. What
would a friend temploid look like?


> Seems like the comment is no longer accurate; the function now only returns
> NULL_TREE if both a and b are NULL_TREE.

It's not. And I removed disjoin_requirements. I don't think it will
ever be used.

>> +static tree
>> +get_constraint_check (tree call)
>
> The comment needs updating.  And the function isn't used anywhere; it seems
> redundant with resolve_constraint_check.

I removed the function.


>> +// and other template nodes from generating new expressions
>> +// during instantiation.
>
> I'm not clear on the issue.  Perhaps leaving processing_template_decl alone
> and using fold_non_dependent_expr would accomplish what you want?

I don't think that will work. The problem comes from the instantiation
of traits (and some other expressions) during constraint checking.
When processing_template_decl is non-zero, finish_trait_expr will
create TRAIT_EXPR nodes, which aren't handled by the constexpr
evaluation engine.

I could updated constexpr to fix that, or changed finish_trait_expr
(and others? noexcept maybe) to evaluate for non-dependent arguments,
but I was trying to limit the scope of my changes.

I'd really like for this structure to go away. It's very fragile.


>> +// Check the template's constraints for the specified arguments,
>> +// returning true if the constraints are satisfied and false
>> +// otherwise.
>> +bool
>> +check_template_constraints (tree t, tree args)
>> +{
>> +  return check_constraints (get_constraints (t), args);
>> +}
>
>
> Seems like the last function would also work for types and non-template
> decls.

It should. Updated the comment to reflect the broader applicability of
the function.


>> +  error_at (loc, "constraints not satisfied");
>
>
> I assume you're planning to make this more verbose?  It could use a TODO to
> that effect.

Very much so. Added comments.


>> +  else if (are_constrained_overloads (newdecl, olddecl))
>> +    {
>> +      // If newdecl and olddecl are function templates with the
>> +      // same type but different constraints, then they cannot be
>> +      // duplicate declarations. However, if the olddecl is declared
>> +      // as a concept, then the program is ill-formed.
>> +      if (DECL_DECLARED_CONCEPT_P (DECL_TEMPLATE_RESULT (olddecl)))
>> +        {
>> +          error ("cannot specialize concept %q#D", olddecl);
>> +          return error_mark_node;
>> +        }
>> +      return NULL;
>> +    }
>
>
> We should check for differing constraints in decls_match, and then this code
> should be in the !types_match section of duplicate_decls.

I'll get back to you on this. I need to work my way through that code.


>
>>        error ("concept %q#D result must be convertible to bool", fn);
>
>
> Why don't we require the result to actually be bool?  It seems difficult to
> decompose dependent requirements if the return type can be something else.

I'm probably sitting somewhere between two ideas. Requiring the result
to be exactly bool is fine.


>> +              cp_lexer_next_token_is_keyword (parser->lexer,
>> RID_REQUIRES))
>>            {
>>              tree reqs = release (current_template_reqs);
>> -            if (tree r = cp_parser_requires_clause_opt (parser))
>> +            if (tree r = cp_parser_requires_clause (parser))
>
>
> I was thinking to change the name of cp_requires_clause to
> cp_parser_requires_clause_opt and change the assert to a test for the
> keyword and return NULL_TREE if it isn't found.

I see. That is cleaner.


>> +          // FIXME: we should be checking the constraints, not just
>> +          // instantiating them.
>
>
> Let's check them in determine_specialization, along with the SFINAE check
> after the comment
>          /* Make sure that the deduced arguments actually work.  */

Okay. I'm not sure where the diagnostics for those failures fit in
yet. I've left a TODO note.


> Can explicit specializations have constraints, to indicate which template
> they are specializing?

Good question. I don't think so. I believe that it would be a
specialization of the most specialized function template whose
constraints were satisfied. So:

  template<Arithmetic T> void f(T x); // #1
  template<Integral T> void f(T x); // #2

  template<> void f(double); // Specializes #1
  template<> void f(int); // Specializes #2

I haven't tested this yet, but it seems like it would follow from the
usual overload resolution rules.


>> +// Argument deduction ios applied to all template arguments, and
>
>
> Passing 'true' for require_all_args means no deduction will be done; rather,
> all arguments must either be specified or have default arguments.

I see. It seems like I should be passing false here, since I want to
ensure that the resulting argument list can be used to instantiate the
template.


>> +      // Check class template requirements. Note that constraints will
>> +      // already have been checked when trying to find a most specialized
>> +      // class among multiple specializations.
>
>
> I don't see where that is; more_specialized_class doesn't seem to compare
> constraints yet.

It doesn't. I have to rethink some aspects of how partial
specialization work. I'm also waiting until specializations get
TEMPLATE_DECs.

Checking specializations will probably happen in get_class_bindings.
That doesn't seem to get called when there are no specializations.

>> +            // FIXME: Do we need to attach constraints?
>> +            // TODO: Is this actually necessary?
>
>
> I don't think you need to fill in TI_CONSTRAINT for anything but the main
> template patterns, here or other places.

Agreed.

>> +substitute_requirements (tree reqs, tree args)
>
> This seems redundant with instantiate_requirements.

It is. I'm using it for constraint diagnosis in a separate version,
but I may not need it. I've removed the function for now.


I'll look over the decls_match code and try to get a revised patch out tomorrow.

Andrew

Reply via email to