aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2025-01-16 16:08:25 -0500
committerPatrick Palka <ppalka@redhat.com>2025-01-16 16:08:25 -0500
commitd72e5b7be203f9bb9b7e2aac8dd812af7f70859f (patch)
treea9156a93d60ad5abe941e70c058b73d59c4b02b5
parent232d3a73e18d6886f0a5781048a78da293fbb014 (diff)
downloadgcc-d72e5b7be203f9bb9b7e2aac8dd812af7f70859f.zip
gcc-d72e5b7be203f9bb9b7e2aac8dd812af7f70859f.tar.gz
gcc-d72e5b7be203f9bb9b7e2aac8dd812af7f70859f.tar.bz2
c++: pack expansion arg vs non-pack parm checking ICE [PR118454]
During ahead of time template argument coercion, we handle the case of passing a pack expansion to a non-pack parameter by breaking out early and using the original unconverted arguments, deferring coercion until instantiation time where we have concrete arguments. This PR illustrates we still need to strip typedefs from the original arguments in this case as in the ordinary case, for sake of our template argument hashing/equivalence routines which assume template arguments went through strip_typedefs. Since we're using the unconverted arguments we need to preserve injected-class-name typedefs because we use them to distinguish passing an injected-class-name vs the corresponding specialization as the argument to a template template parameter (the former is valid, the latter isn't). PR c++/118454 gcc/cp/ChangeLog: * cp-tree.h (STF_KEEP_INJ_CLASS_NAME): Define. * pt.cc (iterative_hash_template_argument) <case tcc_type>: Clarify comment for when we'd see an alias template specialization here. (coerce_template_parms): Strip typedefs (except for injected-class-names) in the pack expansion early break cases that defer coercion. * tree.cc (strip_typedefs): Don't strip an injected-class-name if STF_KEEP_INJ_CLASS_NAME is set. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/variadic187.C: New test. Reviewed-by: Jason Merrill <jason@redhat.com>
-rw-r--r--gcc/cp/cp-tree.h7
-rw-r--r--gcc/cp/pt.cc12
-rw-r--r--gcc/cp/tree.cc7
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/variadic187.C13
4 files changed, 32 insertions, 7 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e229fe0..c9128bd 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6318,9 +6318,14 @@ enum auto_deduction_context
STF_STRIP_DEPENDENT: allow the stripping of aliases with dependent
template parameters, relying on code elsewhere to report any
- appropriate diagnostics. */
+ appropriate diagnostics.
+
+ STF_KEEP_INJ_CLASS_NAME: don't strip injected-class-name typedefs
+ because we're dealing with a non-coerced template argument.
+*/
const unsigned int STF_USER_VISIBLE = 1U;
const unsigned int STF_STRIP_DEPENDENT = 1U << 1;
+const unsigned int STF_KEEP_INJ_CLASS_NAME = 1U << 2;
/* Returns the TEMPLATE_DECL associated to a TEMPLATE_TEMPLATE_PARM
node. */
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 00b61ae..6a5d650 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1913,9 +1913,7 @@ iterative_hash_template_arg (tree arg, hashval_t val)
// to hash differently from its TYPE_CANONICAL, to avoid hash
// collisions that compare as different in template_args_equal.
// These could be dependent specializations that strip_typedefs
- // left alone, or untouched specializations because
- // coerce_template_parms returns the unconverted template
- // arguments if it sees incomplete argument packs.
+ // left alone for example.
tree ti = TYPE_ALIAS_TEMPLATE_INFO (ats);
return hash_tmpl_and_args (TI_TEMPLATE (ti), TI_ARGS (ti));
}
@@ -9301,7 +9299,9 @@ coerce_template_parms (tree parms,
/* We don't know how many args we have yet, just use the
unconverted (and still packed) ones for now. */
ggc_free (new_inner_args);
- new_inner_args = orig_inner_args;
+ new_inner_args = strip_typedefs (orig_inner_args,
+ /*remove_attrs=*/nullptr,
+ STF_KEEP_INJ_CLASS_NAME);
arg_idx = nargs;
break;
}
@@ -9357,7 +9357,9 @@ coerce_template_parms (tree parms,
/* We don't know how many args we have yet, just
use the unconverted (but unpacked) ones for now. */
ggc_free (new_inner_args);
- new_inner_args = inner_args;
+ new_inner_args = strip_typedefs (inner_args,
+ /*remove_attrs=*/nullptr,
+ STF_KEEP_INJ_CLASS_NAME);
arg_idx = nargs;
break;
}
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 988e99d..ed01ca4 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -1566,7 +1566,7 @@ apply_identity_attributes (tree result, tree attribs, bool *remove_attributes)
/* Builds a qualified variant of T that is either not a typedef variant
(the default behavior) or not a typedef variant of a user-facing type
- (if FLAGS contains STF_USER_FACING). If T is not a type, then this
+ (if FLAGS contains STF_USER_VISIBLE). If T is not a type, then this
just dispatches to strip_typedefs_expr.
E.g. consider the following declarations:
@@ -1613,6 +1613,11 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
&& !user_facing_original_type_p (t))
return t;
+ if ((flags & STF_KEEP_INJ_CLASS_NAME)
+ && CLASS_TYPE_P (t)
+ && DECL_SELF_REFERENCE_P (TYPE_NAME (t)))
+ return t;
+
if (dependent_opaque_alias_p (t))
return t;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic187.C b/gcc/testsuite/g++.dg/cpp0x/variadic187.C
new file mode 100644
index 0000000..af1770e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic187.C
@@ -0,0 +1,13 @@
+// PR c++/118454
+// { dg-do compile { target c++11 } }
+// { dg-additional-options --param=hash-table-verification-limit=1000 }
+
+template<class T> using identity = T;
+
+template<class T, class U0, class... Us> struct dual;
+
+template<class T, class... Ts>
+using ty1 = dual<identity<T>, Ts...>;
+
+template<class T, class... Ts>
+using ty2 = dual<T, Ts...>;