> It looks like things are coming together pretty well. What's your feeling > about readiness to merge into the trunk? Is the branch down to no > regressions?
They are coming together pretty well. We have one major unit test failure involving template introductions (Braden is working on it), one involving constraint equivalence that I plan to tackle next week. Other than those issues, which I hope to clear up next week, I think it's ready. > See you on Monday! Unfortunately, I won't be attending. Andrew > >> @@ -4146,21 +4146,21 @@ build_new_function_call (tree fn, vec<tree, va_gc> >> **args, bool koenig_p, >> if (TREE_CODE (fn) == TEMPLATE_ID_EXPR) >> { >> /* If overload resolution selects a specialization of a >> + function concept for non-dependent template arguments, >> + the expression is true if the constraints are satisfied >> + and false otherwise. >> >> NOTE: This is an extension of Concepts Lite TS that >> allows constraints to be used in expressions. */ >> + if (flag_concepts && !processing_template_decl) >> { >> tree tmpl = DECL_TI_TEMPLATE (cand->fn); >> + tree targs = DECL_TI_ARGS (cand->fn); >> tree decl = DECL_TEMPLATE_RESULT (tmpl); >> + if (DECL_DECLARED_CONCEPT_P (decl) >> + && !uses_template_parms (targs)) { >> + return evaluate_function_concept (decl, targs); > > > If processing_template_decl is false, uses_template_parms should always be > false as well. > >> +function_concept_check_p (tree t) > > >> + tree fn = CALL_EXPR_FN (t); >> + if (TREE_CODE (fn) == TEMPLATE_ID_EXPR >> + && TREE_CODE (TREE_OPERAND (fn, 0)) == OVERLOAD) >> + { >> + tree f1 = OVL_FUNCTION (TREE_OPERAND (fn, 0)); > > > I think you want get_first_fn here. > >> if (TEMPLATE_PARM_CONSTRAINTS (current_template_parms)) >> - TYPE_CANONICAL (type) = type; >> + SET_TYPE_STRUCTURAL_EQUALITY (type); > > > This seems like papering over an underlying issue. What was the testcase > that motivated this change? > >> @@ -11854,7 +11854,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t >> complain) >> - if (!spec) >> + if (!spec && DECL_LANG_SPECIFIC (t)) >> - if (!local_p) >> + if (!local_p && DECL_LANG_SPECIFIC (r)) > > > What motivated these changes? From the testcase, it seems that you're > getting here with the decl for "using TD = int", which shouldn't happen. > >> @@ -1159,7 +1159,6 @@ check_noexcept_r (tree *tp, int * /*walk_subtrees*/, >> void * /*data*/) >> - tree type = TREE_TYPE (TREE_TYPE (fn)); >> - if (!TYPE_NOTHROW_P (type)) >> + if (!TYPE_NOTHROW_P (TREE_TYPE (fn))) > > > The old code was incorrectly assuming that CALL_EXPR_FN is always a function > pointer, but your new code seems to be incorrectly assuming that it's always > a function or an expression taking the address of a function; I think this > will break on a call to a function pointer variable. > >> @@ -3481,13 +3481,27 @@ cxx_eval_constant_expression (const constexpr_ctx >> *ctx, tree t, >> case REQUIRES_EXPR: >> + if (!processing_template_decl) >> + return evaluate_constraint_expression (t, NULL_TREE); >> + else >> + *non_constant_p = true; >> + return t; > > > We shouldn't get here with a dependent REQUIRES_EXPR (or any dependent > expression), so we shouldn't ever hit the else clause. > >> @@ -18063,18 +18063,41 @@ cp_parser_declarator (cp_parser* parser, >> + /* Function declarations may be followed by a trailing >> + requires-clause. Declarators for function declartions >> + are function declarators wrapping an id-declarator. >> + If the inner declarator is anything else, it does not >> + declare a function. These may also be reference or >> + pointer declarators enclosing such a function declarator. >> + In the declaration : >> + >> + int *f(args) >> + >> + the declarator is *f(args). >> + >> + Abstract declarators cannot have a requires-clauses >> + because they do not declare functions. Here: >> >> void f() -> int& requires false >> >> + The trailing return type contains an abstract declarator, >> + and the requires-clause applies to the function >> + declaration and not the abstract declarator. */ >> + if (flag_concepts && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT) >> { >> + /* We could have things like *f(args) or &f(args). >> + Look inside references and pointers. */ >> + cp_declarator* p = declarator; >> + if (p->kind == cdk_reference || p->kind == cdk_pointer) >> + p = p->declarator; >> + >> + /* Pointers or references with no name, or functions >> + with no name cannot have constraints. */ >> + if (!p || !p->declarator) >> + return declarator; >> + >> + /* Look for f(args) but not (*f)(args). */ >> + if (p && p->kind == cdk_function && p->declarator->kind == cdk_id) > > > I think you can use function_declarator_p here. > >> +static inline bool >> +pending_expansion_p (tree t) >> +{ >> + return (TREE_CODE (t) == PARM_DECL && CONSTRAINT_VAR_P (t) >> + && PACK_EXPANSION_P (TREE_TYPE (t))); >> +} > > > What's the difference between this and function_parameter_pack_p? > >> + /* A sentinel class that ensures that deferred access checks >> + are popped before a function returns. */ >> + struct deferring_access_check_sentinel >> + { >> + deferring_access_check_sentinel () >> + { >> + push_deferring_access_checks (dk_deferred); >> + } >> + ~ deferring_access_check_sentinel () >> + { >> + pop_deferring_access_checks (); >> + } >> + } > > > Let's put this with the other RAII sentinels in cp-tree.h. > >> + Lifting of concept definitions > > > Could we have a bit more description of what "lifting" means here? > >> >> +/*--------------------------------------------------------------------------- >> + Constraint normalization >> >> +---------------------------------------------------------------------------*/ > > > You have two of these headers; I guess the first one should be > "transformation" and could use more description. On the second, I would > retain the old comment > >> -// Normalize a template requirement to a logical formula written in terms >> of >> -// atomic propositions, returing the new expression. If the expression >> cannot >> -// be normalized, a NULL_TREE is returned. > > >> +check_implicit_conversion_constraint (tree t, tree args, >> + tsubst_flags_t complain, tree >> in_decl) >> +{ >> + tree expr = ICONV_CONSTR_EXPR (t); >> + >> + /* Don't tsubst as if we're processing a template. If we try >> + to we can end up generating template-like expressions >> + (e.g., modop-exprs) that aren't properly typed. */ >> + int saved_template_decl = processing_template_decl; >> + processing_template_decl = 0; > > > Why are we checking constraints when processing_template_decl is true? > >> + Note that this is the only place that we instantiate the >> + constraints. */ >> +bool >> +check_constraints (tree ci, tree args) > > > Except for tsubst_constraint? > >> + ++processing_template_decl; >> + tree constr = transform_expression (lift_function_definition (fn, >> args)); >> + --processing_template_decl; > > > Why do you need to set processing_template_decl here and in other calls to > transform_expression? I don't notice anything that would be helped, > especially now that you're using separate tree codes for constraints, though > there is this in check_logical_expr: > >> + /* Resolve the logical operator. Note that template processing is >> + disabled so we get the actual call or target expression back. >> + not_processing_template_sentinel sentinel. > > > I guess that isn't needed anymore? > >> + FIXME: This is defined in pt.c because it's garbage collection >> + code is not being generated for constraint.cc. */ >> +static GTY (()) hash_table<constr_hasher> *decl_constraints; > > > I think you need to add constraint.cc to the gtfiles variable in > cp/config-lang.in. It also looks like the GTFILES_H rule in gcc/Makefile.in > assumes that all sources have the .c extension, so that may need adjustment. > >> @@ -2454,6 +2454,8 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, >> bool d >> next = OVL_CHAIN (fn); >> + if (flag_concepts) >> + remove_constraints (OVL_FUNCTION (fn)); > > > I don't think we want to remove constraints here; this code is just > discarding the OVERLOAD node, not the FUNCTION_DECL. > > Jason >