From a95753214b55d21e5b44eeb098cccf88d44c94dd Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 25 Nov 2020 17:05:24 -0500 Subject: [PATCH] c++: Fix deduction from auto template parameter [PR93083] 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 | 12 +-- gcc/testsuite/g++.dg/cpp2a/nontype-class40.C | 79 ++++++++++++++++++++ 2 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class40.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index e991a323de8..2d3ab92dfd1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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 index 00000000000..d19354491ff --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class40.C @@ -0,0 +1,79 @@ +// PR c++/93083 +// { dg-do compile { target c++20 } } + +template +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 FixedString(char const (&)[N]) -> FixedString; + +template +struct name_list +{ + template + using add_name = name_list< + names..., + FixedString{ name } + >; +}; + + +int main() +{ + using names = + name_list<> + ::add_name<"Zaphod Beeblebrox">; + +} + +// ---------------- + +template struct literal { + constexpr literal(const char (&input)[N]) noexcept { } + constexpr literal(const literal &) noexcept { } +}; + +template struct field { }; + +template struct field { }; + +// ---------------- + +template +struct use_as_nttp {}; + +template +struct has_nttp {}; + +template +using has_nttp_2 = has_nttp; + +// ---------------- + +using size_t = decltype(sizeof(0)); + +template +struct string_literal +{ + constexpr string_literal(const char*) {} + string_literal(string_literal const&) = default; +}; +template +string_literal(const char (&)[N]) -> string_literal; + +template +struct type_string { }; + +template +void foo() { + type_string{}; +} -- 2.30.2