Improving concepts performance and diagnostics.

PR c++/67565
	PR c++/67579
	PR c++/71843
gcc/
	* timevar.def (TV_CONSTRAINT_SAT, TV_CONSTRAINT_SUB): New time vars
	for constraint satisfaction and subsumption.
	* timevar.h (auto_timevar): New constructor that matches the push/pop
	pattern of usage in pt.c.
gcc/cp/
	* cp-tree.def (CHECK_CONSTR): New.
	* cp-tree.h (CHECK_CONSTR_CONCEPT): New.
	(CHECK_CONSTR_ARGS): New.
	* constraint.cc (make_predicate_constraint): Remove in favor of
	normalize_expression.
	(resolve_constraint_check): Actually return error_mark_node when
	resolution fails.
	(resolve_variable_concept_check): Perform coercion as if processing
	a template. Also return errors on resolution failure.
	(lift_*): Remove all of these functions. Don't unnecessarily inline
	concepts.
	(learn_*): Add facilities to memoize implications for subsumption
	during normalization.
	(expanding_concept): New.
	(expand_concept): New. Return the inlined and normalized definition
	of a concept when needed.
	(transform_*, xform_*): Rename to normalize_* to better reflect the
	responsibility of those functions.
	(normalize_template_id_expression): Check for non-boolean operands
	when possible. Generate check constraints instead of normal variable
	references.
	(normalize_call_expression): Report errors when resolution fails.
	(check_for_logical_overloads): Rewrite this check to more accurately
	report the error.
	(normalize_atom): Check for overloaded calls and invalid types before
	determining if the expression refers to a concept.
	(build_constraints): Don't cache normalized constraints or decmposed
	assumptions.
	(finish_shorthand_constraint): Return a normalized expression instead
	of a predicate constraint.
	(finish_template_introduction): Same.
	(placeholder_extract_concept_and_args): Rewrite this since we only
	ever get check constraints here.
	(equivalent_placeholder_constraints): Rewrite in terms of check
	constraints, and handle error_mark_nodes correctly.
	(tsubst_check_constraint, tsubst_expr_constr, tsubst_type_constr)
	(tsubst_implicit_conversion_constr)
	(tsubst_argument_deduction_constr, tsubst_exception_constr)
	(tsubst_parameterized_constraint, tsubst_constraint): New.
	(tsbust_conjunection): Replace with tsubst_logical_operator and
	actually generate the right kind of constraint.
	(tsubst_requirement_body): Reverse the order of substituted arguments
	so that they appear in the order written (helps diagnostics).
	(satisfy_check_constraint): New.
	(satisfy_conjunction): Simplify.
	(satisfy_disjunction): Same.
	(satisfy_constraint_1): Handle check constraints.
	(eval_constr): New (private) global state.
	(evaluating_constraints_sentinel): New. Manages eval_constr.
	(satisfy_constraint): Add timing variables.
	(satisfy_associated_constraints): Add hooks for memoization.
	(evaluate_function_concept): Build a check constraint instead of
	normalizing its definition.
	(evaluate_variable_concept): Same.
	(evaluate_constraint_expression): Normalize, but in the current
	declaration processing context.
	(evaluating_constraints_p): New.
	(elide_constraint_failure_p): Actually emit constraint_thresh errors.
	(diagnose_*): Remove artificial indentation. Add a new parameter to
	each that tracks the current (complete) constraint prior to any
	substitutions.
	(diagnose_expression): Removed.
	(diagnose_call_expression): Same.
	(diagnose_template_id): Same.
	(diagnose_template_id): New.
	(diagnose_logical_constraint): New.
	(diagnose_expression_constraint): Show the original expression.
	(diagnose_type_constraint): Show the original type.
	(diagnose_implicit_conversion_constraint): Be specific about
	failures, don't re-diagnose a known-to-be-failed substitutions,
	and manage elisions properly.
	(diagnose_argument_deduction_constraint): Same.
	(diagnose_exception_constraint): Same.
	(diagnose_parameterized_constraint): Same.
	(constraint_p): Allow EXPR_PACK_EXPANSION.
	* logic.cc (next_by_distance): Removed. No longer used.
	(any_p): Renamed from any_of.
	(term_entry, term_hasher): New.
	(term_list): Rewrite to include a hash table for quick lookup.
	Also, make less stateful.
	(proof_state): Extend to allow goals to be discharged once
	satisfied.
	(non_atomic_constraint_p): New.
	(any_non_atomic_constraints_p): New.
	(...rest...): Previous implementation completely replaced with an
	iterative algorithm that opportunistically prunes the search space
	before committing to using more memory.
	* parser.c: (cp_parser_type_parameter): Normalize constraints.
	(cp_parser_explicit_template_declaration): Same.
	* pt.c: (finish_template_variable): Be less redundant with this error
	message.
	(template_args_equal): No longer static.
	(tsubst_decl): Don't try to find specializations of variables that
	have already been instantiated.
	(build_non_dependent_expr): Avoid infinite recursion during concept
	expansion.
	(make_constrained_auto): Normalize constraints.
	(do_auto_deduction): When doing auto deduction from a
	partial-concept-id, be sure to include the explicit args checking
	the constraints.
	(constraint_sat_*): New. Memoize satisfied constraints.
	(concept_spec_*): New. Memoize expressions associated with a concept
	specialization.
	(constraint_memos, concept_memos): New.
	(lookup_constraint_satisfaction, memoize_constraint_satisfaction): New.
	(lookup_concept_satisfaction, memoize_concept_satisfaction): New.
	(get_concept_expansion, save_concept_expansion): New.
	(hash_subsumption_args): New.
	(comp_subsumption_args): New.
	(subsumption_*): New. Memoize parts of the subsumption relation.
	(lookup_subsumption_result, save_subsumption_result): New.
	(init_constraint_processing): Initialize memo tables.
	(get_constraints): Shortcut if !flag_concepts.
	* decl.c (grokfndecl): Normalize constraints.
	* error.c (dump_simple_decl): Print "concept" when appropriate.
	(dump_function_decl): Same.
	(dump_template_decl): Don't write requirements when we're not
	printing the header.
	(dump_expr): Handle fold expressions.
	* cxx-pretty-print.c (cxx_pretty_printer::expression): Handle
	fold expressions.
	(get_fold_operator): New.
	(pp_cxx_unary_left_fold_expression): New.
	(pp_cxx_unary_right_fold_expression): New.
	(pp_cxx_binary_fold_expression): New.
	(pp_cxx_check_constraint): New.
	(pp_cxx_*_constraint): Rewrite the grammar of internal constraints
	to make them easier to read when debugging.
	* search.c (accessible_p): Don't shortcut when evaluating constraints.
	* tree.c (cp_tree_equal): Handle CHECK_CONSTR.

Co-Authored-By: Jason Merrill <jason@redhat.com>

From-SVN: r238558
This commit is contained in:
Andrew Sutton 2016-07-21 06:05:24 +00:00 committed by Jason Merrill
parent e17def9a70
commit f078dc7d26
26 changed files with 2406 additions and 1004 deletions

View File

@ -1,3 +1,11 @@
2016-07-21 Andrew Sutton <andrew.n.sutton@gmail.com>
Improving concepts performance and diagnostics.
* timevar.def (TV_CONSTRAINT_SAT, TV_CONSTRAINT_SUB): New time vars
for constraint satisfaction and subsumption.
* timevar.h (auto_timevar): New constructor that matches the push/pop
pattern of usage in pt.c.
2016-07-20 Uros Bizjak <ubizjak@gmail.com> 2016-07-20 Uros Bizjak <ubizjak@gmail.com>
* hwint.h (HOST_WIDE_INT_0): New define. * hwint.h (HOST_WIDE_INT_0): New define.

View File

