public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-4807] c++: NTTP object wrapper substitution fixes [PR103346, ...]
@ 2022-12-20 16:09 Patrick Palka
0 siblings, 0 replies; only message in thread
From: Patrick Palka @ 2022-12-20 16:09 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:49b6b7ac3314843466395c4a194aa178c80e64f5
commit r13-4807-g49b6b7ac3314843466395c4a194aa178c80e64f5
Author: Patrick Palka <ppalka@redhat.com>
Date: Tue Dec 20 11:09:11 2022 -0500
c++: NTTP object wrapper substitution fixes [PR103346, ...]
This patch fixes some issues with substitution into a C++20 template
parameter object wrapper:
* The first testcase demonstrates a situation where the same_type_p
assert in relevant case of tsubst_copy doesn't hold, because (partial)
substitution of {int,} into the wrapper's TREE_TYPE yields A<int> but
substitution into the underlying TEMPLATE_PARM_INDEX is a nop due to
tsubst's level==1/tf_partial early exit tests, hence TREE_TYPE in the
latter case remains A<T>. So this patch just gets rid of the assert;
the type mismatch doesn't seem to be a problem in practice.
* In the second testcase, dependent substitution into the underlying
TEMPLATE_PARM_INDEX yields a CALL_EXPR with empty TREE_TYPE, which
tsubst_copy doesn't expect. This patch fixes this by handling empty
TREE_TYPE the same way as a non-const TREE_TYPE. Moreover, after
this substitution we're left with a VIEW_CONVERT_EXPR wrapping a
CALL_EXPR instead of a TEMPLATE_PARM_INDEX, which during the subsequent
non-dependent substitution tsubst_copy doesn't expect either. So
this patch also relaxes tsubst_copy to accept such VIEW_CONVERT_EXPR
too.
* In the third testcase, we end up never resolving the call to
f.modify() because tsubst_copy doesn't do overload resolution.
This patch fixes this by moving the handling of these
VIEW_CONVERT_EXPR wrappers from tsubst_copy to tsubst_copy_and_build.
For good measure tsubst_copy_and_build should also handle
REF_PARENTHESIZED_P wrappers instead of delegating to tsubst_copy.
PR c++/103346
PR c++/104278
PR c++/102553
gcc/cp/ChangeLog:
* pt.cc (tsubst_copy) <case VIEW_CONVERT_EXPR>: Move the
handling of C++20 template parameter object wrappers to ...
(tsubst_copy_and_build) <case VIEW_CONVERT_EXPR>: ... here.
Accept non-TEMPLATE_PARM_INDEX inner operand. Handle empty
TREE_TYPE on substituted inner operand. Remove same_type_p
assert. Also handle REF_PARENTHESIZED_P VIEW_CONVERT_EXPRs.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/nontype-class52a.C: New test.
* g++.dg/cpp2a/nontype-class53.C: New test.
* g++.dg/cpp2a/nontype-class54.C: New test.
* g++.dg/cpp2a/nontype-class55.C: New test.
Diff:
---
gcc/cp/pt.cc | 74 ++++++++++++++-------------
gcc/testsuite/g++.dg/cpp2a/nontype-class52a.C | 15 ++++++
gcc/testsuite/g++.dg/cpp2a/nontype-class53.C | 25 +++++++++
gcc/testsuite/g++.dg/cpp2a/nontype-class54.C | 23 +++++++++
gcc/testsuite/g++.dg/cpp2a/nontype-class55.C | 15 ++++++
5 files changed, 117 insertions(+), 35 deletions(-)
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2b7b3756b68..83da1ba1bf5 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -17338,42 +17338,16 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
return maybe_wrap_with_location (op0, EXPR_LOCATION (t));
}
tree op = TREE_OPERAND (t, 0);
- if (code == VIEW_CONVERT_EXPR
- && TREE_CODE (op) == TEMPLATE_PARM_INDEX)
- {
- /* Wrapper to make a C++20 template parameter object const. */
- op = tsubst_copy (op, args, complain, in_decl);
- if (!CP_TYPE_CONST_P (TREE_TYPE (op)))
- {
- /* The template argument is not const, presumably because
- it is still dependent, and so not the const template parm
- object. */
- tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
- gcc_checking_assert (same_type_ignoring_top_level_qualifiers_p
- (type, TREE_TYPE (op)));
- if (TREE_CODE (op) == CONSTRUCTOR
- || TREE_CODE (op) == IMPLICIT_CONV_EXPR)
- {
- /* Don't add a wrapper to these. */
- op = copy_node (op);
- TREE_TYPE (op) = type;
- }
- else
- /* Do add a wrapper otherwise (in particular, if op is
- another TEMPLATE_PARM_INDEX). */
- op = build1 (code, type, op);
- }
- return op;
- }
/* force_paren_expr can also create a VIEW_CONVERT_EXPR. */
- else if (code == VIEW_CONVERT_EXPR && REF_PARENTHESIZED_P (t))
+ if (code == VIEW_CONVERT_EXPR && REF_PARENTHESIZED_P (t))
{
op = tsubst_copy (op, args, complain, in_decl);
op = build1 (code, TREE_TYPE (op), op);
REF_PARENTHESIZED_P (op) = true;
return op;
}
- /* We shouldn't see any other uses of these in templates. */
+ /* We shouldn't see any other uses of these in templates
+ (tsubst_copy_and_build handles C++20 tparm object wrappers). */
gcc_unreachable ();
}
@@ -21636,12 +21610,42 @@ tsubst_copy_and_build (tree t,
case NON_LVALUE_EXPR:
case VIEW_CONVERT_EXPR:
- if (location_wrapper_p (t))
- /* We need to do this here as well as in tsubst_copy so we get the
- other tsubst_copy_and_build semantics for a PARM_DECL operand. */
- RETURN (maybe_wrap_with_location (RECUR (TREE_OPERAND (t, 0)),
- EXPR_LOCATION (t)));
- /* fallthrough. */
+ {
+ tree op = RECUR (TREE_OPERAND (t, 0));
+
+ if (location_wrapper_p (t))
+ /* We need to do this here as well as in tsubst_copy so we get the
+ other tsubst_copy_and_build semantics for a PARM_DECL operand. */
+ RETURN (maybe_wrap_with_location (op, EXPR_LOCATION (t)));
+
+ gcc_checking_assert (TREE_CODE (t) == VIEW_CONVERT_EXPR);
+ if (REF_PARENTHESIZED_P (t))
+ /* force_paren_expr can also create a VIEW_CONVERT_EXPR. */
+ RETURN (finish_parenthesized_expr (op));
+
+ /* Otherwise, we're dealing with a wrapper to make a C++20 template
+ parameter object const. */
+ if (TREE_TYPE (op) == NULL_TREE
+ || !CP_TYPE_CONST_P (TREE_TYPE (op)))
+ {
+ /* The template argument is not const, presumably because
+ it is still dependent, and so not the const template parm
+ object. */
+ tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ if (TREE_CODE (op) == CONSTRUCTOR
+ || TREE_CODE (op) == IMPLICIT_CONV_EXPR)
+ {
+ /* Don't add a wrapper to these. */
+ op = copy_node (op);
+ TREE_TYPE (op) = type;
+ }
+ else
+ /* Do add a wrapper otherwise (in particular, if op is
+ another TEMPLATE_PARM_INDEX). */
+ op = build1 (VIEW_CONVERT_EXPR, type, op);
+ }
+ RETURN (op);
+ }
default:
/* Handle Objective-C++ constructs, if appropriate. */
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class52a.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class52a.C
new file mode 100644
index 00000000000..ae5d5df70ac
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class52a.C
@@ -0,0 +1,15 @@
+// A version of nontype-class52.C where explicit template arguments are
+// given in the call to f (which during deduction need to be partially
+// substituted into the NTTP object V in f's signature).
+// { dg-do compile { target c++20 } }
+
+template<class> struct A { };
+
+template<auto> struct B { };
+
+template<class T, A<T> V> void f(B<V>);
+
+int main() {
+ constexpr A<int> a;
+ f<int>(B<a>{});
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class53.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class53.C
new file mode 100644
index 00000000000..9a6398c5f57
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class53.C
@@ -0,0 +1,25 @@
+// PR c++/103346
+// { dg-do compile { target c++20 } }
+
+struct Item {};
+
+template<class T, T... ts>
+struct Sequence { };
+
+template<Item... items>
+using ItemSequence = Sequence<Item, items...>;
+
+template<Item... items>
+constexpr auto f() {
+ constexpr auto l = [](Item item) { return item; };
+ return ItemSequence<l(items)...>{};
+}
+
+using ty0 = decltype(f<>());
+using ty0 = ItemSequence<>;
+
+using ty1 = decltype(f<{}>());
+using ty1 = ItemSequence<{}>;
+
+using ty3 = decltype(f<{}, {}, {}>());
+using ty3 = ItemSequence<{}, {}, {}>;
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class54.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class54.C
new file mode 100644
index 00000000000..8127b1f5426
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class54.C
@@ -0,0 +1,23 @@
+// PR c++/104278
+// { dg-do compile { target c++20 } }
+
+struct foo {
+ int value;
+ constexpr foo modify() const { return { value + 1 }; }
+};
+
+template<foo f, bool Enable = f.value & 1>
+struct bar {
+ static void run() { }
+};
+
+template<foo f>
+struct qux {
+ static void run() {
+ bar<f.modify()>::run();
+ }
+};
+
+int main() {
+ qux<foo{}>::run();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class55.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class55.C
new file mode 100644
index 00000000000..afcb3d64495
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class55.C
@@ -0,0 +1,15 @@
+// PR c++/102553
+// { dg-do compile { target c++20 } }
+
+struct s1{};
+template<int> inline constexpr s1 ch{};
+
+template<s1 f> struct s2{};
+template<s1 f> using alias1 = s2<f>;
+
+template<class T>
+void general(int n) {
+ alias1<ch<1>>{};
+}
+
+template void general<int>(int);
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-12-20 16:09 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-20 16:09 [gcc r13-4807] c++: NTTP object wrapper substitution fixes [PR103346, ...] Patrick Palka
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).