aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/tree.cc
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2022-03-16 09:34:34 -0400
committerMarek Polacek <polacek@redhat.com>2022-03-18 12:50:18 -0400
commitc7a6a32739d62deab03266e2b5449fce261b1ecb (patch)
tree643f699758d2d3aa7a5bce4395da9105f3076788 /gcc/cp/tree.cc
parentc133bdfa9e7d9225510d00dbb7270cc052e4e4ee (diff)
downloadgcc-c7a6a32739d62deab03266e2b5449fce261b1ecb.zip
gcc-c7a6a32739d62deab03266e2b5449fce261b1ecb.tar.gz
gcc-c7a6a32739d62deab03266e2b5449fce261b1ecb.tar.bz2
c++: alias template and empty parameter packs [PR104008]
Zero-length pack expansions are treated as if no list were provided at all, that is, with template<typename...> struct S { }; template<typename T, typename... Ts> void g() { S<std::is_same<T, Ts>...>; } g<int> will result in S<>. In the following test we have something similar: template <typename T, typename... Ts> using IsOneOf = disjunction<is_same<T, Ts>...>; and then we have "IsOneOf<OtherHolders>..." where OtherHolders is an empty pack. Since r11-7931, we strip_typedefs in TYPE_PACK_EXPANSION. In this test that results in "IsOneOf<OtherHolders>" being turned into "disjunction<>". So the whole expansion is now "disjunction<>...". But then we error in make_pack_expansion because find_parameter_packs_r won't find the pack OtherHolders. We strip the alias template because dependent_alias_template_spec_p says it's not dependent. It it not dependent because this alias is not TEMPLATE_DECL_COMPLEX_ALIAS_P. My understanding is that currently we consider an alias complex if it 1) expands a pack from the enclosing class, as in template<template<typename... U> typename... TT> struct S { template<typename... Args> using X = P<TT<Args...>...>; }; where the alias expands TT; or 2) the expansion does *not* name all the template parameters, as in template<typename...> struct R; template<typename T, typename... Ts> using U = R<X<Ts>...>; where T is not named in the expansion. But IsOneOf is neither. And it can't know how it's going to be used. Therefore I think we cannot make it complex (and in turn dependent) to fix this bug. After much gnashing of teeth, I think we simply want to avoid stripping the alias if the new pattern doesn't have any parameter packs to expand. PR c++/104008 gcc/cp/ChangeLog: * tree.cc (strip_typedefs): Don't strip an alias template when doing so would result in losing a parameter pack. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/variadic-alias3.C: New test. * g++.dg/cpp0x/variadic-alias4.C: New test.
Diffstat (limited to 'gcc/cp/tree.cc')
-rw-r--r--gcc/cp/tree.cc13
1 files changed, 12 insertions, 1 deletions
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 6e9be71..eb59e56 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -1778,7 +1778,18 @@ strip_typedefs (tree t, bool *remove_attributes, unsigned int flags)
if (TYPE_P (pat))
{
type = strip_typedefs (pat, remove_attributes, flags);
- if (type != pat)
+ /* Empty packs can thwart our efforts here. Consider
+
+ template <typename T, typename... Ts>
+ using IsOneOf = disjunction<is_same<T, Ts>...>;
+
+ where IsOneOf seemingly uses all of its template parameters in
+ its expansion (and does not expand a pack from the enclosing
+ class), so the alias is not marked as complex. However, it may
+ be used as in "IsOneOf<Ts>", where Ts is an empty parameter pack,
+ and stripping it down into "disjunction<>" here would exclude the
+ Ts pack, resulting in an error. */
+ if (type != pat && uses_parameter_packs (type))
{
result = copy_node (t);
PACK_EXPANSION_PATTERN (result) = type;