@ -1,3 +1,141 @@
2016-07-21 Andrew Sutton <andrew.n.sutton@gmail.com>
Jason Merrill <jason@redhat.com>
Improving concepts performance and diagnostics.
PR c++/67565
PR c++/67579
PR c++/71843
* cp-tree.def (CHECK_CONSTR): New.
* cp-tree.h (CHECK_CONSTR_CONCEPT): New.
(CHECK_CONSTR_ARGS): New.
* constraint.cc (make_predicate_constraint): Remove in favor of
normalize_expression.
(resolve_constraint_check): Actually return error_mark_node when
resolution fails.
(resolve_variable_concept_check): Perform coercion as if processing
a template. Also return errors on resolution failure.
(lift_*): Remove all of these functions. Don't unnecessarily inline
concepts.
(learn_*): Add facilities to memoize implications for subsumption
during normalization.
(expanding_concept): New.
(expand_concept): New. Return the inlined and normalized definition
of a concept when needed.
(transform_*, xform_*): Rename to normalize_* to better reflect the
responsibility of those functions.
(normalize_template_id_expression): Check for non-boolean operands
when possible. Generate check constraints instead of normal variable
references.
(normalize_call_expression): Report errors when resolution fails.
(check_for_logical_overloads): Rewrite this check to more accurately
report the error.
(normalize_atom): Check for overloaded calls and invalid types before
determining if the expression refers to a concept.
(build_constraints): Don't cache normalized constraints or decomposed
assumptions.
(finish_shorthand_constraint): Return a normalized expression instead
of a predicate constraint.
(finish_template_introduction): Same.
(placeholder_extract_concept_and_args): Rewrite this since we only
ever get check constraints here.
(equivalent_placeholder_constraints): Rewrite in terms of check
constraints, and handle error_mark_nodes correctly.
(tsubst_check_constraint, tsubst_expr_constr, tsubst_type_constr)
(tsubst_implicit_conversion_constr)
(tsubst_argument_deduction_constr, tsubst_exception_constr)
(tsubst_parameterized_constraint, tsubst_constraint): New.
(tsbust_conjunection): Replace with tsubst_logical_operator and
actually generate the right kind of constraint.
(tsubst_requirement_body): Reverse the order of substituted arguments
so that they appear in the order written (helps diagnostics).
(satisfy_check_constraint): New.
(satisfy_conjunction): Simplify.
(satisfy_disjunction): Same.
(satisfy_constraint_1): Handle check constraints.
(eval_constr): New (private) global state.
(evaluating_constraints_sentinel): New. Manages eval_constr.
(satisfy_constraint): Add timing variables.
(satisfy_associated_constraints): Add hooks for memoization.
(evaluate_function_concept): Build a check constraint instead of
normalizing its definition.
(evaluate_variable_concept): Same.
(evaluate_constraint_expression): Normalize, but in the current
declaration processing context.
(evaluating_constraints_p): New.
(elide_constraint_failure_p): Actually emit constraint_thresh errors.
(diagnose_*): Remove artificial indentation. Add a new parameter to
each that tracks the current (complete) constraint prior to any
substitutions.
(diagnose_expression): Removed.
(diagnose_call_expression): Same.
(diagnose_template_id): Same.
(diagnose_template_id): New.
(diagnose_logical_constraint): New.
(diagnose_expression_constraint): Show the original expression.
(diagnose_type_constraint): Show the original type.
(diagnose_implicit_conversion_constraint): Be specific about
failures, don't re-diagnose a known-to-be-failed substitutions,
and manage elisions properly.
(diagnose_argument_deduction_constraint): Same.
(diagnose_exception_constraint): Same.
(diagnose_parameterized_constraint): Same.
(constraint_p): Allow EXPR_PACK_EXPANSION.
* logic.cc (next_by_distance): Removed. No longer used.
(any_p): Renamed from any_of.
(term_entry, term_hasher): New.
(term_list): Rewrite to include a hash table for quick lookup.
Also, make less stateful.
(proof_state): Extend to allow goals to be discharged once
satisfied.
(non_atomic_constraint_p): New.
(any_non_atomic_constraints_p): New.
(...rest...): Previous implementation completely replaced with an
iterative algorithm that opportunistically prunes the search space
before committing to using more memory.
* parser.c: (cp_parser_type_parameter): Normalize constraints.
(cp_parser_explicit_template_declaration): Same.
* pt.c: (finish_template_variable): Be less redundant with this error
message.
(template_args_equal): No longer static.
(tsubst_decl): Don't try to find specializations of variables that
have already been instantiated.
(build_non_dependent_expr): Avoid infinite recursion during concept
expansion.
(make_constrained_auto): Normalize constraints.
(do_auto_deduction): When doing auto deduction from a
partial-concept-id, be sure to include the explicit args checking
the constraints.
(constraint_sat_*): New. Memoize satisfied constraints.
(concept_spec_*): New. Memoize expressions associated with a concept
specialization.
(constraint_memos, concept_memos): New.
(lookup_constraint_satisfaction, memoize_constraint_satisfaction): New.
(lookup_concept_satisfaction, memoize_concept_satisfaction): New.
(get_concept_expansion, save_concept_expansion): New.
(hash_subsumption_args): New.
(comp_subsumption_args): New.
(subsumption_*): New. Memoize parts of the subsumption relation.
(lookup_subsumption_result, save_subsumption_result): New.
(init_constraint_processing): Initialize memo tables.
(get_constraints): Shortcut if !flag_concepts.
* decl.c (grokfndecl): Normalize constraints.
* error.c (dump_simple_decl): Print "concept" when appropriate.
(dump_function_decl): Same.
(dump_template_decl): Don't write requirements when we're not
printing the header.
(dump_expr): Handle fold expressions.
* cxx-pretty-print.c (cxx_pretty_printer::expression): Handle
fold expressions.
(get_fold_operator): New.
(pp_cxx_unary_left_fold_expression): New.
(pp_cxx_unary_right_fold_expression): New.
(pp_cxx_binary_fold_expression): New.
(pp_cxx_check_constraint): New.
(pp_cxx_*_constraint): Rewrite the grammar of internal constraints
to make them easier to read when debugging.
* search.c (accessible_p): Don't shortcut when evaluating constraints.
* tree.c (cp_tree_equal): Handle CHECK_CONSTR.
2016-07-20 David Malcolm <dmalcolm@redhat.com> 2016-07-20 David Malcolm <dmalcolm@redhat.com>
PR c/70339 PR c/70339

File diff suppressed because it is too large Load Diff

View File

@ -536,6 +536,14 @@ DEFTREECODE (NESTED_REQ, "nested_req", tcc_expression, 1)
PRED_CONSTR_EXPR has the expression to be evaluated. */ PRED_CONSTR_EXPR has the expression to be evaluated. */
DEFTREECODE (PRED_CONSTR, "pred_constr", tcc_expression, 1) DEFTREECODE (PRED_CONSTR, "pred_constr", tcc_expression, 1)
/* A check constraint represents the checking of a concept
C. It has two operands: the template defining the concept
and a sequence of template arguments.
CHECK_CONSTR_CONCEPT has the concept definition
CHECK_CONSTR_ARGUMENTS are the template arguments */
DEFTREECODE (CHECK_CONSTR, "check_constr", tcc_expression, 2)
/* An expression constraint determines the validity of a expression E. /* An expression constraint determines the validity of a expression E.
EXPR_CONST_EXPR has the expression being validated. */ EXPR_CONST_EXPR has the expression being validated. */
@ -560,7 +568,7 @@ DEFTREECODE (ICONV_CONSTR, "iconv_constr", tcc_expression, 2)
T must contain at least one place holder. T must contain at least one place holder.
DEDUCT_CONSTR_EXPR has the expression E DEDUCT_CONSTR_EXPR has the expression E
DEDUCT_CONSTR_PATTERN has the type patter T. DEDUCT_CONSTR_PATTERN has the type pattern T.
DEDUCT_CONSTR_PLACEHOLDERS has the list of placeholder nodes in T. */ DEDUCT_CONSTR_PLACEHOLDERS has the list of placeholder nodes in T. */
DEFTREECODE (DEDUCT_CONSTR, "deduct_constr", tcc_expression, 3) DEFTREECODE (DEDUCT_CONSTR, "deduct_constr", tcc_expression, 3)

View File

