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:
parent
e17def9a70
commit
f078dc7d26
|
@ -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.
|
||||
|
|
138
gcc/cp/ChangeLog
138
gcc/cp/ChangeLog
|
@ -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
|
||||
|
|
1617
gcc/cp/constraint.cc
1617
gcc/cp/constraint.cc
File diff suppressed because it is too large
Load Diff
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
943
gcc/cp/logic.cc
943
gcc/cp/logic.cc
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
|
|
283
gcc/cp/pt.c
283
gcc/cp/pt.c
|
@ -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. */
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 "" }
|
||||
|
|
|
@ -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" }
|
||||
}
|
||||
|
|
|
@ -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 "" }
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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" }
|
||||
}
|
||||
|
|
|
@ -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" }
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue