c++: Fix deduction from auto template parameter [PR93083]
authorJason Merrill <jason@redhat.com>
Wed, 25 Nov 2020 22:05:24 +0000 (17:05 -0500)
committerJason Merrill <jason@redhat.com>
Fri, 4 Dec 2020 22:47:05 +0000 (17:47 -0500)
The check in do_class_deduction to handle passing one class placeholder
template parm as an argument for itself needed to be extended to also handle
equivalent parms from other templates.

gcc/cp/ChangeLog:

PR c++/93083
* pt.c (convert_template_argument): Handle equivalent placeholders.
(do_class_deduction): Look through EXPR_PACK_EXPANSION, too.

gcc/testsuite/ChangeLog:

PR c++/93083
* g++.dg/cpp2a/nontype-class40.C: New test.

gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp2a/nontype-class40.C [new file with mode: 0644]

index e991a32..2d3ab92 100644 (file)
@@ -8266,7 +8266,7 @@ convert_template_argument (tree parm,
 
   /* When determining whether an argument pack expansion is a template,
      look at the pattern.  */
-  if (TREE_CODE (arg) == TYPE_PACK_EXPANSION)
+  if (PACK_EXPANSION_P (arg))
     arg = PACK_EXPANSION_PATTERN (arg);
 
   /* Deal with an injected-class-name used as a template template arg.  */
@@ -29013,6 +29013,12 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
   if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))
     return ptype;
 
+  /* Initializing one placeholder from another.  */
+  if (init && TREE_CODE (init) == TEMPLATE_PARM_INDEX
+      && is_auto (TREE_TYPE (init))
+      && CLASS_PLACEHOLDER_TEMPLATE (TREE_TYPE (init)) == tmpl)
+    return cp_build_qualified_type (TREE_TYPE (init), cp_type_quals (ptype));
+
   /* Look through alias templates that just rename another template.  */
   tmpl = get_underlying_template (tmpl);
   if (!ctad_template_p (tmpl))
@@ -29029,10 +29035,6 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
                 "with %<-std=c++20%> or %<-std=gnu++20%>");
     }
 
-  if (init && TREE_TYPE (init) == ptype)
-    /* Using the template parm as its own argument.  */
-    return ptype;
-
   tree type = TREE_TYPE (tmpl);
 
   bool try_list_ctor = false;
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class40.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class40.C
new file mode 100644 (file)
index 0000000..d193544
--- /dev/null
@@ -0,0 +1,79 @@
+// PR c++/93083
+// { dg-do compile { target c++20 } }
+
+template<unsigned N>
+struct FixedString
+{
+    char buf[N + 1]{};
+    constexpr FixedString(char const* s) {
+        for (unsigned i = 0; i != N; ++i) buf[i] = s[i];
+    }
+
+    auto operator<=>(const FixedString&) const = default;
+    constexpr operator char const*() const { return buf; }
+    constexpr static unsigned size() noexcept { return N; }
+};
+
+template<unsigned N> FixedString(char const (&)[N]) -> FixedString<N - 1>;
+
+template <FixedString... names>
+struct name_list
+{
+    template <FixedString name>
+    using add_name = name_list<
+        names...,
+        FixedString<name.size()>{ name }
+    >;
+};
+
+
+int main()
+{
+    using names =
+        name_list<>
+        ::add_name<"Zaphod Beeblebrox">;
+
+}
+
+// ----------------
+
+template <int N> struct literal {
+  constexpr literal(const char (&input)[N]) noexcept { }
+  constexpr literal(const literal &) noexcept { }
+};
+
+template <literal Name, int id> struct field { };
+
+template <literal Name> struct field<Name, 1u> { };
+
+// ----------------
+
+template <int N>
+struct use_as_nttp {};
+
+template <use_as_nttp Value>
+struct has_nttp {};
+
+template <use_as_nttp Value>
+using has_nttp_2 = has_nttp<Value>;
+
+// ----------------
+
+using size_t = decltype(sizeof(0));
+
+template <size_t N>
+struct string_literal
+{
+  constexpr string_literal(const char*) {}
+  string_literal(string_literal const&) = default;
+};
+template <size_t N>
+string_literal(const char (&)[N]) -> string_literal<N - 1>;
+
+template <string_literal Str>
+struct type_string { };
+
+template <string_literal Str>
+void foo() {
+  type_string<Str>{};
+}