Hi! The following patch fixes C++ FE ICE during instantiation if if clause argument is type or value dependent (ideally we'd keep the cancel directive as OMP_* and finish it again during instantiation, but adding a new tree code etc. just for this seems overkill). Fixed by using what we use for if clauses on other constructs when not processing_template_decl, otherwise do what we used to do, but in a processing_template_decl friendly way.
While at it, I've noticed we don't diagnose the case when cancel directive has incorrectly more than one if clause and both if clauses have different modifiers and the last one has cancel modifier (all other cases are diagnosed already during the if clause parsing or at this spot for the match of the if clause modifier). Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk. 2019-01-24 Jakub Jelinek <ja...@redhat.com> PR c++/88976 * c-typeck.c (c_finish_omp_cancel): Diagnose more than one if on #pragma omp cancel with different modifiers. * semantics.c (finish_omp_cancel): Diagnose more than one if on #pragma omp cancel with different modifiers. Use maybe_convert_cond when not in template or build_x_binary_op otherwise. * c-c++-common/gomp/cancel-2.c: New test. * gcc.dg/gomp/cancel-1.c: New test. * g++.dg/gomp/cancel-1.C: New test. * g++.dg/gomp/cancel-2.C: New test. * g++.dg/gomp/cancel-3.C: New test. --- gcc/c/c-typeck.c.jj 2019-01-19 09:39:16.703866621 +0100 +++ gcc/c/c-typeck.c 2019-01-24 15:58:49.065106156 +0100 @@ -12766,6 +12766,18 @@ c_finish_omp_cancel (location_t loc, tre && OMP_CLAUSE_IF_MODIFIER (ifc) != VOID_CST) error_at (OMP_CLAUSE_LOCATION (ifc), "expected %<cancel%> %<if%> clause modifier"); + else + { + tree ifc2 = omp_find_clause (OMP_CLAUSE_CHAIN (ifc), OMP_CLAUSE_IF); + if (ifc2 != NULL_TREE) + { + gcc_assert (OMP_CLAUSE_IF_MODIFIER (ifc) == VOID_CST + && OMP_CLAUSE_IF_MODIFIER (ifc2) != ERROR_MARK + && OMP_CLAUSE_IF_MODIFIER (ifc2) != VOID_CST); + error_at (OMP_CLAUSE_LOCATION (ifc2), + "expected %<cancel%> %<if%> clause modifier"); + } + } tree type = TREE_TYPE (OMP_CLAUSE_IF_EXPR (ifc)); ifc = fold_build2_loc (OMP_CLAUSE_LOCATION (ifc), NE_EXPR, --- gcc/cp/semantics.c.jj 2019-01-17 13:19:59.802488931 +0100 +++ gcc/cp/semantics.c 2019-01-24 15:59:04.395854827 +0100 @@ -9055,11 +9055,26 @@ finish_omp_cancel (tree clauses) && OMP_CLAUSE_IF_MODIFIER (ifc) != VOID_CST) error_at (OMP_CLAUSE_LOCATION (ifc), "expected %<cancel%> %<if%> clause modifier"); + else + { + tree ifc2 = omp_find_clause (OMP_CLAUSE_CHAIN (ifc), OMP_CLAUSE_IF); + if (ifc2 != NULL_TREE) + { + gcc_assert (OMP_CLAUSE_IF_MODIFIER (ifc) == VOID_CST + && OMP_CLAUSE_IF_MODIFIER (ifc2) != ERROR_MARK + && OMP_CLAUSE_IF_MODIFIER (ifc2) != VOID_CST); + error_at (OMP_CLAUSE_LOCATION (ifc2), + "expected %<cancel%> %<if%> clause modifier"); + } + } - tree type = TREE_TYPE (OMP_CLAUSE_IF_EXPR (ifc)); - ifc = fold_build2_loc (OMP_CLAUSE_LOCATION (ifc), NE_EXPR, - boolean_type_node, OMP_CLAUSE_IF_EXPR (ifc), - build_zero_cst (type)); + if (!processing_template_decl) + ifc = maybe_convert_cond (OMP_CLAUSE_IF_EXPR (ifc)); + else + ifc = build_x_binary_op (OMP_CLAUSE_LOCATION (ifc), NE_EXPR, + OMP_CLAUSE_IF_EXPR (ifc), ERROR_MARK, + integer_zero_node, ERROR_MARK, + NULL, tf_warning_or_error); } else ifc = boolean_true_node; --- gcc/testsuite/c-c++-common/gomp/cancel-2.c.jj 2019-01-24 16:07:08.278947844 +0100 +++ gcc/testsuite/c-c++-common/gomp/cancel-2.c 2019-01-24 16:07:27.576632880 +0100 @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +void +foo (void) +{ + #pragma omp parallel + { + #pragma omp cancel parallel if (1) if (1) /* { dg-error "too many 'if' clauses without modifier" } */ + #pragma omp cancel parallel if (cancel: 1) if (cancel: 1) /* { dg-error "too many 'if' clauses with 'cancel' modifier" } */ + #pragma omp cancel parallel if (cancel: 1) if (1) /* { dg-error "if any 'if' clause has modifier, then all 'if' clauses have to use modifier" } */ + #pragma omp cancel parallel if (cancel: 1) if (parallel: 1) /* { dg-error "expected 'cancel' 'if' clause modifier" } */ + #pragma omp cancel parallel if (1) if (cancel: 1) /* { dg-error "if any 'if' clause has modifier, then all 'if' clauses have to use modifier" } */ + #pragma omp cancel parallel if (parallel: 1) if (cancel: 1) /* { dg-error "expected 'cancel' 'if' clause modifier" } */ + } +} --- gcc/testsuite/gcc.dg/gomp/cancel-1.c.jj 2019-01-24 16:09:10.673950248 +0100 +++ gcc/testsuite/gcc.dg/gomp/cancel-1.c 2019-01-24 16:09:04.268054790 +0100 @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +struct S { int s; } s; + +void +foo (void) +{ + #pragma omp parallel + { + #pragma omp cancel parallel if (s) /* { dg-error "used struct type value where scalar is required" } */ + } +} --- gcc/testsuite/g++.dg/gomp/cancel-1.C.jj 2019-01-24 15:28:47.824360398 +0100 +++ gcc/testsuite/g++.dg/gomp/cancel-1.C 2019-01-24 15:29:55.956287233 +0100 @@ -0,0 +1,26 @@ +// PR c++/88976 +// { dg-do compile } + +template <class T> void +foo (T x) +{ +#pragma omp parallel + { + #pragma omp cancel parallel if (x) + } +#pragma omp parallel + { + #pragma omp cancel parallel if (1 == 1) + } +} + +void +bar (int x, double y, long long z) +{ + foo (0); + foo (1LL); + foo (1.25); + foo (x); + foo (y); + foo (z); +} --- gcc/testsuite/g++.dg/gomp/cancel-2.C.jj 2019-01-24 15:30:29.935752008 +0100 +++ gcc/testsuite/g++.dg/gomp/cancel-2.C 2019-01-24 16:28:29.271017193 +0100 @@ -0,0 +1,20 @@ +// PR c++/88976 +// { dg-do compile } + +template <class T> void +foo (T x) +{ +#pragma omp parallel + { + #pragma omp cancel parallel if (x) // { dg-error "no match for" } + } +} + +struct S {}; + +void +bar () +{ + S s; + foo (s); +} --- gcc/testsuite/g++.dg/gomp/cancel-3.C.jj 2019-01-24 16:07:35.803498617 +0100 +++ gcc/testsuite/g++.dg/gomp/cancel-3.C 2019-01-24 16:09:52.962260054 +0100 @@ -0,0 +1,12 @@ +// { dg-do compile } + +struct S { int s; } s; + +void +foo (void) +{ + #pragma omp parallel + { + #pragma omp cancel parallel if (s) // { dg-error "could not convert 's' from 'S' to 'bool'" } + } +} Jakub