extract_local_specs wasn't finding the mention of 'an' as a template argument because we weren't walking into template arguments. So here I changed cp_walk_subtrees to do so--only walking into template arguments in the spelling of the type or expression, not any hidden behind typedefs. The change to use typedef_variant_p avoids looking through typedefs spelled with 'typedef' as well as those spelled with 'using'. And then I removed some now-redundant code for walking into template arguments in a couple of walk_tree callbacks.
Tested x86_64-pc-linux-gnu, applying to trunk. PR c++/92654 * tree.c (cp_walk_subtrees): Walk into type template arguments. * cp-tree.h (TYPE_TEMPLATE_INFO_MAYBE_ALIAS): Use typedef_variant_p instead of TYPE_ALIAS_P. * pt.c (push_template_decl_real): Likewise. (find_parameter_packs_r): Likewise. Remove dead code. * error.c (find_typenames_r): Remove dead code. --- gcc/cp/cp-tree.h | 2 +- gcc/cp/error.c | 6 --- gcc/cp/pt.c | 40 ++++--------------- gcc/cp/tree.c | 5 +++ .../g++.dg/cpp1z/constexpr-if-lambda2.C | 12 ++++++ 5 files changed, 25 insertions(+), 40 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda2.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b8035b4360d..c46d1e92b3b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3482,7 +3482,7 @@ struct GTY(()) lang_decl { for the alias template (if any). Otherwise behave as TYPE_TEMPLATE_INFO. */ #define TYPE_TEMPLATE_INFO_MAYBE_ALIAS(NODE) \ - (TYPE_ALIAS_P (NODE) \ + (typedef_variant_p (NODE) \ ? TYPE_ALIAS_TEMPLATE_INFO (NODE) \ : TYPE_TEMPLATE_INFO (NODE)) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 973b3034e12..ab8638fbaec 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1526,12 +1526,6 @@ find_typenames_r (tree *tp, int *walk_subtrees, void *data) if (mv && (mv == *tp || !d->p_set->add (mv))) vec_safe_push (d->typenames, mv); - /* Search into class template arguments, which cp_walk_subtrees - doesn't do. */ - if (CLASS_TYPE_P (*tp) && CLASSTYPE_TEMPLATE_INFO (*tp)) - cp_walk_tree (&CLASSTYPE_TI_ARGS (*tp), find_typenames_r, - data, d->p_set); - return NULL_TREE; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 01bade85cdf..2fb52caa5d4 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -3818,9 +3818,12 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) (struct find_parameter_pack_data*)data; bool parameter_pack_p = false; - /* Handle type aliases/typedefs. */ - if (TYPE_ALIAS_P (t)) + /* Don't look through typedefs; we are interested in whether a + parameter pack is actually written in the expression/type we're + looking at, not the target type. */ + if (TYPE_P (t) && typedef_variant_p (t)) { + /* But do look at arguments for an alias template. */ if (tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t)) cp_walk_tree (&TI_ARGS (tinfo), &find_parameter_packs_r, @@ -3903,27 +3906,13 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) &find_parameter_packs_r, ppd, ppd->visited); /* This switch statement will return immediately if we don't find a - parameter pack. */ + parameter pack. ??? Should some of these be in cp_walk_subtrees? */ switch (TREE_CODE (t)) { - case TEMPLATE_PARM_INDEX: - return NULL_TREE; - case BOUND_TEMPLATE_TEMPLATE_PARM: /* Check the template itself. */ cp_walk_tree (&TREE_TYPE (TYPE_TI_TEMPLATE (t)), &find_parameter_packs_r, ppd, ppd->visited); - /* Check the template arguments. */ - cp_walk_tree (&TYPE_TI_ARGS (t), &find_parameter_packs_r, ppd, - ppd->visited); - *walk_subtrees = 0; - return NULL_TREE; - - case TEMPLATE_TYPE_PARM: - case TEMPLATE_TEMPLATE_PARM: - return NULL_TREE; - - case PARM_DECL: return NULL_TREE; case DECL_EXPR: @@ -3932,20 +3921,6 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) *walk_subtrees = 0; return NULL_TREE; - case RECORD_TYPE: - if (TYPE_PTRMEMFUNC_P (t)) - return NULL_TREE; - /* Fall through. */ - - case UNION_TYPE: - case ENUMERAL_TYPE: - if (TYPE_TEMPLATE_INFO (t)) - cp_walk_tree (&TYPE_TI_ARGS (t), - &find_parameter_packs_r, ppd, ppd->visited); - - *walk_subtrees = 0; - return NULL_TREE; - case TEMPLATE_DECL: if (!DECL_TEMPLATE_TEMPLATE_PARM_P (t)) return NULL_TREE; @@ -5794,8 +5769,7 @@ push_template_decl_real (tree decl, bool is_friend) if (check_for_bare_parameter_packs (TYPE_RAISES_EXCEPTIONS (type))) TYPE_RAISES_EXCEPTIONS (type) = NULL_TREE; } - else if (check_for_bare_parameter_packs ((TREE_CODE (decl) == TYPE_DECL - && TYPE_DECL_ALIAS_P (decl)) + else if (check_for_bare_parameter_packs (is_typedef_decl (decl) ? DECL_ORIGINAL_TYPE (decl) : TREE_TYPE (decl))) { diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 21f733af486..fda630790a2 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -4918,6 +4918,11 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, } \ while (0) + if (TYPE_P (*tp)) + /* Walk into template args without looking through typedefs. */ + if (tree ti = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (*tp)) + WALK_SUBTREE (TI_ARGS (ti)); + /* Not one of the easy cases. We must explicitly go through the children. */ result = NULL_TREE; diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda2.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda2.C new file mode 100644 index 00000000000..fb26ac716d4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda2.C @@ -0,0 +1,12 @@ +// PR c++/92654 +// { dg-do compile { target c++17 } } + +template <unsigned long> struct C; +template <auto I> +void am() { + [](auto an) + { + if constexpr (C<an>::ap) ; // { dg-error "constant" } + }(42); +} +void fn() { am<42>(); } base-commit: c8dd2446f597e6d1581414a9c02ff329285181a9 -- 2.18.1