@ -893,10 +893,6 @@ struct GTY(()) tree_template_info {
// - a constraint expression introduced by a function declarator // - a constraint expression introduced by a function declarator
// - the associated constraints, which are the conjunction of those, // - the associated constraints, which are the conjunction of those,
// and used for declaration matching // and used for declaration matching
// - the cached normalized associated constraints which are used
// to support satisfaction and subsumption.
// - assumptions which is the result of decomposing the normalized
// constraints.
// //
// The template and declarator requirements are kept to support pretty // The template and declarator requirements are kept to support pretty
// printing constrained declarations. // printing constrained declarations.
@ -905,8 +901,6 @@ struct GTY(()) tree_constraint_info {
tree template_reqs; tree template_reqs;
tree declarator_reqs; tree declarator_reqs;
tree associated_constr; tree associated_constr;
tree normalized_constr;
tree assumptions;
}; };
// Require that pointer P is non-null before returning. // Require that pointer P is non-null before returning.
@ -945,14 +939,6 @@ check_constraint_info (tree t)
#define CI_ASSOCIATED_CONSTRAINTS(NODE) \ #define CI_ASSOCIATED_CONSTRAINTS(NODE) \
check_constraint_info (check_nonnull(NODE))->associated_constr check_constraint_info (check_nonnull(NODE))->associated_constr
// The normalized associated constraints.
#define CI_NORMALIZED_CONSTRAINTS(NODE) \
check_constraint_info (check_nonnull(NODE))->normalized_constr
// Get the set of assumptions associated with the constraint info node.
#define CI_ASSUMPTIONS(NODE) \
check_constraint_info (check_nonnull(NODE))->assumptions
// Access the logical constraints on the template parameters introduced // Access the logical constraints on the template parameters introduced
// at a given template parameter list level indicated by NODE. // at a given template parameter list level indicated by NODE.
#define TEMPLATE_PARMS_CONSTRAINTS(NODE) \ #define TEMPLATE_PARMS_CONSTRAINTS(NODE) \
@ -976,6 +962,14 @@ check_constraint_info (tree t)
#define PRED_CONSTR_EXPR(NODE) \ #define PRED_CONSTR_EXPR(NODE) \
TREE_OPERAND (TREE_CHECK (NODE, PRED_CONSTR), 0) TREE_OPERAND (TREE_CHECK (NODE, PRED_CONSTR), 0)
/* The concept of a concept check. */
#define CHECK_CONSTR_CONCEPT(NODE) \
TREE_OPERAND (TREE_CHECK (NODE, CHECK_CONSTR), 0)
/* The template arguments of a concept check. */
#define CHECK_CONSTR_ARGS(NODE) \
TREE_OPERAND (TREE_CHECK (NODE, CHECK_CONSTR), 1)
/* The expression validated by the predicate constraint. */ /* The expression validated by the predicate constraint. */
#define EXPR_CONSTR_EXPR(NODE) \ #define EXPR_CONSTR_EXPR(NODE) \
TREE_OPERAND (TREE_CHECK (NODE, EXPR_CONSTR), 0) TREE_OPERAND (TREE_CHECK (NODE, EXPR_CONSTR), 0)
@ -6118,6 +6112,7 @@ extern bool is_specialization_of_friend (tree, tree);
extern tree get_pattern_parm (tree, tree); extern tree get_pattern_parm (tree, tree);
extern int comp_template_args (tree, tree, tree * = NULL, extern int comp_template_args (tree, tree, tree * = NULL,
tree * = NULL); tree * = NULL);
extern int template_args_equal (tree, tree);
extern tree maybe_process_partial_specialization (tree); extern tree maybe_process_partial_specialization (tree);
extern tree most_specialized_instantiation (tree); extern tree most_specialized_instantiation (tree);
extern void print_candidates (tree); extern void print_candidates (tree);
@ -6848,10 +6843,8 @@ extern tree strip_using_decl (tree);
/* in constraint.cc */ /* in constraint.cc */
extern void init_constraint_processing (); extern void init_constraint_processing ();
extern bool constraint_p (tree); extern bool constraint_p (tree);
extern tree make_predicate_constraint (tree);
extern tree conjoin_constraints (tree, tree); extern tree conjoin_constraints (tree, tree);
extern tree conjoin_constraints (tree); extern tree conjoin_constraints (tree);
extern bool valid_constraints_p (tree);
extern tree get_constraints (tree); extern tree get_constraints (tree);
extern void set_constraints (tree, tree); extern void set_constraints (tree, tree);
extern void remove_constraints (tree); extern void remove_constraints (tree);
@ -6882,13 +6875,23 @@ extern tree tsubst_requires_expr (tree, tree, tsubst_flags_t, tre
extern tree tsubst_constraint (tree, tree, tsubst_flags_t, tree); extern tree tsubst_constraint (tree, tree, tsubst_flags_t, tree);
extern tree tsubst_constraint_info (tree, tree, tsubst_flags_t, tree); extern tree tsubst_constraint_info (tree, tree, tsubst_flags_t, tree);
extern bool function_concept_check_p (tree); extern bool function_concept_check_p (tree);
extern tree normalize_expression (tree);
extern tree expand_concept (tree, tree);
extern bool expanding_concept ();
extern tree evaluate_constraints (tree, tree); extern tree evaluate_constraints (tree, tree);
extern tree evaluate_function_concept (tree, tree); extern tree evaluate_function_concept (tree, tree);
extern tree evaluate_variable_concept (tree, tree); extern tree evaluate_variable_concept (tree, tree);
extern tree evaluate_constraint_expression (tree, tree); extern tree evaluate_constraint_expression (tree, tree);
extern bool constraints_satisfied_p (tree); extern bool constraints_satisfied_p (tree);
extern bool constraints_satisfied_p (tree, tree); extern bool constraints_satisfied_p (tree, tree);
extern tree lookup_constraint_satisfaction (tree, tree);
extern tree memoize_constraint_satisfaction (tree, tree, tree);
extern tree lookup_concept_satisfaction (tree, tree);
extern tree memoize_concept_satisfaction (tree, tree, tree);
extern tree get_concept_expansion (tree, tree);
extern tree save_concept_expansion (tree, tree, tree);
extern bool* lookup_subsumption_result (tree, tree);
extern bool save_subsumption_result (tree, tree, bool);
extern bool equivalent_constraints (tree, tree); extern bool equivalent_constraints (tree, tree);
extern bool equivalently_constrained (tree, tree); extern bool equivalently_constrained (tree, tree);
@ -6899,7 +6902,6 @@ extern int more_constrained (tree, tree);
extern void diagnose_constraints (location_t, tree, tree); extern void diagnose_constraints (location_t, tree, tree);
/* in logic.cc */ /* in logic.cc */
extern tree decompose_assumptions (tree);
extern tree decompose_conclusions (tree); extern tree decompose_conclusions (tree);
extern bool subsumes (tree, tree); extern bool subsumes (tree, tree);

View File

@ -35,6 +35,9 @@ static void pp_cxx_parameter_declaration_clause (cxx_pretty_printer *, tree);
static void pp_cxx_template_parameter (cxx_pretty_printer *, tree); static void pp_cxx_template_parameter (cxx_pretty_printer *, tree);
static void pp_cxx_cast_expression (cxx_pretty_printer *, tree); static void pp_cxx_cast_expression (cxx_pretty_printer *, tree);
static void pp_cxx_typeid_expression (cxx_pretty_printer *, tree); static void pp_cxx_typeid_expression (cxx_pretty_printer *, tree);
static void pp_cxx_unary_left_fold_expression (cxx_pretty_printer *, tree);
static void pp_cxx_unary_right_fold_expression (cxx_pretty_printer *, tree);
static void pp_cxx_binary_fold_expression (cxx_pretty_printer *, tree);
static inline void static inline void
@ -1139,6 +1142,19 @@ cxx_pretty_printer::expression (tree t)
pp_cxx_ws_string (this, "..."); pp_cxx_ws_string (this, "...");
break; break;
case UNARY_LEFT_FOLD_EXPR:
pp_cxx_unary_left_fold_expression (this, t);
break;
case UNARY_RIGHT_FOLD_EXPR:
pp_cxx_unary_right_fold_expression (this, t);
break;
case BINARY_LEFT_FOLD_EXPR:
case BINARY_RIGHT_FOLD_EXPR:
pp_cxx_binary_fold_expression (this, t);
break;
case TEMPLATE_ID_EXPR: case TEMPLATE_ID_EXPR:
pp_cxx_template_id (this, t); pp_cxx_template_id (this, t);
break; break;
@ -1165,6 +1181,7 @@ cxx_pretty_printer::expression (tree t)
break; break;
case PRED_CONSTR: case PRED_CONSTR:
case CHECK_CONSTR:
case EXPR_CONSTR: case EXPR_CONSTR:
case TYPE_CONSTR: case TYPE_CONSTR:
case ICONV_CONSTR: case ICONV_CONSTR:
@ -2198,6 +2215,11 @@ void
pp_cxx_constrained_type_spec (cxx_pretty_printer *pp, tree c) pp_cxx_constrained_type_spec (cxx_pretty_printer *pp, tree c)
{ {
tree t, a; tree t, a;
if (c == error_mark_node)
{
pp_cxx_ws_string(pp, "<unsatisfied-constrained-placeholder>");
return;
}
placeholder_extract_concept_and_args (c, t, a); placeholder_extract_concept_and_args (c, t, a);
pp->id_expression (t); pp->id_expression (t);
if (TREE_VEC_LENGTH (a) > 1) if (TREE_VEC_LENGTH (a) > 1)
@ -2407,6 +2429,102 @@ pp_cxx_offsetof_expression (cxx_pretty_printer *pp, tree t)
pp_cxx_right_paren (pp); pp_cxx_right_paren (pp);
} }
static char const*
get_fold_operator (tree t)
{
int op = int_cst_value (FOLD_EXPR_OP (t));
if (FOLD_EXPR_MODIFY_P (t))
{
switch (op)
{
case NOP_EXPR: return "=";
case PLUS_EXPR: return "+=";
case MINUS_EXPR: return "-=";
case MULT_EXPR: return "*=";
case TRUNC_DIV_EXPR: return "/=";
case TRUNC_MOD_EXPR: return "%=";
case BIT_XOR_EXPR: return "^=";
case BIT_AND_EXPR: return "&=";
case BIT_IOR_EXPR: return "|=";
case LSHIFT_EXPR: return "<<=";
case RSHIFT_EXPR: return ">>=";
default: gcc_unreachable ();
}
}
else
{
switch (op)
{
case PLUS_EXPR: return "+";
case MINUS_EXPR: return "-";
case MULT_EXPR: return "*";
case TRUNC_DIV_EXPR: return "/";
case TRUNC_MOD_EXPR: return "%";
case BIT_XOR_EXPR: return "^";
case BIT_AND_EXPR: return "&";
case BIT_IOR_EXPR: return "|";
case LSHIFT_EXPR: return "<<";
case RSHIFT_EXPR: return ">>";
case EQ_EXPR: return "==";
case NE_EXPR: return "!=";
case LT_EXPR: return "<";
case GT_EXPR: return ">";
case LE_EXPR: return "<=";
case GE_EXPR: return ">=";
case TRUTH_ANDIF_EXPR: return "&&";
case TRUTH_ORIF_EXPR: return "||";
case MEMBER_REF: return "->*";
case DOTSTAR_EXPR: return ".*";
case OFFSET_REF: return ".*";
default: return ","; /* FIXME: Not the right default. */
}
}
}
void
pp_cxx_unary_left_fold_expression (cxx_pretty_printer *pp, tree t)
{
char const* op = get_fold_operator (t);
tree expr = PACK_EXPANSION_PATTERN (FOLD_EXPR_PACK (t));
pp_cxx_left_paren (pp);
pp_cxx_ws_string (pp, "...");
pp_cxx_ws_string (pp, op);
pp->expression (expr);
pp_cxx_right_paren (pp);
}
void
pp_cxx_unary_right_fold_expression (cxx_pretty_printer *pp, tree t)
{
char const* op = get_fold_operator (t);
tree expr = PACK_EXPANSION_PATTERN (FOLD_EXPR_PACK (t));
pp_cxx_left_paren (pp);
pp->expression (expr);
pp_space (pp);
pp_cxx_ws_string (pp, op);
pp_cxx_ws_string (pp, "...");
pp_cxx_right_paren (pp);
}
void
pp_cxx_binary_fold_expression (cxx_pretty_printer *pp, tree t)
{
char const* op = get_fold_operator (t);
tree t1 = TREE_OPERAND (t, 1);
tree t2 = TREE_OPERAND (t, 2);
if (t1 == FOLD_EXPR_PACK (t))
t1 = PACK_EXPANSION_PATTERN (t1);
else
t2 = PACK_EXPANSION_PATTERN (t2);
pp_cxx_left_paren (pp);
pp->expression (t1);
pp_cxx_ws_string (pp, op);
pp_cxx_ws_string (pp, "...");
pp_cxx_ws_string (pp, op);
pp->expression (t2);
pp_cxx_right_paren (pp);
}
void void
pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
{ {
@ -2617,6 +2735,7 @@ pp_cxx_compound_requirement (cxx_pretty_printer *pp, tree t)
pp_cxx_ws_string (pp, "->"); pp_cxx_ws_string (pp, "->");
pp->type_id (type); pp->type_id (type);
} }
pp_cxx_semicolon (pp);
} }
/* nested requirement: /* nested requirement:
@ -2632,74 +2751,94 @@ pp_cxx_nested_requirement (cxx_pretty_printer *pp, tree t)
void void
pp_cxx_predicate_constraint (cxx_pretty_printer *pp, tree t) pp_cxx_predicate_constraint (cxx_pretty_printer *pp, tree t)
{ {
pp_string (pp, "predicate");
pp_left_paren (pp);
pp->expression (TREE_OPERAND (t, 0)); pp->expression (TREE_OPERAND (t, 0));
pp_right_paren (pp); }
void
pp_cxx_check_constraint (cxx_pretty_printer *pp, tree t)
{
tree decl = CHECK_CONSTR_CONCEPT (t);
tree tmpl = DECL_TI_TEMPLATE (decl);
tree args = CHECK_CONSTR_ARGS (t);
tree id = build_nt (TEMPLATE_ID_EXPR, tmpl, args);
if (TREE_CODE (decl) == VAR_DECL)
pp->expression (id);
else if (TREE_CODE (decl) == FUNCTION_DECL)
{
tree call = build_vl_exp (CALL_EXPR, 2);
TREE_OPERAND (call, 0) = integer_two_node;
TREE_OPERAND (call, 1) = id;
pp->expression (call);
}
else
gcc_unreachable ();
} }
void void
pp_cxx_expression_constraint (cxx_pretty_printer *pp, tree t) pp_cxx_expression_constraint (cxx_pretty_printer *pp, tree t)
{ {
pp_string (pp, "valid_expr"); pp_string (pp, "<valid-expression ");
pp_left_paren (pp); pp_cxx_left_paren (pp);
pp->expression (TREE_OPERAND (t, 0)); pp->expression (TREE_OPERAND (t, 0));
pp_right_paren (pp); pp_cxx_right_paren (pp);
pp_string (pp, ">");
} }
void void
pp_cxx_type_constraint (cxx_pretty_printer *pp, tree t) pp_cxx_type_constraint (cxx_pretty_printer *pp, tree t)
{ {
pp_string (pp, "valid_type"); pp_string (pp, "<valid-type ");
pp_left_paren (pp);
pp->type_id (TREE_OPERAND (t, 0)); pp->type_id (TREE_OPERAND (t, 0));
pp_right_paren (pp); pp_string (pp, ">");
} }
void void
pp_cxx_implicit_conversion_constraint (cxx_pretty_printer *pp, tree t) pp_cxx_implicit_conversion_constraint (cxx_pretty_printer *pp, tree t)
{ {
pp_string (pp, "convertible"); pp_string (pp, "<implicitly-conversion ");
pp_left_paren (pp); pp_cxx_left_paren (pp);
pp->expression (ICONV_CONSTR_EXPR (t)); pp->expression (ICONV_CONSTR_EXPR (t));
pp_cxx_separate_with (pp, ','); pp_cxx_right_paren (pp);
pp->expression (ICONV_CONSTR_TYPE (t)); pp_cxx_ws_string (pp, "to");
pp_right_paren (pp); pp->type_id (ICONV_CONSTR_TYPE (t));
pp_string (pp, ">");
} }
void void
pp_cxx_argument_deduction_constraint (cxx_pretty_printer *pp, tree t) pp_cxx_argument_deduction_constraint (cxx_pretty_printer *pp, tree t)
{ {
pp_string (pp, "deducible"); pp_string (pp, "<argument-deduction ");
pp_left_paren (pp); pp_cxx_left_paren (pp);
pp->expression (DEDUCT_CONSTR_EXPR (t)); pp->expression (DEDUCT_CONSTR_EXPR (t));
pp_cxx_separate_with (pp, ','); pp_cxx_right_paren (pp);
pp_cxx_ws_string (pp, "as");
pp->expression (DEDUCT_CONSTR_PATTERN (t)); pp->expression (DEDUCT_CONSTR_PATTERN (t));
pp_right_paren (pp); pp_string (pp, ">");
} }
void void
pp_cxx_exception_constraint (cxx_pretty_printer *pp, tree t) pp_cxx_exception_constraint (cxx_pretty_printer *pp, tree t)
{ {
pp_cxx_ws_string (pp, "noexcept"); pp_cxx_ws_string (pp, "noexcept");
pp_left_paren (pp); pp_cxx_whitespace (pp);
pp_cxx_left_paren (pp);
pp->expression (TREE_OPERAND (t, 0)); pp->expression (TREE_OPERAND (t, 0));
pp_right_paren (pp); pp_cxx_right_paren (pp);
} }
void void
pp_cxx_parameterized_constraint (cxx_pretty_printer *pp, tree t) pp_cxx_parameterized_constraint (cxx_pretty_printer *pp, tree t)
{ {
pp_left_paren (pp); pp_left_paren (pp);
pp_string (pp, "forall"); pp_string (pp, "<requires ");
if (tree parms = PARM_CONSTR_PARMS (t)) if (tree parms = PARM_CONSTR_PARMS (t))
{ {
if (parms)
pp_cxx_parameter_declaration_clause (pp, parms); pp_cxx_parameter_declaration_clause (pp, parms);
pp_cxx_whitespace (pp); pp_cxx_whitespace (pp);
} }
pp_cxx_constraint (pp, PARM_CONSTR_OPERAND (t)); pp_cxx_constraint (pp, PARM_CONSTR_OPERAND (t));
pp_right_paren (pp); pp_string (pp, ">");
} }
void void
@ -2730,6 +2869,10 @@ pp_cxx_constraint (cxx_pretty_printer *pp, tree t)
pp_cxx_predicate_constraint (pp, t); pp_cxx_predicate_constraint (pp, t);
break; break;
case CHECK_CONSTR:
pp_cxx_check_constraint (pp, t);
break;
case EXPR_CONSTR: case EXPR_CONSTR:
pp_cxx_expression_constraint (pp, t); pp_cxx_expression_constraint (pp, t);
break; break;
@ -2762,6 +2905,10 @@ pp_cxx_constraint (cxx_pretty_printer *pp, tree t)
pp_cxx_disjunction (pp, t); pp_cxx_disjunction (pp, t);
break; break;
case EXPR_PACK_EXPANSION:
pp->expression (TREE_OPERAND (t, 0));
break;
default: default:
gcc_unreachable (); gcc_unreachable ();
} }

View File

@ -7921,7 +7921,7 @@ grokfndecl (tree ctype,
/* Adjust the required expression into a constraint. */ /* Adjust the required expression into a constraint. */
if (decl_reqs) if (decl_reqs)
decl_reqs = make_predicate_constraint (decl_reqs); decl_reqs = normalize_expression (decl_reqs);
tree ci = build_constraints (tmpl_reqs, decl_reqs); tree ci = build_constraints (tmpl_reqs, decl_reqs);
set_constraints (decl, ci); set_constraints (decl, ci);

