Re: [PATCH] c++: Some improvements to concept diagnostics
On 2/24/20 12:30 PM, Patrick Palka wrote: On Mon, 24 Feb 2020, Jason Merrill wrote: On 2/20/20 7:27 PM, Patrick Palka wrote: This patch improves our concept diagnostics in two ways. First, it sets a more precise location for the constraint expressions built in finish_constraint_binary_op. As a result, when a disjunction is unsatisfied we now print e.g. .../include/bits/range_access.h:467:2: note: neither operand of the disjunction is satisfied 466 | requires is_bounded_array_v> || __member_end<_Tp> | 467 | || __adl_end<_Tp> | ^ instead of .../include/bits/range_access.h:467:2: note: neither operand of the disjunction is satisfied 467 | || __adl_end<_Tp> | ^~ This hunk is OK. Second, this patch changes diagnose_atomic_constraint to pretty-print unsatisfied atomic constraint expressions with their template arguments substituted in (if doing so does not result in a trivial expression). So for example we now emit cpp2a/concepts-pr67719.C:9:8: note: the expression ‘((C() && C()) && C())’ evaluated to ‘false’ instead of cpp2a/concepts-pr67719.C:9:8: note: the expression ‘(... &&(C)())’ evaluated to ‘false’ Generally with templates we try to print the dependent form and then the arguments; pp_cxx_atomic_constraint already wants to do that, but we don't get there from here. Perhaps pass 'map' instead of 'args' into diagnose_atomic_constraint, and then build a new ATOMIC_CONSTR for printing with %E? That works really well. I had to add handling of TYPE_ARGUMENT_PACK to cxx_pretty_printer::type_id because otherwise an "unsupported type_argument_pack" placeholder would get printed in these diagnostics instead. For consistency with the way we print TYPE_ARGUMENT_PACKs and NONTYPE_ARGUMENT_PACKs elsewhere I also made cxx_pretty_printer::expression print curly braces around a NONTYPE_ARGUMENT_PACK. Tested on x86_64-pc-linux-gnu, does this look OK? OK. -- >8 -- gcc/cp/ChangeLog: * constraint.cc (finish_constraint_binary_op): Set expr's location range to the range of its operands. (satisfy_atom): Pass MAP instead of ARGS to diagnose_atomic_constraint. (diagnose_trait_expr): Take the instantiated parameter mapping MAP instead of the corresponding template arguments ARGS and adjust body accordingly. (diagnose_requires_expr): Likewise. (diagnose_atomic_constraint): Likewise. When printing an atomic constraint expression, print the instantiated parameter mapping alongside it. * cxx-pretty-print.cc (cxx_pretty_printer::expression) [NONTYPE_ARGUMENT_PACK]: Print braces around a NONTYPE_ARGUMENT_PACK. (cxx_pretty_printer::type_id): Handle TYPE_ARGUMENT_PACK. gcc/testsuite/ChangeLog: * g++.dg/concepts/diagnostic2.C: New test. * g++.dg/concepts/diagnostic3.C: New test. --- gcc/cp/constraint.cc| 33 - gcc/cp/cxx-pretty-print.c | 17 +++ gcc/testsuite/g++.dg/concepts/diagnostic2.C | 30 +++ gcc/testsuite/g++.dg/concepts/diagnostic3.C | 29 ++ 4 files changed, 95 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic2.C create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic3.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 58044cd0f9d..4e6ed440211 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -155,14 +155,14 @@ finish_constraint_binary_op (location_t loc, if (!check_constraint_operands (loc, lhs, rhs)) return error_mark_node; tree overload; - tree expr = build_x_binary_op (loc, code, -lhs, TREE_CODE (lhs), -rhs, TREE_CODE (rhs), -&overload, tf_none); + cp_expr expr = build_x_binary_op (loc, code, + lhs, TREE_CODE (lhs), + rhs, TREE_CODE (rhs), + &overload, tf_none); /* When either operand is dependent, the overload set may be non-empty. */ if (expr == error_mark_node) return error_mark_node; - SET_EXPR_LOCATION (expr, loc); + expr.set_range (lhs.get_start (), rhs.get_finish ()); return expr; } @@ -2547,7 +2547,7 @@ satisfy_atom (tree t, tree args, subst_info info) /* Compute the value of the constraint. */ result = satisfaction_value (cxx_constant_value (result)); if (result == boolean_false_node && info.noisy ()) -diagnose_atomic_constraint (t, args, info); +diagnose_atomic_constraint (t, map, info); return cache.save (result); } @@ -3056,9 +3056,10 @@ get_constraint_error_location (tree
Re: [PATCH] c++: Some improvements to concept diagnostics
On Mon, 24 Feb 2020, Jason Merrill wrote: > On 2/20/20 7:27 PM, Patrick Palka wrote: > > This patch improves our concept diagnostics in two ways. First, it sets a > > more > > precise location for the constraint expressions built in > > finish_constraint_binary_op. As a result, when a disjunction is unsatisfied > > we > > now print e.g. > > > > .../include/bits/range_access.h:467:2: note: neither operand of the > > disjunction is satisfied > >466 | requires is_bounded_array_v> || > > __member_end<_Tp> > >| > > > >467 | || __adl_end<_Tp> > >| ^ > > > > instead of > > > > .../include/bits/range_access.h:467:2: note: neither operand of the > > disjunction is satisfied > >467 | || __adl_end<_Tp> > >| ^~ > > This hunk is OK. > > > Second, this patch changes diagnose_atomic_constraint to pretty-print > > unsatisfied atomic constraint expressions with their template arguments > > substituted in (if doing so does not result in a trivial expression). So > > for > > example we now emit > > > > cpp2a/concepts-pr67719.C:9:8: note: the expression ‘((C() && C > int>()) && C())’ evaluated to ‘false’ > > > > instead of > > > > cpp2a/concepts-pr67719.C:9:8: note: the expression ‘(... &&(C)())’ > > evaluated to ‘false’ > > Generally with templates we try to print the dependent form and then the > arguments; pp_cxx_atomic_constraint already wants to do that, but we don't get > there from here. Perhaps pass 'map' instead of 'args' into > diagnose_atomic_constraint, and then build a new ATOMIC_CONSTR for printing > with %E? That works really well. I had to add handling of TYPE_ARGUMENT_PACK to cxx_pretty_printer::type_id because otherwise an "unsupported type_argument_pack" placeholder would get printed in these diagnostics instead. For consistency with the way we print TYPE_ARGUMENT_PACKs and NONTYPE_ARGUMENT_PACKs elsewhere I also made cxx_pretty_printer::expression print curly braces around a NONTYPE_ARGUMENT_PACK. Tested on x86_64-pc-linux-gnu, does this look OK? -- >8 -- gcc/cp/ChangeLog: * constraint.cc (finish_constraint_binary_op): Set expr's location range to the range of its operands. (satisfy_atom): Pass MAP instead of ARGS to diagnose_atomic_constraint. (diagnose_trait_expr): Take the instantiated parameter mapping MAP instead of the corresponding template arguments ARGS and adjust body accordingly. (diagnose_requires_expr): Likewise. (diagnose_atomic_constraint): Likewise. When printing an atomic constraint expression, print the instantiated parameter mapping alongside it. * cxx-pretty-print.cc (cxx_pretty_printer::expression) [NONTYPE_ARGUMENT_PACK]: Print braces around a NONTYPE_ARGUMENT_PACK. (cxx_pretty_printer::type_id): Handle TYPE_ARGUMENT_PACK. gcc/testsuite/ChangeLog: * g++.dg/concepts/diagnostic2.C: New test. * g++.dg/concepts/diagnostic3.C: New test. --- gcc/cp/constraint.cc| 33 - gcc/cp/cxx-pretty-print.c | 17 +++ gcc/testsuite/g++.dg/concepts/diagnostic2.C | 30 +++ gcc/testsuite/g++.dg/concepts/diagnostic3.C | 29 ++ 4 files changed, 95 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic2.C create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic3.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 58044cd0f9d..4e6ed440211 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -155,14 +155,14 @@ finish_constraint_binary_op (location_t loc, if (!check_constraint_operands (loc, lhs, rhs)) return error_mark_node; tree overload; - tree expr = build_x_binary_op (loc, code, -lhs, TREE_CODE (lhs), -rhs, TREE_CODE (rhs), -&overload, tf_none); + cp_expr expr = build_x_binary_op (loc, code, + lhs, TREE_CODE (lhs), + rhs, TREE_CODE (rhs), + &overload, tf_none); /* When either operand is dependent, the overload set may be non-empty. */ if (expr == error_mark_node) return error_mark_node; - SET_EXPR_LOCATION (expr, loc); + expr.set_range (lhs.get_start (), rhs.get_finish ()); return expr; } @@ -2547,7 +2547,7 @@ satisfy_atom (tree t, tree args, subst_info info) /* Compute the value of the constraint. */ result = sat
Re: [PATCH] c++: Some improvements to concept diagnostics
On 2/20/20 7:27 PM, Patrick Palka wrote: This patch improves our concept diagnostics in two ways. First, it sets a more precise location for the constraint expressions built in finish_constraint_binary_op. As a result, when a disjunction is unsatisfied we now print e.g. .../include/bits/range_access.h:467:2: note: neither operand of the disjunction is satisfied 466 | requires is_bounded_array_v> || __member_end<_Tp> | 467 | || __adl_end<_Tp> | ^ instead of .../include/bits/range_access.h:467:2: note: neither operand of the disjunction is satisfied 467 | || __adl_end<_Tp> | ^~ This hunk is OK. Second, this patch changes diagnose_atomic_constraint to pretty-print unsatisfied atomic constraint expressions with their template arguments substituted in (if doing so does not result in a trivial expression). So for example we now emit cpp2a/concepts-pr67719.C:9:8: note: the expression ‘((C() && C()) && C())’ evaluated to ‘false’ instead of cpp2a/concepts-pr67719.C:9:8: note: the expression ‘(... &&(C)())’ evaluated to ‘false’ Generally with templates we try to print the dependent form and then the arguments; pp_cxx_atomic_constraint already wants to do that, but we don't get there from here. Perhaps pass 'map' instead of 'args' into diagnose_atomic_constraint, and then build a new ATOMIC_CONSTR for printing with %E? Tested on x86_64-pc-linux-gnu, and verified that all the diagnostics emitted in our concept tests are no worse with this patch. Does this look OK to commit? gcc/cp/ChangeLog: * constraint.cc (finish_constraint_binary_op): Set expr's location range to the range of its operands. (diagnose_atomic_constraint): Prefer to pretty-print the atomic constraint with template arguments substituted in. gcc/testsuite/ChangeLog: * g++.dg/concepts/diagnostic2.C: New test. * g++.dg/concepts/diagnostic3.C: New test. --- gcc/cp/constraint.cc| 15 +++ gcc/testsuite/g++.dg/concepts/diagnostic2.C | 30 + gcc/testsuite/g++.dg/concepts/diagnostic3.C | 19 + 3 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic2.C create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic3.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 58044cd0f9d..4f6bc11e7e8 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -155,14 +155,14 @@ finish_constraint_binary_op (location_t loc, if (!check_constraint_operands (loc, lhs, rhs)) return error_mark_node; tree overload; - tree expr = build_x_binary_op (loc, code, -lhs, TREE_CODE (lhs), -rhs, TREE_CODE (rhs), -&overload, tf_none); + cp_expr expr = build_x_binary_op (loc, code, + lhs, TREE_CODE (lhs), + rhs, TREE_CODE (rhs), + &overload, tf_none); /* When either operand is dependent, the overload set may be non-empty. */ if (expr == error_mark_node) return error_mark_node; - SET_EXPR_LOCATION (expr, loc); + expr.set_range (lhs.get_start (), rhs.get_finish ()); return expr; } @@ -3330,6 +3330,11 @@ diagnose_atomic_constraint (tree t, tree args, subst_info info) inform (loc, "%qE is never satisfied", expr); break; default: + tree orig_expr = expr; + expr = tsubst_expr (expr, args, tf_none, NULL_TREE, false); + if (CONSTANT_CLASS_P (expr)) + /* We are better off printing the original expression. */ + expr = orig_expr; inform (loc, "the expression %qE evaluated to %", expr); } } diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C b/gcc/testsuite/g++.dg/concepts/diagnostic2.C new file mode 100644 index 000..ce51b71fa8b --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C @@ -0,0 +1,30 @@ +// { dg-do compile { target c++2a } } +// { dg-options "-fdiagnostics-show-caret" } + +template + inline constexpr bool foo_v = false; + +template + concept foo = foo_v || foo_v; // { dg-message "neither operand" } +/* { dg-begin-multiline-output "" } + concept foo = foo_v || foo_v; + ~^~~~ + { dg-end-multiline-output "" } */ + +template + requires foo + void bar(); +/* { dg-begin-multiline-output "" } + void bar(); + { dg-end-multiline-output "" } */ +/* { dg-prune-output "~" } */ + +void +baz() +{ + bar(); // { dg-error "unsatisfied constraints" } +/* { dg-begin-multiline-output "" } + bar(); +
[PATCH] c++: Some improvements to concept diagnostics
This patch improves our concept diagnostics in two ways. First, it sets a more precise location for the constraint expressions built in finish_constraint_binary_op. As a result, when a disjunction is unsatisfied we now print e.g. .../include/bits/range_access.h:467:2: note: neither operand of the disjunction is satisfied 466 | requires is_bounded_array_v> || __member_end<_Tp> | 467 | || __adl_end<_Tp> | ^ instead of .../include/bits/range_access.h:467:2: note: neither operand of the disjunction is satisfied 467 | || __adl_end<_Tp> | ^~ Second, this patch changes diagnose_atomic_constraint to pretty-print unsatisfied atomic constraint expressions with their template arguments substituted in (if doing so does not result in a trivial expression). So for example we now emit cpp2a/concepts-pr67719.C:9:8: note: the expression ‘((C() && C()) && C())’ evaluated to ‘false’ instead of cpp2a/concepts-pr67719.C:9:8: note: the expression ‘(... &&(C)())’ evaluated to ‘false’ Tested on x86_64-pc-linux-gnu, and verified that all the diagnostics emitted in our concept tests are no worse with this patch. Does this look OK to commit? gcc/cp/ChangeLog: * constraint.cc (finish_constraint_binary_op): Set expr's location range to the range of its operands. (diagnose_atomic_constraint): Prefer to pretty-print the atomic constraint with template arguments substituted in. gcc/testsuite/ChangeLog: * g++.dg/concepts/diagnostic2.C: New test. * g++.dg/concepts/diagnostic3.C: New test. --- gcc/cp/constraint.cc| 15 +++ gcc/testsuite/g++.dg/concepts/diagnostic2.C | 30 + gcc/testsuite/g++.dg/concepts/diagnostic3.C | 19 + 3 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic2.C create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic3.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 58044cd0f9d..4f6bc11e7e8 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -155,14 +155,14 @@ finish_constraint_binary_op (location_t loc, if (!check_constraint_operands (loc, lhs, rhs)) return error_mark_node; tree overload; - tree expr = build_x_binary_op (loc, code, -lhs, TREE_CODE (lhs), -rhs, TREE_CODE (rhs), -&overload, tf_none); + cp_expr expr = build_x_binary_op (loc, code, + lhs, TREE_CODE (lhs), + rhs, TREE_CODE (rhs), + &overload, tf_none); /* When either operand is dependent, the overload set may be non-empty. */ if (expr == error_mark_node) return error_mark_node; - SET_EXPR_LOCATION (expr, loc); + expr.set_range (lhs.get_start (), rhs.get_finish ()); return expr; } @@ -3330,6 +3330,11 @@ diagnose_atomic_constraint (tree t, tree args, subst_info info) inform (loc, "%qE is never satisfied", expr); break; default: + tree orig_expr = expr; + expr = tsubst_expr (expr, args, tf_none, NULL_TREE, false); + if (CONSTANT_CLASS_P (expr)) + /* We are better off printing the original expression. */ + expr = orig_expr; inform (loc, "the expression %qE evaluated to %", expr); } } diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C b/gcc/testsuite/g++.dg/concepts/diagnostic2.C new file mode 100644 index 000..ce51b71fa8b --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C @@ -0,0 +1,30 @@ +// { dg-do compile { target c++2a } } +// { dg-options "-fdiagnostics-show-caret" } + +template + inline constexpr bool foo_v = false; + +template + concept foo = foo_v || foo_v; // { dg-message "neither operand" } +/* { dg-begin-multiline-output "" } + concept foo = foo_v || foo_v; + ~^~~~ + { dg-end-multiline-output "" } */ + +template + requires foo + void bar(); +/* { dg-begin-multiline-output "" } + void bar(); + { dg-end-multiline-output "" } */ +/* { dg-prune-output "~" } */ + +void +baz() +{ + bar(); // { dg-error "unsatisfied constraints" } +/* { dg-begin-multiline-output "" } + bar(); +^ + { dg-end-multiline-output "" } */ +} diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic3.C b/gcc/testsuite/g++.dg/concepts/diagnostic3.C new file mode 100644 index 000..e0649dac51a --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/diagnostic3.C @@ -0,0 +1,19 @@ +// { dg-do compile { target c++2a } } + +template + inline constexpr bool foo_v = false; + +template + con
Re: [C++ PATCH] Tweak concept diagnostics
On 12/6/19 3:20 PM, Jakub Jelinek wrote: Hi! I've noticed that while for requires keyword we have a diagnostics like error_at (cp_lexer_peek_token (parser->lexer)->location, "% only available with " "%<-std=c++2a%> or %<-fconcepts%>"); for concept keyword we emit inform (location, "% only available with %<-fconcepts%>"); The following patch adjusts the latter to match the former, because I think more people will use -std=c++2a than -fconcepts in the GCC 10 timeframe. Tested on x86_64-linux, ok for trunk? OK, thanks. 2019-12-06 Jakub Jelinek * parser.c (cp_parser_diagnose_invalid_type_name): Mention that concept is also available with -std=c++2a. --- gcc/cp/parser.c.jj 2019-12-05 10:03:04.072181899 +0100 +++ gcc/cp/parser.c 2019-12-06 19:40:44.090311079 +0100 @@ -3367,7 +3367,8 @@ cp_parser_diagnose_invalid_type_name (cp inform (location, "C++20 % only available with " "%<-std=c++2a%> or %<-std=gnu++2a%>"); else if (!flag_concepts && id == ridpointers[(int)RID_CONCEPT]) - inform (location, "% only available with %<-fconcepts%>"); + inform (location, "% only available with %<-std=c++2a%> or " + "%<-fconcepts%>"); else if (processing_template_decl && current_class_type && TYPE_BINFO (current_class_type)) { Jakub
[C++ PATCH] Tweak concept diagnostics
Hi! I've noticed that while for requires keyword we have a diagnostics like error_at (cp_lexer_peek_token (parser->lexer)->location, "% only available with " "%<-std=c++2a%> or %<-fconcepts%>"); for concept keyword we emit inform (location, "% only available with %<-fconcepts%>"); The following patch adjusts the latter to match the former, because I think more people will use -std=c++2a than -fconcepts in the GCC 10 timeframe. Tested on x86_64-linux, ok for trunk? 2019-12-06 Jakub Jelinek * parser.c (cp_parser_diagnose_invalid_type_name): Mention that concept is also available with -std=c++2a. --- gcc/cp/parser.c.jj 2019-12-05 10:03:04.072181899 +0100 +++ gcc/cp/parser.c 2019-12-06 19:40:44.090311079 +0100 @@ -3367,7 +3367,8 @@ cp_parser_diagnose_invalid_type_name (cp inform (location, "C++20 % only available with " "%<-std=c++2a%> or %<-std=gnu++2a%>"); else if (!flag_concepts && id == ridpointers[(int)RID_CONCEPT]) - inform (location, "% only available with %<-fconcepts%>"); + inform (location, "% only available with %<-std=c++2a%> or " + "%<-fconcepts%>"); else if (processing_template_decl && current_class_type && TYPE_BINFO (current_class_type)) { Jakub
concept diagnostics
This is not a proper patch. I'm missing the usual changelog and I'm still running the regression tests, but I wanted to get some opinions before committing more time to it. This patch extends the diagnostics for concepts to report precise failures when constraints are not satisfied. It currently reports up to 7 errors and then elides the rest. That should probably be under control of a compiler option, but I'd like some suggestions on how to proceed. Also, diagnostics are currently emitted as notes against the location of the concept declaration. It would be better to diagnose the failure against location of each requirement, but we're not doing a very good job tracking source locations for those. Also, in a lot of cases, we probably just want to replay a substitution with tf_error to generate precise failures. Although that potentially generates *way* more information (e.g., candidate sets for failed overload resolution). I also started try to apply these diagnostics to static_if. The basic idea being: if you write static_if(C, "") where C is a concept, then you should get the full diagnostics for that concept. I suspect that this will be the most requested feature within a few months time. Unfortunately, I ran into a little problem that C is immediately folded into true/false and the original expression is unrecoverable from finish_static_if. I tinkered with parsing the condition as a non-constant expression and then folding it on demand, but that caused a number of regressions, so I had to back it out. Any thoughts on how to proceed? Andrew Index: cxx-pretty-print.c === --- cxx-pretty-print.c (revision 226937) +++ cxx-pretty-print.c (working copy) @@ -2600,6 +2600,7 @@ pp_cxx_compound_requirement (cxx_pretty_ pp_cxx_ws_string (pp, "->"); pp->type_id (type); } + pp_cxx_semicolon (pp); } /* nested requirement: @@ -2646,7 +2647,7 @@ pp_cxx_implicit_conversion_constraint (c pp_left_paren (pp); pp->expression (ICONV_CONSTR_EXPR (t)); pp_cxx_separate_with (pp, ','); - pp->expression (ICONV_CONSTR_TYPE (t)); + pp->type_id (ICONV_CONSTR_TYPE (t)); pp_right_paren (pp); } Index: cp-tree.h === --- cp-tree.h (revision 226937) +++ cp-tree.h (working copy) @@ -6680,6 +6680,8 @@ extern tree tsubst_requires_expr 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 bool variable_concept_check_p(tree); +extern bool concept_check_p (tree); extern tree evaluate_constraints(tree, tree); extern tree evaluate_function_concept (tree, tree); @@ -6687,6 +6689,7 @@ extern tree evaluate_variable_concept extern tree evaluate_constraint_expression (tree, tree); extern bool constraints_satisfied_p (tree); extern bool constraints_satisfied_p (tree, tree); +extern bool constraint_expression_satisfied_p (tree, tree); extern bool equivalent_constraints (tree, tree); extern bool equivalently_constrained(tree, tree); Index: constraint.cc === --- constraint.cc (revision 226937) +++ constraint.cc (working copy) @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. #include "wide-int.h" #include "inchash.h" #include "tree.h" +#include "print-tree.h" #include "stringpool.h" #include "attribs.h" #include "intl.h" @@ -113,13 +114,22 @@ conjoin_constraints (tree t) return r; } -/* Returns true if T is a call expression to a function - concept. */ +/* Returns true if T is an expression that would evaluate + a variable or function concept. */ + +bool +concept_check_p (tree t) +{ + return function_concept_check_p (t) || variable_concept_check_p (t); +} + +/* Returns true if T is a call to a function concept. */ bool function_concept_check_p (tree t) { - gcc_assert (TREE_CODE (t) == CALL_EXPR); + if (!t || t == error_mark_node || TREE_CODE (t) != CALL_EXPR) +return false; tree fn = CALL_EXPR_FN (t); if (TREE_CODE (fn) == TEMPLATE_ID_EXPR && TREE_CODE (TREE_OPERAND (fn, 0)) == OVERLOAD) @@ -132,6 +142,17 @@ function_concept_check_p (tree t) return false; } +/* Returns true if T is a template-id referring to a variable concept. */ + +bool +variable_concept_check_p (tree t) +{ + if (!t || t == error_mark_node || TREE_CODE (t) != TEMPLATE_ID_EXPR) +return false; + return variable_template_p (TREE_OPERAND (t, 0)); +} + + /*--- Resolution of qualified concept names ---*/ @@ -350,12 +371,12 @@ lift_func