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>
* 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>
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. */
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.
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.
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. */
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
// - the associated constraints, which are the conjunction of those,
// 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
// printing constrained declarations.
@ -905,8 +901,6 @@ struct GTY(()) tree_constraint_info {
tree template_reqs;
tree declarator_reqs;
tree associated_constr;
tree normalized_constr;
tree assumptions;
};
// Require that pointer P is non-null before returning.
@ -945,14 +939,6 @@ check_constraint_info (tree t)
#define CI_ASSOCIATED_CONSTRAINTS(NODE) \
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
// at a given template parameter list level indicated by NODE.
#define TEMPLATE_PARMS_CONSTRAINTS(NODE) \
@ -976,6 +962,14 @@ check_constraint_info (tree t)
#define PRED_CONSTR_EXPR(NODE) \
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. */
#define EXPR_CONSTR_EXPR(NODE) \
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 int comp_template_args (tree, tree, tree * = NULL,
tree * = NULL);
extern int template_args_equal (tree, tree);
extern tree maybe_process_partial_specialization (tree);
extern tree most_specialized_instantiation (tree);
extern void print_candidates (tree);
@ -6848,10 +6843,8 @@ extern tree strip_using_decl (tree);
/* in constraint.cc */
extern void init_constraint_processing ();
extern bool constraint_p (tree);
extern tree make_predicate_constraint (tree);
extern tree conjoin_constraints (tree, tree);
extern tree conjoin_constraints (tree);
extern bool valid_constraints_p (tree);
extern tree get_constraints (tree);
extern void set_constraints (tree, 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_info (tree, tree, tsubst_flags_t, 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_function_concept (tree, tree);
extern tree evaluate_variable_concept (tree, tree);
extern tree evaluate_constraint_expression (tree, tree);
extern bool constraints_satisfied_p (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 equivalently_constrained (tree, tree);
@ -6899,7 +6902,6 @@ extern int more_constrained (tree, tree);
extern void diagnose_constraints (location_t, tree, tree);
/* in logic.cc */
extern tree decompose_assumptions (tree);
extern tree decompose_conclusions (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_cast_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
@ -1139,6 +1142,19 @@ cxx_pretty_printer::expression (tree t)
pp_cxx_ws_string (this, "...");
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:
pp_cxx_template_id (this, t);
break;
@ -1165,6 +1181,7 @@ cxx_pretty_printer::expression (tree t)
break;
case PRED_CONSTR:
case CHECK_CONSTR:
case EXPR_CONSTR:
case TYPE_CONSTR:
case ICONV_CONSTR:
@ -2198,6 +2215,11 @@ void
pp_cxx_constrained_type_spec (cxx_pretty_printer *pp, tree c)
{
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);
pp->id_expression (t);
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);
}
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
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->type_id (type);
}
pp_cxx_semicolon (pp);
}
/* nested requirement:
@ -2632,74 +2751,94 @@ pp_cxx_nested_requirement (cxx_pretty_printer *pp, tree t)
void
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_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
pp_cxx_expression_constraint (cxx_pretty_printer *pp, tree t)
{
pp_string (pp, "valid_expr");
pp_left_paren (pp);
pp_string (pp, "<valid-expression ");
pp_cxx_left_paren (pp);
pp->expression (TREE_OPERAND (t, 0));
pp_right_paren (pp);
pp_cxx_right_paren (pp);
pp_string (pp, ">");
}
void
pp_cxx_type_constraint (cxx_pretty_printer *pp, tree t)
{
pp_string (pp, "valid_type");
pp_left_paren (pp);
pp_string (pp, "<valid-type ");
pp->type_id (TREE_OPERAND (t, 0));
pp_right_paren (pp);
pp_string (pp, ">");
}
void
pp_cxx_implicit_conversion_constraint (cxx_pretty_printer *pp, tree t)
{
pp_string (pp, "convertible");
pp_left_paren (pp);
pp_string (pp, "<implicitly-conversion ");
pp_cxx_left_paren (pp);
pp->expression (ICONV_CONSTR_EXPR (t));
pp_cxx_separate_with (pp, ',');
pp->expression (ICONV_CONSTR_TYPE (t));
pp_right_paren (pp);
pp_cxx_right_paren (pp);
pp_cxx_ws_string (pp, "to");
pp->type_id (ICONV_CONSTR_TYPE (t));
pp_string (pp, ">");
}
void
pp_cxx_argument_deduction_constraint (cxx_pretty_printer *pp, tree t)
{
pp_string (pp, "deducible");
pp_left_paren (pp);
pp_string (pp, "<argument-deduction ");
pp_cxx_left_paren (pp);
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_right_paren (pp);
pp_string (pp, ">");
}
void
pp_cxx_exception_constraint (cxx_pretty_printer *pp, tree t)
{
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_right_paren (pp);
pp_cxx_right_paren (pp);
}
void
pp_cxx_parameterized_constraint (cxx_pretty_printer *pp, tree t)
{
pp_left_paren (pp);
pp_string (pp, "forall");
pp_string (pp, "<requires ");
if (tree parms = PARM_CONSTR_PARMS (t))
{
if (parms)
pp_cxx_parameter_declaration_clause (pp, parms);
pp_cxx_whitespace (pp);
}
pp_cxx_constraint (pp, PARM_CONSTR_OPERAND (t));
pp_right_paren (pp);
pp_string (pp, ">");
}
void
@ -2730,6 +2869,10 @@ pp_cxx_constraint (cxx_pretty_printer *pp, tree t)
pp_cxx_predicate_constraint (pp, t);
break;
case CHECK_CONSTR:
pp_cxx_check_constraint (pp, t);
break;
case EXPR_CONSTR:
pp_cxx_expression_constraint (pp, t);
break;
@ -2762,6 +2905,10 @@ pp_cxx_constraint (cxx_pretty_printer *pp, tree t)
pp_cxx_disjunction (pp, t);
break;
case EXPR_PACK_EXPANSION:
pp->expression (TREE_OPERAND (t, 0));
break;
default:
gcc_unreachable ();
}

View File

@ -7921,7 +7921,7 @@ grokfndecl (tree ctype,
/* Adjust the required expression into a constraint. */
if (decl_reqs)
decl_reqs = make_predicate_constraint (decl_reqs);
decl_reqs = normalize_expression (decl_reqs);
tree ci = build_constraints (tmpl_reqs, decl_reqs);
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)
&& 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);
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)))
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))
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");
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? */
@ -2665,6 +2678,10 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
break;
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 MEMBER_REF:
case DOTSTAR_EXPR:
@ -2737,6 +2754,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
break;
case PRED_CONSTR:
case CHECK_CONSTR:
case EXPR_CONSTR:
case TYPE_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);
// If template requirements are present, parse them.
tree reqs = get_shorthand_constraints (current_template_parms);
if (tree r = cp_parser_requires_clause_opt (parser))
reqs = conjoin_constraints (reqs, make_predicate_constraint (r));
TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
if (flag_concepts)
{
tree reqs = get_shorthand_constraints (current_template_parms);
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. */
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);
/* Manage template requirements */
tree reqs = get_shorthand_constraints (current_template_parms);
if (tree r = cp_parser_requires_clause_opt (parser))
reqs = conjoin_constraints (reqs, make_predicate_constraint (r));
TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
if (flag_concepts)
{
tree reqs = get_shorthand_constraints (current_template_parms);
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,
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
constrained parameter, try to find a previous parameter with
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)
{
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,
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 tree for_each_template_parm_r (tree *, int *, void *);
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. */
static int
int
template_args_equal (tree ot, tree nt)
{
if (nt == ot)
@ -8702,7 +8701,7 @@ finish_template_variable (tree var, tsubst_flags_t complain)
{
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);
}
return error_mark_node;
@ -9058,7 +9057,7 @@ uses_outer_template_parms (tree decl)
return true;
tree ci = get_constraints (decl);
if (ci)
ci = CI_NORMALIZED_CONSTRAINTS (ci);
ci = CI_ASSOCIATED_CONSTRAINTS (ci);
if (ci && for_each_template_parm (ci, template_parm_outer_level,
&depth, NULL, /*nondeduced*/true))
return true;
@ -23764,7 +23763,10 @@ build_non_dependent_expr (tree expr)
&& cxx_dialect >= cxx11
/* Don't do this during nsdmi parsing as it can lead to
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);
/* Preserve OVERLOADs; the functions must be available to resolve
@ -23902,7 +23904,7 @@ make_constrained_auto (tree con, tree args)
else
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;
/* 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
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
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
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 (tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (auto_node))
{
/* Use the deduced type to check the associated constraints. */
if (!constraints_satisfied_p (constr, targs))
/* Use the deduced type to check the associated constraints. If we
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)
{
@ -24482,24 +24498,15 @@ struct constr_hasher : ggc_ptr_hash<constr_entry>
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
constrained, return NULL_TREE. Note that T must be non-null. */
tree
get_constraints (tree t)
{
if (!flag_concepts)
return NULL_TREE;
gcc_assert (DECL_P (t));
if (TREE_CODE (t) == TEMPLATE_DECL)
t = DECL_TEMPLATE_RESULT (t);
@ -24521,7 +24528,7 @@ set_constraints (tree t, tree ci)
{
if (!ci)
return;
gcc_assert (t);
gcc_assert (t && flag_concepts);
if (TREE_CODE (t) == TEMPLATE_DECL)
t = DECL_TEMPLATE_RESULT (t);
gcc_assert (!get_constraints (t));
@ -24547,12 +24554,244 @@ remove_constraints (tree t)
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. */
void
init_constraint_processing (void)
{
if (!flag_concepts)
return;
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. */

View File

@ -260,7 +260,6 @@ cxx_print_xnode (FILE *file, tree node, int indent)
indent+4);
print_node (file, "associated_constr",
cinfo->associated_constr, indent+4);
print_node_brief (file, "assumptions", cinfo->assumptions, indent+4);
break;
}
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
checking should be performed in the outermost parameter list. */
if (processing_template_decl
&& !expanding_concept ()
&& (!processing_template_parmlist || processing_template_decl > 1))
return 1;

View File

@ -3182,6 +3182,11 @@ cp_tree_equal (tree t1, tree t2)
return cp_tree_equal (CI_ASSOCIATED_CONSTRAINTS (t1),
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:
{
unsigned ix;

View File

@ -1,16 +1,30 @@
// PR c++/67159
// { dg-options "-std=c++1z -fconcepts" }
template <class T, class U>
concept bool SameAs = __is_same_as(T, U);
template <class T>
concept bool R = requires (T& t) {
concept bool R1 = requires (T& t) {
{ t.begin() } -> T
{ t.end() } -> SameAs<T*>;
};
template <class T>
concept bool R2 = requires (T& t) {
{ t.end() } -> SameAs<T*>;
};
struct foo {
int* begin();
int* end();
};
R{T}
R1{T}
constexpr bool f() { return true; }
R2{T}
constexpr bool g() { return true; }
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;
}
template <typename T, typename U, typename... Args>
concept bool Similar = true;
template <typename... Args>
requires Same<Args...>() // { dg-error "concept" }
requires Same<Args...>() // { dg-error "invalid reference" }
void foo( Args... args ) {}
template <typename... Args>
requires Similar<Args...> // { dg-error "invalid reference" }
void bar( Args... args ) {}
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()
{
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
// the constraint check before emitting the access check
// failures. The context is being presented constistently
// in both cases.
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>
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) { }
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>
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) { }
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(); }
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>
concept bool C2() { return X() == X(); } // OK

View File

@ -13,4 +13,4 @@ template <class T>
constexpr bool f() { return false; }
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 Both = Copyable<T> && Constructable<T>;
template <Copyable... Ts> void f(Ts...) { }
template <Both... Ts> void f(Ts...) { }
template <Copyable... Ts>
constexpr int f(Ts...) { return 0; } // #1
template <Both... Ts>
constexpr int f(Ts...) { return 1; } // #2
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_INMETH , "parser inl. meth. body")
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_EARLY_INLINING , "early inlining heuristics")
DEFTIMEVAR (TV_INLINE_PARAMETERS , "inline parameters")

View File

@ -229,6 +229,14 @@ class auto_timevar
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 ()
{
if (m_timer)