View File

@ -961,7 +961,12 @@ dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags)
{ {
if (VAR_P (t) if (VAR_P (t)
&& DECL_DECLARED_CONSTEXPR_P (t)) && DECL_DECLARED_CONSTEXPR_P (t))
pp_cxx_ws_string (pp, "constexpr"); {
if (DECL_DECLARED_CONCEPT_P (t))
pp_cxx_ws_string (pp, "concept");
else
pp_cxx_ws_string (pp, "constexpr");
}
dump_type_prefix (pp, type, flags & ~TFF_UNQUALIFIED_NAME); dump_type_prefix (pp, type, flags & ~TFF_UNQUALIFIED_NAME);
pp_maybe_space (pp); pp_maybe_space (pp);
} }
@ -1334,16 +1339,19 @@ dump_template_decl (cxx_pretty_printer *pp, tree t, int flags)
if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (t))) if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (t)))
pp_cxx_ws_string (pp, "..."); pp_cxx_ws_string (pp, "...");
} }
/* Only print the requirements if we're also printing
the template header. */
if (flag_concepts)
if (tree ci = get_constraints (t))
if (check_constraint_info (ci))
if (tree reqs = CI_TEMPLATE_REQS (ci))
{
pp_cxx_requires_clause (pp, reqs);
pp_cxx_whitespace (pp);
}
} }
if (flag_concepts)
if (tree ci = get_constraints (t))
if (check_constraint_info (ci))
if (tree reqs = CI_TEMPLATE_REQS (ci))
{
pp_cxx_requires_clause (pp, reqs);
pp_cxx_whitespace (pp);
}
if (DECL_CLASS_TEMPLATE_P (t)) if (DECL_CLASS_TEMPLATE_P (t))
dump_type (pp, TREE_TYPE (t), dump_type (pp, TREE_TYPE (t),
@ -1534,7 +1542,12 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
pp_cxx_ws_string (pp, "virtual"); pp_cxx_ws_string (pp, "virtual");
if (constexpr_p) if (constexpr_p)
pp_cxx_ws_string (pp, "constexpr"); {
if (DECL_DECLARED_CONCEPT_P (t))
pp_cxx_ws_string (pp, "concept");
else
pp_cxx_ws_string (pp, "constexpr");
}
} }
/* Print the return type? */ /* Print the return type? */
@ -2665,6 +2678,10 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
break; break;
case EXPR_PACK_EXPANSION: case EXPR_PACK_EXPANSION:
case UNARY_LEFT_FOLD_EXPR:
case UNARY_RIGHT_FOLD_EXPR:
case BINARY_LEFT_FOLD_EXPR:
case BINARY_RIGHT_FOLD_EXPR:
case TYPEID_EXPR: case TYPEID_EXPR:
case MEMBER_REF: case MEMBER_REF:
case DOTSTAR_EXPR: case DOTSTAR_EXPR:
@ -2737,6 +2754,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
break; break;
case PRED_CONSTR: case PRED_CONSTR:
case CHECK_CONSTR:
case EXPR_CONSTR: case EXPR_CONSTR:
case TYPE_CONSTR: case TYPE_CONSTR:
case ICONV_CONSTR: case ICONV_CONSTR:

