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