File diff suppressed because it is too large Load Diff

View File

@ -14728,10 +14728,13 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
cp_parser_require (parser, CPP_GREATER, RT_GREATER); cp_parser_require (parser, CPP_GREATER, RT_GREATER);
// If template requirements are present, parse them. // If template requirements are present, parse them.
tree reqs = get_shorthand_constraints (current_template_parms); if (flag_concepts)
if (tree r = cp_parser_requires_clause_opt (parser)) {
reqs = conjoin_constraints (reqs, make_predicate_constraint (r)); tree reqs = get_shorthand_constraints (current_template_parms);
TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs; if (tree r = cp_parser_requires_clause_opt (parser))
reqs = conjoin_constraints (reqs, normalize_expression (r));
TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
}
/* Look for the `class' or 'typename' keywords. */ /* Look for the `class' or 'typename' keywords. */
cp_parser_type_parameter_key (parser); cp_parser_type_parameter_key (parser);
@ -25754,10 +25757,13 @@ cp_parser_explicit_template_declaration (cp_parser* parser, bool member_p)
cp_parser_skip_to_end_of_template_parameter_list (parser); cp_parser_skip_to_end_of_template_parameter_list (parser);
/* Manage template requirements */ /* Manage template requirements */
tree reqs = get_shorthand_constraints (current_template_parms); if (flag_concepts)
if (tree r = cp_parser_requires_clause_opt (parser)) {
reqs = conjoin_constraints (reqs, make_predicate_constraint (r)); tree reqs = get_shorthand_constraints (current_template_parms);
TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs; if (tree r = cp_parser_requires_clause_opt (parser))
reqs = conjoin_constraints (reqs, normalize_expression (r));
TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
}
cp_parser_template_declaration_after_parameters (parser, parameter_list, cp_parser_template_declaration_after_parameters (parser, parameter_list,
member_p); member_p);
@ -37916,7 +37922,13 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr)
implicit template scope, and we're trying to synthesize a implicit template scope, and we're trying to synthesize a
constrained parameter, try to find a previous parameter with constrained parameter, try to find a previous parameter with
the same name. This is the same-type rule for abbreviated the same name. This is the same-type rule for abbreviated
function templates. */ function templates.
NOTE: We can generate implicit parameters when tentatively
parsing a nested name specifier, only to reject that parse
later. However, matching the same template-id as part of a
direct-declarator should generate an identical template
parameter, so this rule will merge them. */
if (parser->implicit_template_scope && constr) if (parser->implicit_template_scope && constr)
{ {
tree t = parser->implicit_template_parms; tree t = parser->implicit_template_parms;

View File

@ -195,7 +195,6 @@ static tree try_class_unification (tree, tree, tree, tree, bool);
static int coerce_template_template_parms (tree, tree, tsubst_flags_t, static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
tree, tree); tree, tree);
static bool template_template_parm_bindings_ok_p (tree, tree); static bool template_template_parm_bindings_ok_p (tree, tree);
static int template_args_equal (tree, tree);
static void tsubst_default_arguments (tree, tsubst_flags_t); static void tsubst_default_arguments (tree, tsubst_flags_t);
static tree for_each_template_parm_r (tree *, int *, void *); static tree for_each_template_parm_r (tree *, int *, void *);
static tree copy_default_args_to_explicit_spec_1 (tree, tree); static tree copy_default_args_to_explicit_spec_1 (tree, tree);
@ -7855,7 +7854,7 @@ coerce_innermost_template_parms (tree parms,
/* Returns 1 if template args OT and NT are equivalent. */ /* Returns 1 if template args OT and NT are equivalent. */
static int int
template_args_equal (tree ot, tree nt) template_args_equal (tree ot, tree nt)
{ {
if (nt == ot) if (nt == ot)
@ -8702,7 +8701,7 @@ finish_template_variable (tree var, tsubst_flags_t complain)
{ {
if (complain & tf_error) if (complain & tf_error)
{ {
error ("constraints for %qD not satisfied", templ); error ("use of invalid variable template %qE", var);
diagnose_constraints (location_of (var), templ, arglist); diagnose_constraints (location_of (var), templ, arglist);
} }
return error_mark_node; return error_mark_node;
@ -9058,7 +9057,7 @@ uses_outer_template_parms (tree decl)
return true; return true;
tree ci = get_constraints (decl); tree ci = get_constraints (decl);
if (ci) if (ci)
ci = CI_NORMALIZED_CONSTRAINTS (ci); ci = CI_ASSOCIATED_CONSTRAINTS (ci);
if (ci && for_each_template_parm (ci, template_parm_outer_level, if (ci && for_each_template_parm (ci, template_parm_outer_level,
&depth, NULL, /*nondeduced*/true)) &depth, NULL, /*nondeduced*/true))
return true; return true;
@ -23764,7 +23763,10 @@ build_non_dependent_expr (tree expr)
&& cxx_dialect >= cxx11 && cxx_dialect >= cxx11
/* Don't do this during nsdmi parsing as it can lead to /* Don't do this during nsdmi parsing as it can lead to
unexpected recursive instantiations. */ unexpected recursive instantiations. */
&& !parsing_nsdmi ()) && !parsing_nsdmi ()
/* Don't do this during concept expansion either and for
the same reason. */
&& !expanding_concept ())
fold_non_dependent_expr (expr); fold_non_dependent_expr (expr);
/* Preserve OVERLOADs; the functions must be available to resolve /* Preserve OVERLOADs; the functions must be available to resolve
@ -23902,7 +23904,7 @@ make_constrained_auto (tree con, tree args)
else else
expr = build_concept_check (build_overload (tmpl, NULL_TREE), type, args); expr = build_concept_check (build_overload (tmpl, NULL_TREE), type, args);
tree constr = make_predicate_constraint (expr); tree constr = normalize_expression (expr);
PLACEHOLDER_TYPE_CONSTRAINTS (type) = constr; PLACEHOLDER_TYPE_CONSTRAINTS (type) = constr;
/* Our canonical type depends on the constraint. */ /* Our canonical type depends on the constraint. */
@ -24054,7 +24056,10 @@ do_auto_deduction (tree type, tree init, tree auto_node)
/* Replace occurrences of 'auto' in TYPE with the appropriate type deduced /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
from INIT. AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE. from INIT. AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE.
The CONTEXT determines the context in which auto deduction is performed The CONTEXT determines the context in which auto deduction is performed
and is used to control error diagnostics. */ and is used to control error diagnostics.
For partial-concept-ids, extra args may be appended to the list of deduced
template arguments prior to determining constraint satisfaction. */
tree tree
do_auto_deduction (tree type, tree init, tree auto_node, do_auto_deduction (tree type, tree init, tree auto_node,
@ -24161,8 +24166,19 @@ do_auto_deduction (tree type, tree init, tree auto_node,
if (flag_concepts && !processing_template_decl) if (flag_concepts && !processing_template_decl)
if (tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (auto_node)) if (tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (auto_node))
{ {
/* Use the deduced type to check the associated constraints. */ /* Use the deduced type to check the associated constraints. If we
if (!constraints_satisfied_p (constr, targs)) have a partial-concept-id, rebuild the argument list so that
we check using the extra arguments. */
gcc_assert (TREE_CODE (constr) == CHECK_CONSTR);
tree cargs = CHECK_CONSTR_ARGS (constr);
if (TREE_VEC_LENGTH (cargs) > 1)
{
cargs = copy_node (cargs);
TREE_VEC_ELT (cargs, 0) = TREE_VEC_ELT (targs, 0);
}
else
cargs = targs;
if (!constraints_satisfied_p (constr, cargs))
{ {
if (complain & tf_warning_or_error) if (complain & tf_warning_or_error)
{ {
@ -24482,24 +24498,15 @@ struct constr_hasher : ggc_ptr_hash<constr_entry>
static GTY (()) hash_table<constr_hasher> *decl_constraints; static GTY (()) hash_table<constr_hasher> *decl_constraints;
/* Returns true iff cinfo contains a valid set of constraints.
This is the case when the associated requirements have been
successfully decomposed into lists of atomic constraints.
That is, when the saved assumptions are not error_mark_node. */
bool
valid_constraints_p (tree cinfo)
{
gcc_assert (cinfo);
return CI_ASSUMPTIONS (cinfo) != error_mark_node;
}
/* Returns the template constraints of declaration T. If T is not /* Returns the template constraints of declaration T. If T is not
constrained, return NULL_TREE. Note that T must be non-null. */ constrained, return NULL_TREE. Note that T must be non-null. */
tree tree
get_constraints (tree t) get_constraints (tree t)
{ {
if (!flag_concepts)
return NULL_TREE;
gcc_assert (DECL_P (t)); gcc_assert (DECL_P (t));
if (TREE_CODE (t) == TEMPLATE_DECL) if (TREE_CODE (t) == TEMPLATE_DECL)
t = DECL_TEMPLATE_RESULT (t); t = DECL_TEMPLATE_RESULT (t);
@ -24521,7 +24528,7 @@ set_constraints (tree t, tree ci)
{ {
if (!ci) if (!ci)
return; return;
gcc_assert (t); gcc_assert (t && flag_concepts);
if (TREE_CODE (t) == TEMPLATE_DECL) if (TREE_CODE (t) == TEMPLATE_DECL)
t = DECL_TEMPLATE_RESULT (t); t = DECL_TEMPLATE_RESULT (t);
gcc_assert (!get_constraints (t)); gcc_assert (!get_constraints (t));
@ -24547,12 +24554,244 @@ remove_constraints (tree t)
decl_constraints->clear_slot (slot); decl_constraints->clear_slot (slot);
} }
/* Memoized satisfaction results for declarations. This
maps the pair (constraint_info, arguments) to the result computed
by constraints_satisfied_p. */
struct GTY((for_user)) constraint_sat_entry
{
tree ci;
tree args;
tree result;
};
/* Hashing function and equality for constraint entries. */
struct constraint_sat_hasher : ggc_ptr_hash<constraint_sat_entry>
{
static hashval_t hash (constraint_sat_entry *e)
{
hashval_t val = iterative_hash_object(e->ci, 0);
return iterative_hash_template_arg (e->args, val);
}
static bool equal (constraint_sat_entry *e1, constraint_sat_entry *e2)
{
return e1->ci == e2->ci && comp_template_args (e1->args, e2->args);
}
};
/* Memoized satisfaction results for concept checks. */
struct GTY((for_user)) concept_spec_entry
{
tree tmpl;
tree args;
tree result;
};
/* Hashing function and equality for constraint entries. */
struct concept_spec_hasher : ggc_ptr_hash<concept_spec_entry>
{
static hashval_t hash (concept_spec_entry *e)
{
return hash_tmpl_and_args (e->tmpl, e->args);
}
static bool equal (concept_spec_entry *e1, concept_spec_entry *e2)
{
++comparing_specializations;
bool eq = e1->tmpl == e2->tmpl && comp_template_args (e1->args, e2->args);
--comparing_specializations;
return eq;
}
};
static GTY (()) hash_table<constraint_sat_hasher> *constraint_memos;
static GTY (()) hash_table<concept_spec_hasher> *concept_memos;
/* Search for a memoized satisfaction result. Returns one of the
truth value nodes if previously memoized, or NULL_TREE otherwise. */
tree
lookup_constraint_satisfaction (tree ci, tree args)
{
constraint_sat_entry elt = { ci, args, NULL_TREE };
constraint_sat_entry* found = constraint_memos->find (&elt);
if (found)
return found->result;
else
return NULL_TREE;
}
/* Memoize the result of a satisfication test. Returns the saved result. */
tree
memoize_constraint_satisfaction (tree ci, tree args, tree result)
{
constraint_sat_entry elt = {ci, args, result};
constraint_sat_entry** slot = constraint_memos->find_slot (&elt, INSERT);
constraint_sat_entry* entry = ggc_alloc<constraint_sat_entry> ();
*entry = elt;
*slot = entry;
return result;
}
/* Search for a memoized satisfaction result for a concept. */
tree
lookup_concept_satisfaction (tree tmpl, tree args)
{
concept_spec_entry elt = { tmpl, args, NULL_TREE };
concept_spec_entry* found = concept_memos->find (&elt);
if (found)
return found->result;
else
return NULL_TREE;
}
/* Memoize the result of a concept check. Returns the saved result. */
tree
memoize_concept_satisfaction (tree tmpl, tree args, tree result)
{
concept_spec_entry elt = {tmpl, args, result};
concept_spec_entry** slot = concept_memos->find_slot (&elt, INSERT);
concept_spec_entry* entry = ggc_alloc<concept_spec_entry> ();
*entry = elt;
*slot = entry;
return result;
}
static GTY (()) hash_table<concept_spec_hasher> *concept_expansions;
/* Returns a prior concept specialization. This returns the substituted
and normalized constraints defined by the concept. */
tree
get_concept_expansion (tree tmpl, tree args)
{
concept_spec_entry elt = { tmpl, args, NULL_TREE };
concept_spec_entry* found = concept_expansions->find (&elt);
if (found)
return found->result;
else
return NULL_TREE;
}
/* Save a concept expansion for later. */
tree
save_concept_expansion (tree tmpl, tree args, tree def)
{
concept_spec_entry elt = {tmpl, args, def};
concept_spec_entry** slot = concept_expansions->find_slot (&elt, INSERT);
concept_spec_entry* entry = ggc_alloc<concept_spec_entry> ();
*entry = elt;
*slot = entry;
return def;
}
static hashval_t
hash_subsumption_args (tree t1, tree t2)
{
gcc_assert (TREE_CODE (t1) == CHECK_CONSTR);
gcc_assert (TREE_CODE (t2) == CHECK_CONSTR);
int val = 0;
val = iterative_hash_object (CHECK_CONSTR_CONCEPT (t1), val);
val = iterative_hash_template_arg (CHECK_CONSTR_ARGS (t1), val);
val = iterative_hash_object (CHECK_CONSTR_CONCEPT (t2), val);
val = iterative_hash_template_arg (CHECK_CONSTR_ARGS (t2), val);
return val;
}
/* Compare the constraints of two subsumption entries. The LEFT1 and
LEFT2 arguments comprise the first subsumption pair and the RIGHT1
and RIGHT2 arguments comprise the second. These are all CHECK_CONSTRs. */
static bool
comp_subsumption_args (tree left1, tree left2, tree right1, tree right2)
{
if (CHECK_CONSTR_CONCEPT (left1) == CHECK_CONSTR_CONCEPT (right1))
if (CHECK_CONSTR_CONCEPT (left2) == CHECK_CONSTR_CONCEPT (right2))
if (comp_template_args (CHECK_CONSTR_ARGS (left1),
CHECK_CONSTR_ARGS (right1)))
return comp_template_args (CHECK_CONSTR_ARGS (left2),
CHECK_CONSTR_ARGS (right2));
return false;
}
/* Key/value pair for learning and memoizing subsumption results. This
associates a pair of check constraints (including arguments) with
a boolean value indicating the result. */
struct GTY((for_user)) subsumption_entry
{
tree t1;
tree t2;
bool result;
};
/* Hashing function and equality for constraint entries. */
struct subsumption_hasher : ggc_ptr_hash<subsumption_entry>
{
static hashval_t hash (subsumption_entry *e)
{
return hash_subsumption_args (e->t1, e->t2);
}
static bool equal (subsumption_entry *e1, subsumption_entry *e2)
{
++comparing_specializations;
bool eq = comp_subsumption_args(e1->t1, e1->t2, e2->t1, e2->t2);
--comparing_specializations;
return eq;
}
};
static GTY (()) hash_table<subsumption_hasher> *subsumption_table;
/* Search for a previously cached subsumption result. */
bool*
lookup_subsumption_result (tree t1, tree t2)
{
subsumption_entry elt = { t1, t2, false };
subsumption_entry* found = subsumption_table->find (&elt);
if (found)
return &found->result;
else
return 0;
}
/* Save a subsumption result. */
bool
save_subsumption_result (tree t1, tree t2, bool result)
{
subsumption_entry elt = {t1, t2, result};
subsumption_entry** slot = subsumption_table->find_slot (&elt, INSERT);
subsumption_entry* entry = ggc_alloc<subsumption_entry> ();
*entry = elt;
*slot = entry;
return result;
}
/* Set up the hash table for constraint association. */ /* Set up the hash table for constraint association. */
void void
init_constraint_processing (void) init_constraint_processing (void)
{ {
if (!flag_concepts)
return;
decl_constraints = hash_table<constr_hasher>::create_ggc(37); decl_constraints = hash_table<constr_hasher>::create_ggc(37);
constraint_memos = hash_table<constraint_sat_hasher>::create_ggc(37);
concept_memos = hash_table<concept_spec_hasher>::create_ggc(37);
concept_expansions = hash_table<concept_spec_hasher>::create_ggc(37);
subsumption_table = hash_table<subsumption_hasher>::create_ggc(37);
} }
/* Set up the hash tables for template instantiations. */ /* Set up the hash tables for template instantiations. */

View File

@ -260,7 +260,6 @@ cxx_print_xnode (FILE *file, tree node, int indent)
indent+4); indent+4);
print_node (file, "associated_constr", print_node (file, "associated_constr",
cinfo->associated_constr, indent+4); cinfo->associated_constr, indent+4);
print_node_brief (file, "assumptions", cinfo->assumptions, indent+4);
break; break;
} }
case ARGUMENT_PACK_SELECT: case ARGUMENT_PACK_SELECT:

View File

@ -947,6 +947,7 @@ accessible_p (tree type, tree decl, bool consider_local_p)
in default arguments for template parameters), and access in default arguments for template parameters), and access
checking should be performed in the outermost parameter list. */ checking should be performed in the outermost parameter list. */
if (processing_template_decl if (processing_template_decl
&& !expanding_concept ()
&& (!processing_template_parmlist || processing_template_decl > 1)) && (!processing_template_parmlist || processing_template_decl > 1))
return 1; return 1;

View File

@ -3182,6 +3182,11 @@ cp_tree_equal (tree t1, tree t2)
return cp_tree_equal (CI_ASSOCIATED_CONSTRAINTS (t1), return cp_tree_equal (CI_ASSOCIATED_CONSTRAINTS (t1),
CI_ASSOCIATED_CONSTRAINTS (t2)); CI_ASSOCIATED_CONSTRAINTS (t2));
case CHECK_CONSTR:
return (CHECK_CONSTR_CONCEPT (t1) == CHECK_CONSTR_CONCEPT (t2)
&& comp_template_args (CHECK_CONSTR_ARGS (t1),
CHECK_CONSTR_ARGS (t2)));
case TREE_VEC: case TREE_VEC:
{ {
unsigned ix; unsigned ix;

View File

@ -1,16 +1,30 @@
// PR c++/67159 // PR c++/67159
// { dg-options "-std=c++1z -fconcepts" } // { dg-options "-std=c++1z -fconcepts" }
template <class T, class U>
concept bool SameAs = __is_same_as(T, U);
template <class T> template <class T>
concept bool R = requires (T& t) { concept bool R1 = requires (T& t) {
{ t.begin() } -> T { t.begin() } -> T
{ t.end() } -> SameAs<T*>;
};
template <class T>
concept bool R2 = requires (T& t) {
{ t.end() } -> SameAs<T*>;
}; };
struct foo { struct foo {
int* begin(); int* begin();
int* end();
}; };
R{T} R1{T}
constexpr bool f() { return true; } constexpr bool f() { return true; }
R2{T}
constexpr bool g() { return true; }
static_assert(f<foo>()); // { dg-error "" } static_assert(f<foo>()); // { dg-error "" }
static_assert(g<foo>()); // { dg-error "" }

View File

@ -24,11 +24,19 @@ template <typename T, typename U, typename... Args>
return decltype(check<T, U, Args...>())::value; return decltype(check<T, U, Args...>())::value;
} }
template <typename T, typename U, typename... Args>
concept bool Similar = true;
template <typename... Args> template <typename... Args>
requires Same<Args...>() // { dg-error "concept" } requires Same<Args...>() // { dg-error "invalid reference" }
void foo( Args... args ) {} void foo( Args... args ) {}
template <typename... Args>
requires Similar<Args...> // { dg-error "invalid reference" }
void bar( Args... args ) {}
int main() int main()
{ {
foo(1, 2, 3); // { dg-error "" } foo(1, 2, 3); // { dg-error "cannot call" }
bar(1, 2, 3); // { dg-error "cannot call" }
} }

View File

@ -31,12 +31,12 @@ class S
int main() int main()
{ {
f1(s); // { dg-error "cannot call" } f1(s); // { dg-error "cannot call" }
f2(s); // { dg-error "cannot call" } f2(s); // { dg-error "" }
// When used in non-SFINAE contexts, make sure that we fail // When used in non-SFINAE contexts, make sure that we fail
// the constraint check before emitting the access check // the constraint check before emitting the access check
// failures. The context is being presented constistently // failures. The context is being presented constistently
// in both cases. // in both cases.
static_assert(C1<S>(), ""); // { dg-error "failed" } static_assert(C1<S>(), ""); // { dg-error "failed" }
static_assert(C2<S>(), ""); // { dg-error "failed" } static_assert(C2<S>(), ""); // { dg-error "" }
} }

View File

@ -0,0 +1,13 @@
// { dg-options "-std=c++1z -fconcepts" }
struct B
{
template <class T> void f(T t)
requires requires (T tt) { tt; }
{ }
};
int main()
{
B().f(42);
}

View File

@ -0,0 +1,20 @@
// { dg-options "-std=c++1z -fconcepts" }
template <class T> concept bool C = true;
template <class T>
requires C<typename T::foo>
void f(T t) { }
void f(...);
template <class T>
requires C<T>
void g(T t) { }
int main()
{
f(42);
g(42);
}

View File

@ -9,10 +9,10 @@ template<typename T> constexpr fool p1() { return {}; }
template<typename T> constexpr fool p2() { return {}; } template<typename T> constexpr fool p2() { return {}; }
template<typename T> template<typename T>
concept bool C() { return p1<T>() && p2<T>(); } // { dg-error "does not have type" } concept bool C() { return p1<T>() && p2<T>(); }
template<C T> void f(T x) { } template<C T> void f(T x) { }
int main() { int main() {
f(0); // { dg-error "cannot call" } f(0); // { dg-error "cannot call|uses overloaded operator" }
} }

View File

@ -9,10 +9,10 @@ template<typename T> constexpr fool p1() { return {}; }
template<typename T> constexpr fool p2() { return {}; } template<typename T> constexpr fool p2() { return {}; }
template<typename T> template<typename T>
concept bool C() { return p1<T>() && p2<T>(); } // { dg-error "does not have type" } concept bool C() { return p1<T>() && p2<T>(); }
template<C T> void f(T x) { } template<C T> void f(T x) { }
int main() { int main() {
f(0); // { dg-error "cannot call" } f(0); // { dg-error "cannot call|uses overloaded operator" }
} }

View File

@ -7,7 +7,12 @@ template<typename T>
concept bool C1() { return X(); } concept bool C1() { return X(); }
template<C1 T> template<C1 T>
void h(T) { } // { dg-error "not|bool" } void h(T) { } // OK until used.
void f()
{
h(0); // { dg-error "does not have|cannot call" }
}
template<typename T> template<typename T>
concept bool C2() { return X() == X(); } // OK concept bool C2() { return X() == X(); } // OK

View File

@ -13,4 +13,4 @@ template <class T>
constexpr bool f() { return false; } constexpr bool f() { return false; }
static_assert(f<void>()); static_assert(f<void>());
static_assert(v<void>); // { dg-error "constraints" } static_assert(v<void>); // { dg-error "invalid" }

View File

@ -4,10 +4,13 @@ template <class T> concept bool Copyable = requires (T t) { T(t); };
template <class T> concept bool Constructable = requires { T(); }; template <class T> concept bool Constructable = requires { T(); };
template <class T> concept bool Both = Copyable<T> && Constructable<T>; template <class T> concept bool Both = Copyable<T> && Constructable<T>;
template <Copyable... Ts> void f(Ts...) { } template <Copyable... Ts>
template <Both... Ts> void f(Ts...) { } constexpr int f(Ts...) { return 0; } // #1
template <Both... Ts>
constexpr int f(Ts...) { return 1; } // #2
int main() int main()
{ {
f(42); static_assert(f(42) == 1);
} }

View File

@ -137,6 +137,8 @@ DEFTIMEVAR (TV_PARSE_FUNC , "parser function body")
DEFTIMEVAR (TV_PARSE_INLINE , "parser inl. func. body") DEFTIMEVAR (TV_PARSE_INLINE , "parser inl. func. body")
DEFTIMEVAR (TV_PARSE_INMETH , "parser inl. meth. body") DEFTIMEVAR (TV_PARSE_INMETH , "parser inl. meth. body")
DEFTIMEVAR (TV_TEMPLATE_INST , "template instantiation") DEFTIMEVAR (TV_TEMPLATE_INST , "template instantiation")
DEFTIMEVAR (TV_CONSTRAINT_SAT , "constraint satisfaction")
DEFTIMEVAR (TV_CONSTRAINT_SUB , "constraint subsumption")
DEFTIMEVAR (TV_FLATTEN_INLINING , "flatten inlining") DEFTIMEVAR (TV_FLATTEN_INLINING , "flatten inlining")
DEFTIMEVAR (TV_EARLY_INLINING , "early inlining heuristics") DEFTIMEVAR (TV_EARLY_INLINING , "early inlining heuristics")
DEFTIMEVAR (TV_INLINE_PARAMETERS , "inline parameters") DEFTIMEVAR (TV_INLINE_PARAMETERS , "inline parameters")

View File

@ -229,6 +229,14 @@ class auto_timevar
m_timer->push (m_tv); m_timer->push (m_tv);
} }
explicit auto_timevar (timevar_id_t tv)
: m_timer (g_timer)
, m_tv (tv)
{
if (m_timer)
m_timer->push (m_tv);
}
~auto_timevar () ~auto_timevar ()
{ {
if (m_timer) if (m_timer)